diff --git a/.gn b/.gn
index 3e528d2..bed9277 100644
--- a/.gn
+++ b/.gn
@@ -249,6 +249,7 @@
 # to force additional review for new uses of exec_script, which is strongly
 # discouraged except for gypi_to_gn calls.
 exec_script_whitelist = [
+  "//android_webview/BUILD.gn",
   "//ash/BUILD.gn",
   "//build/config/android/config.gni",
   "//build/config/android/internal_rules.gni",
diff --git a/BUILD.gn b/BUILD.gn
index 4ee431b..98b9402 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -287,7 +287,7 @@
 
     if (!is_chromecast) {
       deps += [
-        "//android_webview:system_webview_apk",
+        "//android_webview",
         "//chrome/android:chrome_junit_tests",
         "//chrome/android:chrome_public_apk",
         "//chrome/android:chrome_public_test_apk",
diff --git a/DEPS b/DEPS
index 4b63cd6f..942ac3d 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'cb8d719d7a991ceb93ccc7dd1542bb0cd82437d6',
+  'skia_revision': '95105938da29f8a43cd76199769ed6ec6710a446',
   # 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': '10449d46aa20f10f39598627bf07f70def597029',
+  'v8_revision': '32d14df37820a52fc0aa3217025b9180d66a7259',
   # 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.
@@ -67,7 +67,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': 'ad38dc7452b6bdaf226965b88080736495ac263c',
+  'boringssl_revision': 'd7421ebf6cae07051caf657016f160585b64f8a6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling nss
   # and whatever else without interference from each other.
@@ -87,7 +87,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'f3dcedcdb5cf72890166b9618005331bd2666e84',
+  'nacl_revision': '546ef11ffcbedf8c33bfa12643408c1182b6839e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling dEQP
   # and whatever else without interference from each other.
@@ -193,7 +193,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b1b22ffc6a5c809c41cc27910e3e8b479c15d3a2',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '024b75ea420658818878983392c0245acb65d4fc', # commit position 10603
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'f213f6d46a0132c77b1eedc714b9ee71a91e782b', # commit position 10609
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
@@ -217,7 +217,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' + '@' + 'c3834e3a15751fd0135525531b94730b9ab206d6', # commit position 10602
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'b671e854b2721cb982ce7d0c05f406e0e244fbc6', # commit position 10614
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 644a146..4d6ea54d 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -16,17 +16,17 @@
   arch_suffix = 64
 }
 
-# This is dummy target for adding WebView gn piece by piece, so we don't need
-# to modify the src/BUILD.gn everytime new targets added.
-group("system_webview_apk") {
+group("android_webview") {
   deps = [
-    ":android_webview_java",
-    ":common",
-    ":assets",
-    "//android_webview/glue",
+    ":system_webview_apk",
   ]
 }
 
+jinja_template("system_webview_manifest") {
+  input = "apk/java/AndroidManifest.xml"
+  output = "$target_gen_dir/system_webview_manifest/AndroidManifest.xml"
+}
+
 webview_repack_locales("repack_locales") {
   input_locales = locales
   output_locales = locales
@@ -140,15 +140,18 @@
 }
 
 android_webview_assets_dir = "$root_build_dir/android_webview_assets"
+webview_license_path = "$target_gen_dir/webview_licenses.notice"
 
 copy_ex("assets") {
   clear_dir = true
   dest = android_webview_assets_dir
   sources = [
     "$target_gen_dir/webviewchromium.pak",
+    webview_license_path,
   ]
   deps = [
     ":repack_pack",
+    ":generate_webview_license_notice",
   ]
   if (icu_use_data_file) {
     sources += [ "$root_build_dir/icudtl.dat" ]
@@ -166,6 +169,26 @@
   }
 }
 
+action("generate_webview_license_notice") {
+  script = "tools/webview_licenses.py"
+  inputs = exec_script("//android_webview/tools/webview_licenses.py",
+                       [ "gn_notice_deps" ],
+                       "value")
+  inputs += [ "tools/licenses_notice.tmpl" ]
+  outputs = [
+    webview_license_path,
+  ]
+  args = [
+    "notice",
+    rebase_path(webview_license_path),
+  ]
+}
+
+android_resources("system_webview_resources") {
+  resource_dirs = [ "apk/java/res" ]
+  custom_package = "com.android.webview"
+}
+
 android_resources("resources") {
   resource_dirs = [ "java/res" ]
   custom_package = "org.chromium.android_webview"
@@ -316,6 +339,16 @@
   ]
 }
 
+shared_library("libwebviewchromium") {
+  deps = [
+    ":common",
+  ]
+  sources = [
+    "lib/main/webview_entry_point.cc",
+  ]
+  configs -= [ "//build/config/android:hide_native_jni_exports" ]
+}
+
 source_set("common") {
   sources = [
     "browser/aw_browser_context.cc",
@@ -487,6 +520,7 @@
     "//components/visitedlink/browser",
     "//components/visitedlink/renderer",
     "//components/web_contents_delegate_android:web_contents_delegate_android",
+    "//content",
     "//content/public/app:both",
     "//content/public/browser",
     "//gin",
@@ -644,3 +678,20 @@
     "values/android_webview_strings.xml",
   ]
 }
+
+android_apk("system_webview_apk") {
+  android_manifest = get_target_outputs(":system_webview_manifest")
+  android_manifest = android_manifest[1]
+  android_manifest_dep = ":system_webview_manifest"
+  asset_location = android_webview_assets_dir
+  chromium_code = true
+  deps = [
+    ":system_webview_resources",
+    ":assets",
+    ":libwebviewchromium",
+    "//android_webview/glue",
+    "//base:base_java",
+  ]
+  apk_name = "SystemWebView"
+  native_libs = [ "$root_build_dir/libwebviewchromium.so" ]
+}
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index de442b5..00ecd5e 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -94,7 +94,7 @@
             '<@(locales)',
           ],
         },
-        # GN version:  //android_webview/rename_snapshot_blob 
+        # GN version:  //android_webview/rename_snapshot_blob
         {
           'action_name': 'rename_snapshot_blob',
           'inputs': [
@@ -110,7 +110,7 @@
             '<@(_outputs)',
           ],
         },
-        # GN version:  //android_webview/rename_natives_blob 
+        # GN version:  //android_webview/rename_natives_blob
         {
           'action_name': 'rename_natives_blob',
           'inputs': [
@@ -126,6 +126,7 @@
             '<@(_outputs)',
           ],
         },
+        # GN version:  //android_webview/generate_webview_license_notice
         {
           'action_name': 'generate_webview_license_notice',
           'inputs': [
@@ -146,7 +147,7 @@
         },
       ],
     },
-    # GN version:  //android_webview/locale_paks 
+    # GN version:  //android_webview/locale_paks
     {
       'target_name': 'android_webview_locale_paks',
       'type': 'none',
@@ -173,7 +174,7 @@
       ],
     },
     {
-      # GN version:  //android_webview/common:version 
+      # GN version:  //android_webview/common:version
       'target_name': 'android_webview_version',
       'type': 'none',
       'direct_dependent_settings': {
@@ -422,6 +423,7 @@
         }],
       ],
     },
+    # GN version:  //android_webview:libwebviewchromium
     {
       'target_name': 'libwebviewchromium',
       'includes': [
@@ -458,6 +460,7 @@
       ],
       'includes': [ '../build/java.gypi' ],
     },
+    # GN version:  //android_webview/glue
     {
       'target_name': 'system_webview_glue_java',
       'variables': {
@@ -466,6 +469,7 @@
       },
       'includes': [ 'apk/system_webview_glue_common.gypi' ],
     },
+    # GN version:  //android_webview:system_webview_apk
     {
       'target_name': 'system_webview_apk',
       'dependencies': [
diff --git a/android_webview/native/BUILD.gn b/android_webview/native/BUILD.gn
index 3a7b91f..561c1e1 100644
--- a/android_webview/native/BUILD.gn
+++ b/android_webview/native/BUILD.gn
@@ -106,6 +106,8 @@
   if (enable_video_hole) {
     deps += [ "//components/external_video_surface:external_video_surface" ]
   }
+
+  libs = [ "jnigraphics" ]
 }
 
 generate_jni("native_jni") {
diff --git a/android_webview/tools/webview_licenses.py b/android_webview/tools/webview_licenses.py
index 345ef9a..f747cb8 100755
--- a/android_webview/tools/webview_licenses.py
+++ b/android_webview/tools/webview_licenses.py
@@ -281,6 +281,13 @@
     print ' '.join(
       sorted(set(GenerateNoticeFile(generate_licenses_file_list_only=True))))
     return ScanResult.Ok
+  elif args[0] == 'gn_notice_deps':
+    # generate list for gn.
+    # 'set' is used to eliminate duplicate references to the same license file.
+    gn_file_list = ['"' + f + '"' for f in
+        sorted(set(GenerateNoticeFile(generate_licenses_file_list_only=True)))]
+    print '[%s] ' % ','.join(gn_file_list)
+    return ScanResult.Ok
   elif args[0] == 'notice':
     notice_file_contents = GenerateNoticeFile()
     if len(args) == 1:
diff --git a/ash/session/session_state_delegate.h b/ash/session/session_state_delegate.h
index ef88a24..8768f73 100644
--- a/ash/session/session_state_delegate.h
+++ b/ash/session/session_state_delegate.h
@@ -10,6 +10,8 @@
 #include "ash/ash_export.h"
 #include "ash/session/session_types.h"
 
+class AccountId;
+
 namespace aura {
 class Window;
 }
@@ -113,9 +115,9 @@
   virtual gfx::ImageSkia GetAvatarImageForWindow(
       aura::Window* window) const = 0;
 
-  // Switches to another active user with |user_id|
+  // Switches to another active user with |account_id|
   // (if that user has already signed in).
-  virtual void SwitchActiveUser(const std::string& user_id) = 0;
+  virtual void SwitchActiveUser(const AccountId& account_id) = 0;
 
   // Switches the active user to the next or previous user, with the same
   // ordering as GetLoggedInUsers.
diff --git a/ash/session/session_state_observer.h b/ash/session/session_state_observer.h
index 36fad83..dcb3b37b 100644
--- a/ash/session/session_state_observer.h
+++ b/ash/session/session_state_observer.h
@@ -11,15 +11,17 @@
 #include "ash/session/session_state_delegate.h"
 #include "base/basictypes.h"
 
+class AccountId;
+
 namespace ash {
 
 class ASH_EXPORT SessionStateObserver {
  public:
   // Called when active user has changed.
-  virtual void ActiveUserChanged(const std::string& user_id) {}
+  virtual void ActiveUserChanged(const AccountId& account_id) {}
 
   // Called when another user gets added to the existing session.
-  virtual void UserAddedToSession(const std::string& user_id) {}
+  virtual void UserAddedToSession(const AccountId& account_id) {}
 
   // Called when session state is changed.
   virtual void SessionStateChanged(SessionStateDelegate::SessionState state) {}
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index e87aab0..5677b9b 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -117,7 +117,7 @@
   gfx::ImageSkia GetAvatarImageForWindow(aura::Window* window) const override {
     return gfx::ImageSkia();
   }
-  void SwitchActiveUser(const std::string& user_id) override {}
+  void SwitchActiveUser(const AccountId& account_id) override {}
   void CycleActiveUser(CycleUser cycle_user) override {}
   bool IsMultiProfileAllowedByPrimaryUserPolicy() const override {
     return true;
diff --git a/ash/system/tray/system_tray_delegate.cc b/ash/system/tray/system_tray_delegate.cc
index 314817e..15e7304 100644
--- a/ash/system/tray/system_tray_delegate.cc
+++ b/ash/system/tray/system_tray_delegate.cc
@@ -259,7 +259,7 @@
 }
 
 tray::UserAccountsDelegate* SystemTrayDelegate::GetUserAccountsDelegate(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   return nullptr;
 }
 
diff --git a/ash/system/tray/system_tray_delegate.h b/ash/system/tray/system_tray_delegate.h
index 9859a48..9b05286 100644
--- a/ash/system/tray/system_tray_delegate.h
+++ b/ash/system/tray/system_tray_delegate.h
@@ -18,6 +18,8 @@
 #include "base/strings/string16.h"
 #include "ui/gfx/image/image_skia.h"
 
+class AccountId;
+
 namespace base {
 class TimeDelta;
 class TimeTicks;
@@ -314,7 +316,7 @@
 
   // Returns accounts delegate for given user. May return nullptr.
   virtual tray::UserAccountsDelegate* GetUserAccountsDelegate(
-      const std::string& user_id);
+      const AccountId& account_id);
 
   // Adding observers that are notified when supervised info is being changed.
   virtual void AddCustodianInfoTrayObserver(
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index 06d1823..e947641 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -119,7 +119,7 @@
                                    ->GetAccountId();
   tray::UserAccountsDelegate* delegate =
       Shell::GetInstance()->system_tray_delegate()->GetUserAccountsDelegate(
-          account_id.GetUserEmail());
+          account_id);
   if (!delegate)
     return nullptr;
   return new tray::AccountsDetailedView(this, status, delegate);
diff --git a/ash/system/user/user_view.cc b/ash/system/user/user_view.cc
index 0c48ca99..1b65bd5 100644
--- a/ash/system/user/user_view.cc
+++ b/ash/system/user/user_view.cc
@@ -78,8 +78,7 @@
       ash::Shell::GetInstance()->session_state_delegate();
   ash::MultiProfileUMA::RecordSwitchActiveUser(
       ash::MultiProfileUMA::SWITCH_ACTIVE_USER_BY_TRAY);
-  delegate->SwitchActiveUser(
-      delegate->GetUserInfo(user_index)->GetAccountId().GetUserEmail());
+  delegate->SwitchActiveUser(delegate->GetUserInfo(user_index)->GetAccountId());
 }
 
 class LogoutButton : public TrayPopupLabelButton {
diff --git a/ash/test/test_session_state_delegate.cc b/ash/test/test_session_state_delegate.cc
index bd0bdd3..d7e8fbb 100644
--- a/ash/test/test_session_state_delegate.cc
+++ b/ash/test/test_session_state_delegate.cc
@@ -21,11 +21,16 @@
 
 namespace {
 
-// The the "canonicalized" Account ID from a given |email| address.
-AccountId GetAccountIdFromEmail(const std::string& email) {
+// Returns the "canonicalized" email from a given |email| address.
+std::string GetUserIdFromEmail(const std::string& email) {
   std::string user_id = email;
   std::transform(user_id.begin(), user_id.end(), user_id.begin(), ::tolower);
-  return AccountId::FromUserEmail(user_id);
+  return user_id;
+}
+
+// Returns Account ID from a given |email| address.
+AccountId GetAccountIdFromEmail(const std::string& email) {
+  return AccountId::FromUserEmail(GetUserIdFromEmail(email));
 }
 
 }  // namespace
@@ -101,8 +106,8 @@
   STLDeleteElements(&user_list_);
 }
 
-void TestSessionStateDelegate::AddUser(const std::string& user_id) {
-  user_list_.push_back(new MockUserInfo(user_id));
+void TestSessionStateDelegate::AddUser(const AccountId& account_id) {
+  user_list_.push_back(new MockUserInfo(account_id.GetUserEmail()));
 }
 
 const user_manager::UserInfo* TestSessionStateDelegate::GetActiveUserInfo()
@@ -216,10 +221,10 @@
   return gfx::ImageSkia();
 }
 
-void TestSessionStateDelegate::SwitchActiveUser(const std::string& user_id) {
-  const AccountId account_id(GetAccountIdFromEmail(user_id));
+void TestSessionStateDelegate::SwitchActiveUser(const AccountId& account_id) {
   // Make sure this is a user id and not an email address.
-  EXPECT_EQ(user_id, account_id.GetUserEmail());
+  EXPECT_EQ(account_id.GetUserEmail(),
+            GetUserIdFromEmail(account_id.GetUserEmail()));
   active_user_index_ = 0;
   for (std::vector<MockUserInfo*>::iterator iter = user_list_.begin();
        iter != user_list_.end();
@@ -233,7 +238,7 @@
 }
 
 void TestSessionStateDelegate::CycleActiveUser(CycleUser cycle_user) {
-  SwitchActiveUser("someone@tray");
+  SwitchActiveUser(AccountId::FromUserEmail("someone@tray"));
 }
 
 bool TestSessionStateDelegate::IsMultiProfileAllowedByPrimaryUserPolicy()
diff --git a/ash/test/test_session_state_delegate.h b/ash/test/test_session_state_delegate.h
index 10b1429..ade02f5 100644
--- a/ash/test/test_session_state_delegate.h
+++ b/ash/test/test_session_state_delegate.h
@@ -13,6 +13,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "ui/gfx/image/image_skia.h"
 
+class AccountId;
+
 namespace ash {
 namespace test {
 
@@ -27,7 +29,7 @@
   void set_session_state(SessionState session_state) {
     session_state_ = session_state;
   }
-  void AddUser(const std::string& user_id);
+  void AddUser(const AccountId& account_id);
   const user_manager::UserInfo* GetActiveUserInfo() const;
 
   // SessionStateDelegate:
@@ -45,7 +47,7 @@
       ash::UserIndex index) const override;
   bool ShouldShowAvatar(aura::Window* window) const override;
   gfx::ImageSkia GetAvatarImageForWindow(aura::Window* window) const override;
-  void SwitchActiveUser(const std::string& user_id) override;
+  void SwitchActiveUser(const AccountId& account_id) override;
   void CycleActiveUser(CycleUser cycle_user) override;
   bool IsMultiProfileAllowedByPrimaryUserPolicy() const override;
   void AddSessionStateObserver(ash::SessionStateObserver* observer) override;
diff --git a/base/containers/scoped_ptr_map.h b/base/containers/scoped_ptr_map.h
index 23aadbb..dfa26f4 100644
--- a/base/containers/scoped_ptr_map.h
+++ b/base/containers/scoped_ptr_map.h
@@ -22,6 +22,9 @@
 //
 // |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
 // std::map in C++11.
+//
+// TODO(http://crbug.com/554291): DEPRECATED: Use std::map instead (now that we
+// have support for moveable types inside containers).
 template <class Key, class ScopedPtr, class Compare = std::less<Key>>
 class ScopedPtrMap {
   MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
index e1e5c722..250947f 100644
--- a/base/memory/scoped_vector.h
+++ b/base/memory/scoped_vector.h
@@ -15,6 +15,9 @@
 
 // ScopedVector wraps a vector deleting the elements from its
 // destructor.
+//
+// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
+// we have support for moveable types inside containers).
 template <class T>
 class ScopedVector {
   MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
diff --git a/breakpad/BUILD.gn b/breakpad/BUILD.gn
index 808f1e98..233c59715 100644
--- a/breakpad/BUILD.gn
+++ b/breakpad/BUILD.gn
@@ -53,6 +53,8 @@
 if (!is_win && current_toolchain == host_toolchain) {
   # Contains the code shared by both {micro,mini}dump_stackwalk.
   static_library("stackwalk_common") {
+    # Always want these files included regardless of platform.
+    set_sources_assignment_filter([])
     sources = [
       "src/processor/basic_code_module.h",
       "src/processor/basic_code_modules.cc",
diff --git a/build/common.gypi b/build/common.gypi
index a253ce6..b80d0f2 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -2212,13 +2212,8 @@
               # no need to load it dynamically.
               'clang_dynlib_flags%': '',
             }],
-            # https://crbug.com/441916
-            ['OS=="android" or OS=="linux" or OS=="mac"', {
-              'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang check-templates ',
-            }, { # OS != "linux"
-              'clang_plugin_args%': ''
-            }],
           ],
+          'clang_plugin_args%': '-Xclang -plugin-arg-find-bad-constructs -Xclang check-templates ',
         },
         # If you change these, also change build/config/clang/BUILD.gn.
         'clang_chrome_plugins_flags%':
@@ -6002,6 +5997,9 @@
         # Limited to Windows because lld-link is the driver that is
         # compatible with link.exe.
         ['LD', '<(make_clang_dir)/bin/lld-link'],
+        # lld-link includes a replacement for lib.exe that can produce thin
+        # archives and understands bitcode (for use_lto==1).
+        ['AR', '<(make_clang_dir)/bin/lld-link /lib /llvmlibthin'],
       ],
     }],
     ['OS=="android" and clang==0', {
@@ -6087,6 +6085,15 @@
             ],
           }],
         ],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'AdditionalOptions': [
+              # TODO(pcc): Add LTO support to clang-cl driver and use it here.
+              '-Xclang',
+              '-emit-llvm-bc',
+            ],
+          },
+        },
       },
     }],
     # Apply a lower LTO optimization level as the default is too slow.
@@ -6106,6 +6113,13 @@
             },
           }],
         ],
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'AdditionalOptions': [
+              '/opt:lldlto=1',
+            ],
+          },
+        },
       },
     }],
     ['use_lto==1 and clang==1 and target_arch=="arm"', {
@@ -6225,10 +6239,24 @@
             'msvs_settings': {
               'VCCLCompilerTool': {
                 'AdditionalOptions': [
+                  # TODO(pcc): Use regular -fsanitize=* flags here once clang-cl
+                  # supports LTO.
+                  '-Xclang',
                   '-fsanitize=cfi-vcall',
+                  '-Xclang',
                   '-fsanitize=cfi-derived-cast',
+                  '-Xclang',
                   '-fsanitize=cfi-unrelated-cast',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-vcall',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-derived-cast',
+                  '-Xclang',
+                  '-fsanitize-trap=cfi-unrelated-cast',
+                  '-Xclang',
                   '-fsanitize-blacklist=<(cfi_blacklist)',
+                  '-Xclang',
+                  '-fsanitize-blacklist=../../<(make_clang_dir)/lib/clang/<!(python <(DEPTH)/tools/clang/scripts/update.py --print-clang-version)/cfi_blacklist.txt',
                 ],
               },
             },
diff --git a/build/config/clang/BUILD.gn b/build/config/clang/BUILD.gn
index 6dff4863..02c5f2ca 100644
--- a/build/config/clang/BUILD.gn
+++ b/build/config/clang/BUILD.gn
@@ -31,21 +31,15 @@
       ]
     }
 
-    # https://crbug.com/441916
-    if (is_android || is_linux || is_mac) {
-      cflags += [
-        "-Xclang",
-        "-plugin-arg-find-bad-constructs",
-        "-Xclang",
-        "check-templates",
-      ]
-    }
-
     cflags += [
       "-Xclang",
       "-add-plugin",
       "-Xclang",
       "find-bad-constructs",
+      "-Xclang",
+      "-plugin-arg-find-bad-constructs",
+      "-Xclang",
+      "check-templates",
     ]
   }
 }
diff --git a/build/config/features.gni b/build/config/features.gni
index 669ad5d..d8ddb47 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -39,7 +39,7 @@
   # the commented out logic.
   # Eventually we want this to be:
   #   enable_nacl = !is_ios && !is_android && !is_chromecast
-  enable_nacl = ((is_linux && !is_chromeos) || is_nacl) &&
+  enable_nacl = (is_mac || (is_linux && !is_chromeos) || is_nacl) &&
                 current_cpu != "mipsel" && !is_chromecast
   enable_nacl_untrusted = enable_nacl
   enable_pnacl = enable_nacl_untrusted
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 184d0b1..072086f 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -655,7 +655,7 @@
             begin_main_frame_args_.on_critical_path);
         state_machine_.WillSendBeginMainFrame();
         // TODO(brianderson): Pass begin_main_frame_args_ directly to client.
-        client_->ScheduledActionSendBeginMainFrame();
+        client_->ScheduledActionSendBeginMainFrame(begin_main_frame_args_);
         break;
       case SchedulerStateMachine::ACTION_COMMIT: {
         // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 632dd14..5773bc4 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -35,7 +35,8 @@
 class SchedulerClient {
  public:
   virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
-  virtual void ScheduledActionSendBeginMainFrame() = 0;
+  virtual void ScheduledActionSendBeginMainFrame(
+      const BeginFrameArgs& args) = 0;
   virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
   virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
   virtual void ScheduledActionAnimate() = 0;
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 6349454b..6bdf5dd 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -63,6 +63,7 @@
     swap_will_happen_if_draw_happens_ = true;
     num_draws_ = 0;
     begin_frame_args_sent_to_children_ = BeginFrameArgs();
+    last_begin_main_frame_args_ = BeginFrameArgs();
   }
 
   void set_scheduler(TestScheduler* scheduler) { scheduler_ = scheduler; }
@@ -115,9 +116,15 @@
   }
   void DidFinishImplFrame() override {}
 
-  void ScheduledActionSendBeginMainFrame() override {
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
     PushAction("ScheduledActionSendBeginMainFrame");
+    last_begin_main_frame_args_ = args;
   }
+
+  const BeginFrameArgs& last_begin_main_frame_args() {
+    return last_begin_main_frame_args_;
+  }
+
   void ScheduledActionAnimate() override {
     PushAction("ScheduledActionAnimate");
     if (animate_causes_redraw_)
@@ -204,6 +211,7 @@
   bool automatic_swap_ack_;
   int num_draws_;
   BeginFrameArgs begin_frame_args_sent_to_children_;
+  BeginFrameArgs last_begin_main_frame_args_;
   base::TimeTicks posted_begin_impl_frame_deadline_;
   std::vector<const char*> actions_;
   std::vector<scoped_refptr<base::trace_event::ConvertableToTraceFormat>>
@@ -3485,28 +3493,32 @@
   EXPECT_FALSE(scheduler_->ImplLatencyTakesPriority());
 }
 
-TEST_F(SchedulerTest, BeginFrameArgs_OnCriticalPath) {
+TEST_F(SchedulerTest, BeginMainFrameArgs_OnCriticalPath) {
   scheduler_settings_.use_external_begin_frame_source = true;
   SetUpScheduler(true);
 
   scheduler_->SetImplLatencyTakesPriority(false);
-  scheduler_->SetChildrenNeedBeginFrames(true);
+  scheduler_->SetNeedsBeginMainFrame();
 
+  client_->Reset();
+  EXPECT_FALSE(client_->last_begin_main_frame_args().IsValid());
   EXPECT_SCOPED(AdvanceFrame());
-  EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
-  EXPECT_TRUE(client_->begin_frame_args_sent_to_children().on_critical_path);
+  EXPECT_TRUE(client_->last_begin_main_frame_args().IsValid());
+  EXPECT_TRUE(client_->last_begin_main_frame_args().on_critical_path);
 }
 
-TEST_F(SchedulerTest, BeginFrameArgs_NotOnCriticalPath) {
+TEST_F(SchedulerTest, BeginMainFrameArgs_NotOnCriticalPath) {
   scheduler_settings_.use_external_begin_frame_source = true;
   SetUpScheduler(true);
 
   scheduler_->SetImplLatencyTakesPriority(true);
-  scheduler_->SetChildrenNeedBeginFrames(true);
+  scheduler_->SetNeedsBeginMainFrame();
 
+  client_->Reset();
+  EXPECT_FALSE(client_->last_begin_main_frame_args().IsValid());
   EXPECT_SCOPED(AdvanceFrame());
-  EXPECT_TRUE(client_->begin_frame_is_sent_to_children());
-  EXPECT_FALSE(client_->begin_frame_args_sent_to_children().on_critical_path);
+  EXPECT_TRUE(client_->last_begin_main_frame_args().IsValid());
+  EXPECT_FALSE(client_->last_begin_main_frame_args().on_critical_path);
 }
 
 }  // namespace
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 41cf98b..b6c8570 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -135,9 +135,9 @@
     test_hooks_->DidSetNeedsUpdateLayers();
   }
 
-  void ScheduledActionSendBeginMainFrame() override {
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
     test_hooks_->ScheduledActionWillSendBeginMainFrame();
-    ThreadProxy::ScheduledActionSendBeginMainFrame();
+    ThreadProxy::ScheduledActionSendBeginMainFrame(args);
     test_hooks_->ScheduledActionSendBeginMainFrame();
   }
 
@@ -364,9 +364,9 @@
  private:
   TestHooks* test_hooks_;
 
-  void ScheduledActionSendBeginMainFrame() override {
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override {
     test_hooks_->ScheduledActionWillSendBeginMainFrame();
-    SingleThreadProxy::ScheduledActionSendBeginMainFrame();
+    SingleThreadProxy::ScheduledActionSendBeginMainFrame(args);
     test_hooks_->ScheduledActionSendBeginMainFrame();
   }
 
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 5288ae6..55f2c31 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -725,7 +725,8 @@
   layer_tree_host_impl_->WillBeginImplFrame(args);
 }
 
-void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
+void SingleThreadProxy::ScheduledActionSendBeginMainFrame(
+    const BeginFrameArgs& begin_frame_args) {
   TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
   // Although this proxy is single-threaded, it's problematic to synchronously
   // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame.  This
@@ -738,8 +739,6 @@
   DCHECK(inside_impl_frame_)
       << "BeginMainFrame should only be sent inside a BeginImplFrame";
 #endif
-  const BeginFrameArgs& begin_frame_args =
-      layer_tree_host_impl_->CurrentBeginFrameArgs();
 
   task_runner_provider_->MainThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&SingleThreadProxy::BeginMainFrame,
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 4b1a2767..591e0c1 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -67,7 +67,7 @@
   // SchedulerClient implementation
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
   void DidFinishImplFrame() override;
-  void ScheduledActionSendBeginMainFrame() override;
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
   DrawResult ScheduledActionDrawAndSwapIfPossible() override;
   DrawResult ScheduledActionDrawAndSwapForced() override;
   void ScheduledActionCommit() override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 592d7da..60d13688 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -332,8 +332,7 @@
     // set, that means the current frame is one past the frame in which we've
     // finished the processing.
     impl().layer_tree_host_impl->RecordMainFrameTiming(
-        impl().last_processed_begin_main_frame_args,
-        impl().layer_tree_host_impl->CurrentBeginFrameArgs());
+        impl().last_processed_begin_main_frame_args, args);
     impl().last_processed_begin_main_frame_args = BeginFrameArgs();
   }
 }
@@ -560,15 +559,15 @@
   completion->Signal();
 }
 
-void ThreadProxy::ScheduledActionSendBeginMainFrame() {
+void ThreadProxy::ScheduledActionSendBeginMainFrame(
+    const BeginFrameArgs& args) {
   unsigned int begin_frame_id = nextBeginFrameId++;
   benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
       benchmark_instrumentation::kSendBeginFrame, begin_frame_id);
   scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
       new BeginMainFrameAndCommitState);
   begin_main_frame_state->begin_frame_id = begin_frame_id;
-  begin_main_frame_state->begin_frame_args =
-      impl().layer_tree_host_impl->CurrentBeginFrameArgs();
+  begin_main_frame_state->begin_frame_args = args;
   begin_main_frame_state->scroll_info =
       impl().layer_tree_host_impl->ProcessScrollDeltas();
   begin_main_frame_state->memory_allocation_limit_bytes =
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index e11d370a..7be549e 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -223,7 +223,7 @@
   // SchedulerClient implementation
   void WillBeginImplFrame(const BeginFrameArgs& args) override;
   void DidFinishImplFrame() override;
-  void ScheduledActionSendBeginMainFrame() override;
+  void ScheduledActionSendBeginMainFrame(const BeginFrameArgs& args) override;
   DrawResult ScheduledActionDrawAndSwapIfPossible() override;
   DrawResult ScheduledActionDrawAndSwapForced() override;
   void ScheduledActionAnimate() override;
diff --git a/chrome/VERSION b/chrome/VERSION
index 567f494..fc86763 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=48
 MINOR=0
-BUILD=2562
+BUILD=2563
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
index 6add6b8..58914a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
@@ -145,6 +145,27 @@
             "SM-N7505", // Galaxy Note3 Neo
             "SM-N7505L", // Galaxy Note3 Neo
             "SM-N7507", // Galaxy Note3 Neo
+            "HTC One dual sim", // HTC ONE
+            "HTC 801e", // HTC One
+            "HTC One", // HTC One
+            "HTC One 801e", // HTC One
+            "HTC_PN071", // HTC One
+            "HTC 802t", // HTC One
+            "HTC 802t 16GB", // HTC One
+            "HTC 802w", // HTC One
+            "HTC One dual sim", // HTC One
+            "HTC 802d", // HTC One
+            "HTC One dual 802d", // HTC One
+            "HTC One dual sim", // HTC One
+            "HTC One", // HTC One
+            "HTCONE", // HTC One
+            "HTC ONE", // HTC One
+            "HTC One", // HTC One
+            "HTC One 801e", // HTC One 801e
+            "HTC One 801s", // HTC One 801e
+            "HTC One dual 802d", //HTC One Dual 802d
+            "HTC One dual sim", // HTC One Dual Sim
+            "HTC One", // HTC One Google Play edition
     };
 
     private static DocumentModeManager sManager;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index c44e72ad..3b70c45 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -285,7 +285,7 @@
         Auto Sign-in
       </message>
       <message name="IDS_PASSWORDS_AUTO_SIGNIN_DESCRIPTION" desc="Text under 'Auto sign-in' checkbox">
-        Automatically sign in to websites using stored credentials. When the feature is off, you'll be asked for verification every time before signing in to a website.
+        Automatically sign in to websites using stored credentials. When the feature is off, you’ll be asked for verification every time before signing in to a website.
       </message>
       <message name="IDS_SECTION_SAVED_PASSWORDS" desc="Header for the list of passwords that have been saved in Chrome. [CHAR-LIMIT=32]">
         Passwords
@@ -408,10 +408,10 @@
         crash_dump_only_with_wifi
       </message>
       <message name="IDS_DO_NOT_TRACK_TITLE" desc="Title for 'Do Not Track' preference">
-        ‘Do Not Track’
+        “Do Not Track”
       </message>
       <message name="IDS_DO_NOT_TRACK_DESCRIPTION" desc="Description for 'Do Not Track' preference">
-        Enabling ‘Do Not Track’ means that a request will be included with your browsing traffic. Any effect depends on whether a website responds to the request, and how the request is interpreted.
+        Enabling “Do Not Track” means that a request will be included with your browsing traffic. Any effect depends on whether a website responds to the request, and how the request is interpreted.
 
 For example, some websites may respond to this request by showing you ads that aren’t based on other websites you’ve visited. Many websites will still collect and use your browsing data - for example to improve security, to provide content, ads and recommendations on their websites, and to generate reporting statistics.
       </message>
@@ -428,7 +428,7 @@
         Cookies, site data
       </message>
       <message name="IDS_CLEAR_COOKIES_NO_SIGN_OUT_SUMMARY" desc="Text at the bottom of the Clear Browsing Data dialog informing that clearing cookies wouldn't sign the user out of Google Accounts. Dialog also contains a link which opens the Account Management screen.">
-        You won't be signed out of your <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Accounts<ph name="END_LINK">&lt;/link&gt;</ph>
+        You won’t be signed out of your <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Accounts<ph name="END_LINK">&lt;/link&gt;</ph>
       </message>
       <message name="IDS_CLEAR_PASSWORDS_TITLE" desc="Title for Clear Passwords in Clear Browsing Data preference">
         Saved passwords
@@ -449,7 +449,7 @@
         Please wait…
       </message>
       <message name="IDS_CAN_NOT_CLEAR_BROWSING_HISTORY_TOAST" desc="Message on the toast explaining that child account users can not clear their browsing history.">
-        Browsing history can't be cleared with accounts for kids
+        Browsing history can’t be cleared with accounts for kids
       </message>
       <message name="IDS_USAGE_AND_CRASH_REPORTS_TITLE" desc="Title for 'Usage and crash reports' preference">
         Usage and crash reports
@@ -823,7 +823,7 @@
 
       <!-- Child accounts -->
       <message name="IDS_KIDS_ACCOUNT" desc="Identifies an account as a child account.">
-        This is a kid's account
+        This is a kid’s account
       </message>
       <message name="IDS_ACCOUNT_MANAGEMENT_PARENTAL_SETTINGS" desc="Title of parental settings section of account page for child account.">
         Parental Settings
@@ -946,7 +946,7 @@
         You are signing out of an account managed by <ph name="DOMAIN_NAME">%1$s<ex>google.com</ex></ph>. This will delete the Chrome data stored on this device, but the data will remain in your Google Account.
       </message>
       <message name="IDS_FIRSTRUN_SIGNED_IN_TITLE" desc="Message informing the user that they are now signed in.">
-        You're now signed in to Chrome.
+        You’re now signed in to Chrome.
       </message>
       <message name="IDS_FIRSTRUN_SIGNED_IN_DESCRIPTION" desc="Message informing the user what is being synced.">
         Your open bookmarks, history, passwords, and more are being synced with your Google Account.
@@ -1017,7 +1017,7 @@
         This field cannot be blank
       </message>
       <message name="IDS_SYNC_PASSPHRASE_RESET_INSTRUCTIONS" desc="Inform the user how they can reset their passphrase if they have forgotten it." meaning="Android">
-        If you've forgotten your passphrase, stop and reset Sync via <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Dashboard<ph name="END_LINK">&lt;/link&gt;</ph>.
+        If you’ve forgotten your passphrase, stop and reset Sync via <ph name="BEGIN_LINK">&lt;link&gt;</ph>Google Dashboard<ph name="END_LINK">&lt;/link&gt;</ph>.
       </message>
       <message name="IDS_SYNC_PASSPHRASES_DO_NOT_MATCH" desc="Inform user that their sync password does not match.">
         Passphrases do not match
@@ -1036,7 +1036,7 @@
       <message name="IDS_BLUETOOTH_DIALOG_TITLE" desc="The header message shown on top of the dialog that lets the user pick a Bluetooth device for the site to pair with. Shown above a list of Bluetooth devices discovered. ">
         <ph name="SITE">%1$s<ex>https://www.google.com</ex></ph> wants to <ph name="BEGIN_LINK">&lt;link&gt;</ph>pair with<ph name="END_LINK">&lt;/link&gt;</ph>:</message>
       <message name="IDS_BLUETOOTH_SEARCHING" desc="The message shown in the Bluetooth picker dialog while scanning for devices.">
-        Searching for devices...
+        Searching for devices…
       </message>
       <message name="IDS_BLUETOOTH_CONFIRM_BUTTON" desc="The button to confirm association of a website with a Bluetooth device. Use the same term as in 'Pair this Bluetooth headset with your phone.'">
         Pair
@@ -1425,7 +1425,7 @@
 
       <!-- Sad tab page -->
       <message name="IDS_SAD_TAB_SUGGESTIONS" desc="The help message displayed on the sad tab page after a tab crashes.">
-        If you're seeing this frequently, try these <ph name="BEGIN_LINK">&lt;link&gt;</ph>suggestions<ph name="END_LINK">&lt;/link&gt;</ph>.
+        If you’re seeing this frequently, try these <ph name="BEGIN_LINK">&lt;link&gt;</ph>suggestions<ph name="END_LINK">&lt;/link&gt;</ph>.
       </message>
 
       <!-- Web Notifications API -->
@@ -1503,13 +1503,13 @@
         Chrome tabs have moved
       </message>
       <message name="IDS_TABS_AND_APPS_OPT_OUT_TEXT" desc="A promo message shown to users who have document mode enabled to explain the new location for the tabs and provide an option to opt out">
-        See your tabs with other recent apps on your phone's Overview screen. You can control this in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
+        See your tabs with other recent apps on your phone’s Overview screen. You can control this in <ph name="BEGIN_LINK">&lt;link&gt;</ph>Settings<ph name="END_LINK">&lt;/link&gt;</ph>.
       </message>
       <message name="IDS_TABS_AND_APPS_GOT_IT_BUTTON" desc="A button to confirm and dismiss opt out promo">
         Ok, got it
       </message>
       <message name="IDS_TABS_AND_APPS_SETTINGS_DESCRIPTION" desc="A message shown on settings screen from which you can enable/disable the feature that combines Chrome tabs with recent applications and shows them together in the system app switcher.">
-        See your tabs with other recent apps on your phone's Overview screen.
+        See your tabs with other recent apps on your phone’s Overview screen.
       </message>
       <message name="IDS_TABS_AND_APPS_TURN_OFF_TITLE" desc="A message shown as a title of a confirmation dialog to turn off a feature where apps and tabs are located together in recents switcher">
         Separate tabs and apps
@@ -1590,7 +1590,7 @@
         Your parents help manage these settings.
       </message>
       <message name="IDS_FRE_TOS_AND_PRIVACY" desc="Message explaining that use of Chrome is governed by Chrome's terms of service and privacy notice.">
-        By using this application, you agree to Chrome's <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>.
+        By using this application, you agree to Chrome’s <ph name="BEGIN_LINK1">&lt;LINK1&gt;</ph>Terms of Service<ph name="END_LINK1">&lt;/LINK1&gt;</ph> and <ph name="BEGIN_LINK2">&lt;LINK2&gt;</ph>Privacy Notice<ph name="END_LINK2">&lt;/LINK2&gt;</ph>.
       </message>
       <message name="IDS_FRE_SEND_REPORT_CHECK" desc="Text for asking the user to allow sending stats and crash reports">
         Help make Chrome better by sending usage statistics and crash reports to Google.
@@ -1675,7 +1675,7 @@
         Your most visited pages will appear here
       </message>
       <message name="IDS_ACCESSIBILITY_GOOGLE_DOODLE" desc="Content description for the Google Doodle (the fun, alternative Google logo) shown on the new tab page.">
-        Google doodle: <ph name="DOODLE_DESCRIPTION">%1$s<ex>Einstein's birthday</ex></ph>
+        Google doodle: <ph name="DOODLE_DESCRIPTION">%1$s<ex>Einstein’s birthday</ex></ph>
       </message>
       <message name="IDS_NTP_RECENT_TABS_SYNC_PROMO_TITLE" desc="Header for the promo explaining how users can see the list of tabs open on their other devices">
         Other devices
@@ -2179,7 +2179,7 @@
         Touch to return to <ph name="URL_OF_THE_CURRENT_TAB">%1$s<ex>https://apprtc.appspot.com</ex></ph>
       </message>
       <message name="IDS_NEW_TAB_INCOGNITO_HEADER" desc="Header shown when a user opens an incognito tab explaining incognito mode">
-        You've gone incognito.
+        You’ve gone incognito.
       </message>
       <message name="IDS_NEW_TAB_INCOGNITO_MESSAGE" desc="Message shown when a user opens an incognito tab explaining incognito mode">
         Pages you view in incognito tabs won’t stick around in your browser’s history, cookie store, or search history after you’ve closed all of your incognito tabs. Any files you download or bookmarks you create will be kept.
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 3836721..8ff34ec21 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1049,20 +1049,6 @@
     Volume slider
   </message>
 
-<!-- Audio Player -->
-  <message name="IDS_AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL" desc="Label for the Shuffle button of audio player.">
-    Shuffle
-  </message>
-  <message name="IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL" desc="Label for the Repeat button of audio player">
-    Repeat
-  </message>
-  <message name="IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL" desc="Label for a button which is used to open volume slider in audio player.">
-    Open volume slider
-  </message>
-  <message name="IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL" desc="Label for a button which is used to open play list in audio player.">
-    Open play list
-  </message>
-
 <!-- Video Player -->
   <message name="IDS_VIDEO_PLAYER_PLAY_THIS_COMPUTER" desc="In the video player app, message of menu item which is shown at the top of the list of Chromecasts. This menuitem is to play the video on this computer (locally), intead of on TVs with Chromecast.">
     This computer
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 11496fa0..1f7794d 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -230,6 +230,14 @@
           This computer will no longer receive Chromium updates because its hardware is no longer supported.
         </message>
       </if>
+      <if expr="is_win">
+        <message name="IDS_WIN_XP_VISTA_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and about:help warning the user that the computer they are using is about to become unsupported.">
+          Future versions of Chromium will no longer support Windows XP or Windows Vista.
+        </message>
+        <message name="IDS_WIN_XP_VISTA_OBSOLETE_NOW" desc="A message displayed on an at-launch infobar and about:help warning the user that the computer they are using is no longer supported.">
+          Chromium may not function correctly because it is no longer supported on Windows XP or Windows Vista.
+        </message>
+      </if>
       <message name="IDS_ACCNAME_APP" desc="The accessible name for the app menu.">
         Chromium
       </message>
@@ -543,13 +551,6 @@
         </message>
       </if>
 
-      <!-- Autolaunch infobar -->
-      <if expr="is_win">
-        <message name="IDS_AUTO_LAUNCH_INFOBAR_TEXT" desc="The text to show in the infobar when Chromium was automatically launched on startup">
-          Chromium is configured to automatically launch when you start your computer.
-        </message>
-      </if>
-
       <!-- about:flags -->
       <message name="IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_NAME" desc="Title for the flag to enable iframe-based sign-in flows.">
         Enables iframe-based Chromium sign-in flows. This flag overrides --enable-web-based-signin.
@@ -1014,9 +1015,6 @@
 
       <!-- chrome://settings. Android uses native UI for settings -->
       <if expr="not is_android">
-        <message name="IDS_AUTOLAUNCH_TEXT" desc="The text displayed in settings to explain whether Chromium is set to auto-launch on startup or not.">
-          Launch Chromium automatically when your computer starts
-        </message>
         <message name="IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT" desc="The label of the 'Use Chromium as default' browser button">
           Make Chromium the default browser
         </message>
@@ -1201,7 +1199,7 @@
       <!-- Offline interstitial  -->
       <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED" desc="Summary of the error page when the network connection failed. May be followed by platform dependent instructions.">
-        Chromium can’t display the webpage because your computer isn’t connected to the Internet.
+        Chromium can't display the webpage because your computer isn't connected to the Internet.
         </message>
       </if>
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index d066557..6c401a8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -3398,16 +3398,6 @@
         View
       </message>
 
-      <!-- Autolaunch infobar -->
-      <if expr="is_win">
-        <message name="IDS_AUTO_LAUNCH_OK" desc="Label for OK button on Autolaunch confirmation infobar.">
-          OK
-        </message>
-        <message name="IDS_AUTO_LAUNCH_REVERT" desc="Label for button (on Autolaunch confirmation infobar) that disables autolaunching.">
-          Cut it out!
-        </message>
-      </if>
-
       <!-- DevTools attached infobar -->
       <message name="IDS_DEV_TOOLS_INFOBAR_LABEL" desc="Label displayed in an infobar when external debugger is attached to the browser">
         "<ph name="CLIENT_NAME">$1<ex>Extension Foo</ex></ph>" is debugging this browser.
@@ -13361,9 +13351,12 @@
       <message name="IDS_FULLSCREEN_ENTERED_MOUSELOCK" desc="Text displayed in the bubble to inform the user that the page has locked the mouse. (No domain to be shown, e.g. from filesystem page)">
         This page has disabled your mouse cursor.
       </message>
-      <message name="IDS_FULLSCREEN_PRESS_ESC_TO_EXIT" desc="Text displayed in the bubble to tell users how to return to normal mode">
+      <message name="IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_SENTENCE" desc="Text displayed in the bubble to tell users how to return to normal mode.">
         Press <ph name="ACCELERATOR">$1<ex>Esc</ex></ph> to exit.
       </message>
+      <message name="IDS_FULLSCREEN_PRESS_ESC_TO_EXIT" desc="Text displayed in the bubble to tell users how to return to normal mode. Please surround the name of the key (e.g. 'Esc') in pipe characters so it can be rendered as a key.">
+        Press |<ph name="ACCELERATOR">$1<ex>Esc</ex></ph>| to exit
+      </message>
       <message name="IDS_FULLSCREEN_ALLOW" desc="Text in the bubble button that grants permission for a site to enter fullscreen and/or lock the mouse.">
         Allow
       </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 83e23ef..abc976c 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -232,6 +232,14 @@
           This computer will no longer receive Google Chrome updates because its hardware is no longer supported.
         </message>
       </if>
+      <if expr="is_win">
+        <message name="IDS_WIN_XP_VISTA_OBSOLETE_SOON" desc="A message displayed on an at-launch infobar and about:help warning the user that the computer they are using is about to become unsupported.">
+          This computer will soon stop receiving Google Chrome updates because Windows XP and Windows Vista are no longer supported.
+        </message>
+        <message name="IDS_WIN_XP_VISTA_OBSOLETE_NOW" desc="A message displayed on an at-launch infobar and about:help warning the user that the computer they are using is no longer supported.">
+          This computer will no longer receive Google Chrome updates because Windows XP and Windows Vista are no longer supported.
+        </message>
+      </if>
       <message name="IDS_ACCNAME_APP" desc="The accessible name for the app menu.">
         Chrome
       </message>
@@ -545,13 +553,6 @@
         </message>
       </if>
 
-      <!-- Autolaunch infobar -->
-      <if expr="is_win">
-        <message name="IDS_AUTO_LAUNCH_INFOBAR_TEXT" desc="The text to show in the infobar when Chrome was automatically launched on startup">
-          Google Chrome is configured to automatically launch when you start your computer.
-        </message>
-      </if>
-
       <!-- about:flags -->
       <message name="IDS_FLAGS_ENABLE_IFRAME_BASED_SIGNIN_NAME" desc="Title for the flag to enable iframe-based sign-in flows.">
         Enables iframe-based Chrome sign-in flows. This flag overrides --enable-web-based-signin.
@@ -1016,9 +1017,6 @@
 
       <!-- chrome://settings. Android uses native UI for settings -->
       <if expr="not is_android">
-        <message name="IDS_AUTOLAUNCH_TEXT" desc="The text displayed in settings to explain whether Chromium is set to auto-launch on startup or not.">
-          Launch Chromium automatically when your computer starts
-        </message>
         <message name="IDS_OPTIONS_DEFAULTBROWSER_USEASDEFAULT" desc="The label of the 'Use Chrome as default' browser button">
           Make Google Chrome the default browser
         </message>
@@ -1203,7 +1201,7 @@
       <!-- Offline interstitial  -->
       <if expr="not is_android and not is_ios">
         <message name="IDS_ERRORPAGES_SUMMARY_INTERNET_DISCONNECTED" desc="Summary of the error page when the network connection failed. May be followed by platform dependent instructions.">
-          Google Chrome can’t display the webpage because your computer isn’t connected to the Internet.
+          Google Chrome can't display the webpage because your computer isn't connected to the Internet.
         </message>
       </if>
 
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5cf72bf..a9a506a 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2002,13 +2002,6 @@
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableMaterialDesignDownloads,
                                switches::kDisableMaterialDesignDownloads)},
 #endif
-#if defined(OS_WIN) || defined(OS_MACOSX)
-    {"enable-tab-discarding",
-     IDS_FLAGS_ENABLE_TAB_DISCARDING_NAME,
-     IDS_FLAGS_ENABLE_TAB_DISCARDING_DESCRIPTION,
-     kOsWin | kOsMac,
-     SINGLE_VALUE_TYPE(switches::kEnableTabDiscarding)},
-#endif
     {"enable-clear-browsing-data-counters",
      IDS_FLAGS_ENABLE_CLEAR_BROWSING_DATA_COUNTERS_NAME,
      IDS_FLAGS_ENABLE_CLEAR_BROWSING_DATA_COUNTERS_DESCRIPTION,
diff --git a/chrome/browser/auto_launch_trial.cc b/chrome/browser/auto_launch_trial.cc
deleted file mode 100644
index a235de7..0000000
--- a/chrome/browser/auto_launch_trial.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/auto_launch_trial.h"
-
-#include "base/files/file_path.h"
-#include "base/metrics/field_trial.h"
-#include "base/strings/string_util.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/installer/util/master_preferences.h"
-#include "chrome/installer/util/master_preferences_constants.h"
-
-const char kAutoLaunchTrialName[] = "AutoLaunchExperiment";
-const char kAutoLaunchTrialAutoLaunchGroup[] = "AutoLaunching";
-const char kAutoLaunchTrialControlGroup[] = "NotAutoLaunching";
-
-namespace auto_launch_trial {
-
-bool IsInAutoLaunchGroup() {
-  return base::FieldTrialList::TrialExists(kAutoLaunchTrialName) &&
-         base::FieldTrialList::Find(kAutoLaunchTrialName)->group_name()
-             == kAutoLaunchTrialAutoLaunchGroup;
-}
-
-bool IsInExperimentGroup(const std::string& brand_code) {
-  return base::LowerCaseEqualsASCII(brand_code, "rngp");
-}
-
-bool IsInControlGroup(const std::string& brand_code) {
-  return base::LowerCaseEqualsASCII(brand_code, "rngq");
-}
-
-}  // namespace auto_launch_trial
diff --git a/chrome/browser/auto_launch_trial.h b/chrome/browser/auto_launch_trial.h
deleted file mode 100644
index 1c7cf4c..0000000
--- a/chrome/browser/auto_launch_trial.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_
-#define CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_
-
-#include <string>
-
-// Strings used with the "auto launching Chrome at computer startup" trial.  If
-// the field trial is running then...
-// base::FieldTrialList::TrialExists(kAutoLaunchTrial_Name) returns true.
-//
-// The field trial consists of two groups of users: those that auto-launch
-// Chrome at startup and those that don't.  The group_name() of the field
-// trial object is used to determine the group that the user belongs to.
-//
-// The field trial is setup in ChromeBrowserMainParts::AutoLaunchFieldTrial()
-// based on the user's brand code:
-//
-//   - brand RNGP auto launches Chrome on computer startup.
-//   - brand RNGQ does not.
-//   - any other brand code does whatever comes natural to it.
-
-extern const char kAutoLaunchTrialName[];
-extern const char kAutoLaunchTrialAutoLaunchGroup[];
-extern const char kAutoLaunchTrialControlGroup[];
-
-namespace auto_launch_trial {
-
-// The possible responses for the auto-launch infobar.
-enum InfobarMetricResponse {
-  INFOBAR_CUT_IT_OUT = 0,
-  INFOBAR_OK,
-  INFOBAR_IGNORE,
-};
-
-// Whether the auto-launch experiment is active and the user is part of it.
-bool IsInAutoLaunchGroup();
-
-// Whether the brand is part of the experiment group for auto-launch.
-bool IsInExperimentGroup(const std::string& brand_code);
-
-// Whether the brand is part of the control group for auto-launch.
-bool IsInControlGroup(const std::string& brand_code);
-
-}  // namespace auto_launch_trial
-
-#endif  // CHROME_BROWSER_AUTO_LAUNCH_TRIAL_H_
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index f238c73..ae14bb6 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -603,6 +603,20 @@
     }
   }
 
+  if (remove_mask & REMOVE_HISTORY) {
+    password_manager::PasswordStore* password_store =
+        PasswordStoreFactory::GetForProfile(
+            profile_, ServiceAccessType::EXPLICIT_ACCESS).get();
+
+    if (password_store) {
+      waiting_for_clear_passwords_stats_ = true;
+      password_store->RemoveStatisticsCreatedBetween(
+          delete_begin_, delete_end_,
+          base::Bind(&BrowsingDataRemover::OnClearedPasswordsStats,
+                     base::Unretained(this)));
+    }
+  }
+
   if (remove_mask & REMOVE_FORM_DATA) {
     content::RecordAction(UserMetricsAction("ClearBrowsingData_Autofill"));
     scoped_refptr<autofill::AutofillWebDataService> web_data_service =
@@ -876,6 +890,7 @@
          !waiting_for_clear_network_predictor_ &&
          !waiting_for_clear_networking_history_ &&
          !waiting_for_clear_passwords_ &&
+         !waiting_for_clear_passwords_stats_ &&
          !waiting_for_clear_platform_keys_ &&
          !waiting_for_clear_plugin_data_ &&
          !waiting_for_clear_pnacl_cache_ &&
@@ -1087,6 +1102,12 @@
   NotifyAndDeleteIfDone();
 }
 
+void BrowsingDataRemover::OnClearedPasswordsStats() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  waiting_for_clear_passwords_stats_ = false;
+  NotifyAndDeleteIfDone();
+}
+
 void BrowsingDataRemover::OnClearedCookies(int num_deleted) {
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     BrowserThread::PostTask(
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h
index f0b0847..62cd36ea 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.h
+++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -66,7 +66,8 @@
     REMOVE_DOWNLOADS = 1 << 3,
     REMOVE_FILE_SYSTEMS = 1 << 4,
     REMOVE_FORM_DATA = 1 << 5,
-    // In addition to visits, REMOVE_HISTORY removes keywords and last session.
+    // In addition to visits, REMOVE_HISTORY removes keywords, last session and
+    // passwords UI statistics.
     REMOVE_HISTORY = 1 << 6,
     REMOVE_INDEXEDDB = 1 << 7,
     REMOVE_LOCAL_STORAGE = 1 << 8,
@@ -92,8 +93,8 @@
     REMOVE_HOSTED_APP_DATA_TESTONLY = 1 << 31,
 
     // "Site data" includes cookies, appcache, file systems, indexedDBs, local
-    // storage, webSQL, service workers, cache storage, plugin data, and web app
-    // data (on Android).
+    // storage, webSQL, service workers, cache storage, plugin data, web app
+    // data (on Android) and statistics about passwords.
     REMOVE_SITE_DATA = REMOVE_APPCACHE | REMOVE_COOKIES | REMOVE_FILE_SYSTEMS |
                        REMOVE_INDEXEDDB |
                        REMOVE_LOCAL_STORAGE |
@@ -358,6 +359,10 @@
   // Callback for when passwords for the requested time range have been cleared.
   void OnClearedPasswords();
 
+  // Callback for when passwords stats for the requested time range have been
+  // cleared.
+  void OnClearedPasswordsStats();
+
   // Callback for when Cookies has been deleted. Invokes NotifyAndDeleteIfDone.
   void OnClearedCookies(int num_deleted);
 
@@ -456,6 +461,7 @@
   bool waiting_for_clear_network_predictor_ = false;
   bool waiting_for_clear_networking_history_ = false;
   bool waiting_for_clear_passwords_ = false;
+  bool waiting_for_clear_passwords_stats_ = false;
   bool waiting_for_clear_platform_keys_ = false;
   bool waiting_for_clear_plugin_data_ = false;
   bool waiting_for_clear_pnacl_cache_ = false;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index cbaaa50..cf26f6c 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -27,6 +27,7 @@
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
 #include "chrome/browser/favicon/favicon_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/password_manager/password_store_factory.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -44,6 +45,9 @@
 #include "components/favicon/core/favicon_service.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/omnibox/browser/omnibox_pref_names.h"
+#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/cookie_store_factory.h"
 #include "content/public/browser/dom_storage_context.h"
@@ -2116,3 +2120,20 @@
   BlockUntilOriginDataRemoved(BrowsingDataRemover::EVERYTHING,
                               BrowsingDataRemover::REMOVE_DOWNLOADS, kOrigin1);
 }
+
+TEST_F(BrowsingDataRemoverTest, RemovePasswordStatistics) {
+  PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
+      GetProfile(),
+      password_manager::BuildPasswordStoreService<
+          content::BrowserContext, password_manager::MockPasswordStore>);
+  password_manager::MockPasswordStore* store =
+      static_cast<password_manager::MockPasswordStore*>(
+          PasswordStoreFactory::GetInstance()
+              ->GetForProfile(GetProfile(), ServiceAccessType::EXPLICIT_ACCESS)
+              .get());
+  EXPECT_CALL(*store, RemoveStatisticsCreatedBetweenImpl(base::Time(),
+                                                         base::Time::Max()));
+  BlockUntilBrowsingDataRemoved(
+      BrowsingDataRemover::EVERYTHING,
+      BrowsingDataRemover::REMOVE_HISTORY, false);
+}
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc
index 4e6ac08..d5761d4 100644
--- a/chrome/browser/chrome_browser_field_trials_desktop.cc
+++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -8,8 +8,6 @@
 
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
-#include "chrome/browser/auto_launch_trial.h"
-#include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/prerender/prerender_field_trial.h"
 #include "chrome/browser/tracing/background_tracing_field_trial.h"
 #include "chrome/common/chrome_switches.h"
@@ -21,20 +19,6 @@
 
 namespace {
 
-void AutoLaunchChromeFieldTrial() {
-  std::string brand;
-  google_brand::GetBrand(&brand);
-
-  // Create a 100% field trial based on the brand code.
-  if (auto_launch_trial::IsInExperimentGroup(brand)) {
-    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
-                                           kAutoLaunchTrialAutoLaunchGroup);
-  } else if (auto_launch_trial::IsInControlGroup(brand)) {
-    base::FieldTrialList::CreateFieldTrial(kAutoLaunchTrialName,
-                                           kAutoLaunchTrialControlGroup);
-  }
-}
-
 void SetupLightSpeedTrials() {
   if (!variations::GetVariationParamValue("LightSpeed", "NoGpu").empty()) {
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
@@ -67,7 +51,6 @@
 
 void SetupDesktopFieldTrials(const base::CommandLine& parsed_command_line) {
   prerender::ConfigurePrerender(parsed_command_line);
-  AutoLaunchChromeFieldTrial();
   SetupLightSpeedTrials();
   tracing::SetupBackgroundTracingFieldTrial();
   SetupStunProbeTrial();
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 48d69db..059a6ad 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1163,8 +1163,7 @@
 #elif defined(OS_WIN) || defined(OS_MACOSX)
   const std::string group_name =
       base::FieldTrialList::FindFullName("AutomaticTabDiscarding");
-  if (parsed_command_line().HasSwitch(switches::kEnableTabDiscarding) ||
-      base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE)) {
+  if (base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE)) {
     bool enabled_once = base::StartsWith(group_name, "Enabled_Once",
                                          base::CompareCase::SENSITIVE);
     g_browser_process->GetTabManager()->Start(enabled_once);
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 95ce0f2..73563c3 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -955,7 +955,7 @@
   UpdateVirtualKeyboardFromPref();
 }
 
-void AccessibilityManager::ActiveUserChanged(const std::string& user_id) {
+void AccessibilityManager::ActiveUserChanged(const AccountId& account_id) {
   SetProfile(ProfileManager::GetActiveUserProfile());
 }
 
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index c961b205..26bdf40 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -164,7 +164,7 @@
   bool IsBrailleDisplayConnected() const;
 
   // SessionStateObserver overrides:
-  void ActiveUserChanged(const std::string& user_id) override;
+  void ActiveUserChanged(const AccountId& account_id) override;
 
   // ShellObserver overrides:
   void OnAppTerminating() override;
diff --git a/chrome/browser/chromeos/accessibility/magnification_manager.cc b/chrome/browser/chromeos/accessibility/magnification_manager.cc
index fb9f43e2..d1cb19c 100644
--- a/chrome/browser/chromeos/accessibility/magnification_manager.cc
+++ b/chrome/browser/chromeos/accessibility/magnification_manager.cc
@@ -29,6 +29,8 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 
+class AccountId;
+
 namespace chromeos {
 
 namespace {
@@ -107,7 +109,7 @@
   void SetProfileForTest(Profile* profile) override { SetProfile(profile); }
 
   // SessionStateObserver overrides:
-  void ActiveUserChanged(const std::string& user_id) override {
+  void ActiveUserChanged(const AccountId& account_id) override {
     SetProfile(ProfileManager::GetActiveUserProfile());
   }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 143abd9..c1c54cb 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -40,6 +40,7 @@
 #include "chromeos/settings/timezone_settings.h"
 #include "components/drive/drive_pref_names.h"
 #include "components/drive/event_logger.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/user_manager/user_manager.h"
@@ -88,7 +89,8 @@
     // Make a ProfileInfo.
     linked_ptr<api::file_manager_private::ProfileInfo> profile_info(
         new api::file_manager_private::ProfileInfo());
-    profile_info->profile_id = multi_user_util::GetUserIDFromProfile(profile);
+    profile_info->profile_id =
+        multi_user_util::GetAccountIdFromProfile(profile).GetUserEmail();
     profile_info->display_name = UTF16ToUTF8(user->GetDisplayName());
     // TODO(hirono): Remove the property from the profile_info.
     profile_info->is_current_profile = true;
@@ -376,17 +378,18 @@
   AppWindow* const app_window = GetCurrentAppWindow(this);
   chrome::MultiUserWindowManager* const window_manager =
       chrome::MultiUserWindowManager::GetInstance();
-  const std::string current_profile_id =
-      multi_user_util::GetUserIDFromProfile(GetProfile());
-  const std::string display_profile_id =
-      window_manager && app_window ? window_manager->GetUserPresentingWindow(
-                                         app_window->GetNativeWindow())
-                                   : "";
+  const AccountId current_profile_id =
+      multi_user_util::GetAccountIdFromProfile(GetProfile());
+  const AccountId display_profile_id =
+      window_manager && app_window
+          ? window_manager->GetUserPresentingWindow(
+                app_window->GetNativeWindow())
+          : EmptyAccountId();
 
   results_ = api::file_manager_private::GetProfiles::Results::Create(
-      profiles,
-      current_profile_id,
-      display_profile_id.empty() ? current_profile_id : display_profile_id);
+      profiles, current_profile_id.GetUserEmail(),
+      display_profile_id.is_valid() ? display_profile_id.GetUserEmail()
+                                    : current_profile_id.GetUserEmail());
   return true;
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 87684e5e..1e6fe65 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -250,14 +250,6 @@
   SET_STRING("AUDIO_PLAYER_DEFAULT_ARTIST",
              IDS_FILE_BROWSER_AUDIO_PLAYER_DEFAULT_ARTIST);
   SET_STRING("AUDIO_PLAYER_TITLE", IDS_FILE_BROWSER_AUDIO_PLAYER_TITLE);
-  SET_STRING("AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL",
-             IDS_AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL);
-  SET_STRING("AUDIO_PLAYER_REPEAT_BUTTON_LABEL",
-             IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL);
-  SET_STRING("AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL",
-             IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL);
-  SET_STRING("AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL",
-             IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL);
 }
 
 void AddStringsForCloudImport(base::DictionaryValue* dict) {
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
index ff3e942..442884d 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_private_api_unittest.cc
@@ -235,8 +235,8 @@
 void WallpaperPrivateApiMultiUserUnittest::SetUpMultiUserWindowManager(
     const AccountId& active_account_id,
     chrome::MultiUserWindowManager::MultiProfileMode mode) {
-  multi_user_window_manager_ = new chrome::MultiUserWindowManagerChromeOS(
-      active_account_id.GetUserEmail());
+  multi_user_window_manager_ =
+      new chrome::MultiUserWindowManagerChromeOS(active_account_id);
   multi_user_window_manager_->Init();
   chrome::MultiUserWindowManager::SetInstanceForTest(
       multi_user_window_manager_, mode);
@@ -249,8 +249,7 @@
 void WallpaperPrivateApiMultiUserUnittest::SwitchActiveUser(
     const AccountId& active_account_id) {
   fake_user_manager()->SwitchActiveUser(active_account_id);
-  multi_user_window_manager_->ActiveUserChanged(
-      active_account_id.GetUserEmail());
+  multi_user_window_manager_->ActiveUserChanged(active_account_id);
 }
 
 // In multi profile mode, user may open wallpaper picker in one profile and
@@ -273,18 +272,13 @@
   ash::wm::WindowState* window3_state = ash::wm::GetWindowState(window3.get());
   ash::wm::WindowState* window4_state = ash::wm::GetWindowState(window4.get());
 
-  multi_user_window_manager()->SetWindowOwner(window0.get(),
-                                              test_account_id1_.GetUserEmail());
-  multi_user_window_manager()->SetWindowOwner(window1.get(),
-                                              test_account_id1_.GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window0.get(), test_account_id1_);
+  multi_user_window_manager()->SetWindowOwner(window1.get(), test_account_id1_);
 
   // Set some windows to an inactive owner.
-  multi_user_window_manager()->SetWindowOwner(window2.get(),
-                                              test_account_id2_.GetUserEmail());
-  multi_user_window_manager()->SetWindowOwner(window3.get(),
-                                              test_account_id2_.GetUserEmail());
-  multi_user_window_manager()->SetWindowOwner(window4.get(),
-                                              test_account_id2_.GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window2.get(), test_account_id2_);
+  multi_user_window_manager()->SetWindowOwner(window3.get(), test_account_id2_);
+  multi_user_window_manager()->SetWindowOwner(window4.get(), test_account_id2_);
 
   EXPECT_FALSE(window0_state->IsMinimized());
   EXPECT_FALSE(window1_state->IsMinimized());
@@ -377,20 +371,16 @@
   ash::wm::WindowState* window2_state = ash::wm::GetWindowState(window2.get());
   ash::wm::WindowState* window3_state = ash::wm::GetWindowState(window3.get());
 
-  multi_user_window_manager()->SetWindowOwner(window0.get(),
-                                              test_account_id1_.GetUserEmail());
-  multi_user_window_manager()->SetWindowOwner(window1.get(),
-                                              test_account_id1_.GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window0.get(), test_account_id1_);
+  multi_user_window_manager()->SetWindowOwner(window1.get(), test_account_id1_);
 
   // Set some windows to an inactive owner.
-  multi_user_window_manager()->SetWindowOwner(window2.get(),
-                                              test_account_id2_.GetUserEmail());
-  multi_user_window_manager()->SetWindowOwner(window3.get(),
-                                              test_account_id2_.GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window2.get(), test_account_id2_);
+  multi_user_window_manager()->SetWindowOwner(window3.get(), test_account_id2_);
 
   // Teleport window2 to kTestAccount1.
-  multi_user_window_manager()->ShowWindowForUser(
-      window2.get(), test_account_id1_.GetUserEmail());
+  multi_user_window_manager()->ShowWindowForUser(window2.get(),
+                                                 test_account_id1_);
 
   // Initial window state. All windows shouldn't be minimized.
   EXPECT_FALSE(window0_state->IsMinimized());
diff --git a/chrome/browser/chromeos/file_system_provider/notification_manager.cc b/chrome/browser/chromeos/file_system_provider/notification_manager.cc
index 2a40d42d..44b3b3c 100644
--- a/chrome/browser/chromeos/file_system_provider/notification_manager.cc
+++ b/chrome/browser/chromeos/file_system_provider/notification_manager.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/extensions/app_icon_loader_impl.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
@@ -118,7 +119,8 @@
   message_center::NotifierId notifier_id(
       message_center::NotifierId::SYSTEM_COMPONENT,
       file_system_info_.mount_path().value());
-  notifier_id.profile_id = multi_user_util::GetUserIDFromProfile(profile_);
+  notifier_id.profile_id =
+      multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail();
 
   scoped_ptr<message_center::Notification> notification(
       new message_center::Notification(
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc
index 67cf837..8808a34 100644
--- a/chrome/browser/download/download_extensions.cc
+++ b/chrome/browser/download/download_extensions.cc
@@ -70,6 +70,97 @@
     // Included for parity with kSafeBrowsingFileTypes.
     {"bin", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
 
+    // Archive file types. Not inherently dangerous, but could contain dangerous
+    // files. Included for parity with kSafeBrowsingFileTypes.
+    {"001", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"7z", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"ace", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"arc", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"arj", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"b64", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"balz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"bhx", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"bz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"bz2", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"bzip2", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"cab", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"cpio", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"fat", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"gz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"gzip", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"hfs", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"hqx", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"iso", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lha", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lpaq1", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lpaq5", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lpaq8", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lzh", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"lzma", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"mim", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"ntfs", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"paq8f", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"paq8jd", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"paq8l", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"paq8o", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"pea", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"quad", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r00", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r01", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r02", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r03", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r04", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r05", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r06", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r07", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r08", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r09", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r10", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r11", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r12", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r13", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r14", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r15", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r16", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r17", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r18", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r19", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r20", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r21", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r22", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r23", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r24", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r25", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r26", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r27", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r28", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"r29", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"rar", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"squashfs", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"swm", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tar", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"taz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tbz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tbz2", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tgz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tpz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"txz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"tz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"udf", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"uu", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"uue", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"vhd", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"vmdk", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"wim", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"wrc", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"xar", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"xxe", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"xz", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"z", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"zip", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"zipx", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+    {"zpaq", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
+
     // Windows, all file categories. The list is in alphabetical order of
     // extensions. Exceptions are made for logical groupings of file types.
     //
@@ -399,7 +490,10 @@
 #endif
 #if defined(OS_LINUX)
     {"deb", ALLOW_ON_USER_GESTURE, DISALLOW_AUTO_OPEN},
+    {"pet", ALLOW_ON_USER_GESTURE, DISALLOW_AUTO_OPEN},
+    {"pup", ALLOW_ON_USER_GESTURE, DISALLOW_AUTO_OPEN},
     {"rpm", ALLOW_ON_USER_GESTURE, DISALLOW_AUTO_OPEN},
+    {"slp", ALLOW_ON_USER_GESTURE, DISALLOW_AUTO_OPEN},
 
     // "common" executable file extensions for linux. There's not really much
     // reason to block since they require execute bit to actually run. Included
diff --git a/chrome/browser/feedback/show_feedback_page.cc b/chrome/browser/feedback/show_feedback_page.cc
index f70a83d..6a5c8584 100644
--- a/chrome/browser/feedback/show_feedback_page.cc
+++ b/chrome/browser/feedback/show_feedback_page.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
@@ -66,14 +67,14 @@
   // Obtains the display profile ID on which the Feedback window should show.
   chrome::MultiUserWindowManager* const window_manager =
       chrome::MultiUserWindowManager::GetInstance();
-  const std::string display_profile_id =
+  const AccountId display_account_id =
       window_manager && browser
           ? window_manager->GetUserPresentingWindow(
                 browser->window()->GetNativeWindow())
-          : "";
-  profile = display_profile_id.empty()
-                ? profile
-                : multi_user_util::GetProfileFromUserID(display_profile_id);
+          : EmptyAccountId();
+  profile = display_account_id.is_valid()
+                ? multi_user_util::GetProfileFromAccountId(display_account_id)
+                : profile;
 #endif
 
   extensions::FeedbackPrivateAPI* api =
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm
index 61261a4..9dc61f8 100644
--- a/chrome/browser/mac/keystone_glue.mm
+++ b/chrome/browser/mac/keystone_glue.mm
@@ -23,7 +23,6 @@
 #include "base/threading/worker_pool.h"
 #include "build/build_config.h"
 #import "chrome/browser/mac/keystone_registration.h"
-#include "chrome/browser/mac/obsolete_system.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/grit/chromium_strings.h"
@@ -1080,9 +1079,6 @@
   // Info.plist, tag suffix components should only be appended to the tag
   // suffix in ASCII sort order.
   NSString* tagSuffix = @"";
-  if (ObsoleteSystemMac::Has32BitOnlyCPU()) {
-    tagSuffix = [tagSuffix stringByAppendingString:@"-32bit"];
-  }
   if ([self wantsFullInstaller]) {
     tagSuffix = [tagSuffix stringByAppendingString:@"-full"];
   }
diff --git a/chrome/browser/mac/obsolete_system.cc b/chrome/browser/mac/obsolete_system.cc
deleted file mode 100644
index 32473b2..0000000
--- a/chrome/browser/mac/obsolete_system.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/mac/obsolete_system.h"
-
-#include <sys/sysctl.h>
-#include <sys/types.h>
-
-#include "chrome/grit/chromium_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if !defined(ARCH_CPU_64_BITS)
-
-// static
-bool ObsoleteSystemMac::Has32BitOnlyCPU() {
-  int value;
-  size_t valueSize = sizeof(value);
-  if (sysctlbyname("hw.cpu64bit_capable", &value, &valueSize, NULL, 0) != 0) {
-    return true;
-  }
-  return value == 0;
-}
-
-// static
-base::string16 ObsoleteSystemMac::LocalizedObsoleteSystemString() {
-  return l10n_util::GetStringUTF16(
-      Is32BitEndOfTheLine() ? IDS_MAC_32_BIT_OBSOLETE_NOW :
-                              IDS_MAC_32_BIT_OBSOLETE_SOON);
-}
-
-#endif
diff --git a/chrome/browser/mac/obsolete_system.h b/chrome/browser/mac/obsolete_system.h
deleted file mode 100644
index c372770..0000000
--- a/chrome/browser/mac/obsolete_system.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MAC_OBSOLETE_SYSTEM_H_
-#define CHROME_BROWSER_MAC_OBSOLETE_SYSTEM_H_
-
-#include "base/basictypes.h"
-#include "base/strings/string16.h"
-
-class ObsoleteSystemMac {
- public:
-  // true if 32-bit-only systems are already considered obsolete, or if
-  // they'll be considered obsolete soon. Used to control whether to show
-  // messaging about 32-bit deprecation within the app.
-  static bool Is32BitObsoleteNowOrSoon() {
-#if defined(GOOGLE_CHROME_BUILD)
-    return true;
-#else
-    return false;
-#endif
-  }
-
-  // true if the system's CPU is 32-bit-only, false if it's 64-bit-capable.
-#if !defined(ARCH_CPU_64_BITS)
-  static bool Has32BitOnlyCPU();
-#else
-  static bool Has32BitOnlyCPU() {
-    return false;
-  }
-#endif
-
-  // Returns a localized string informing users that their system will either
-  // soon be unsupported by future versions of the application, or that they
-  // are already using the last version of the application that supports their
-  // system. Do not use the returned string unless both
-  // Is32BitObsoleteNowOrSoon() and Has32BitOnlyCPU() return true.
-#if !defined(ARCH_CPU_64_BITS)
-  static base::string16 LocalizedObsoleteSystemString();
-#else
-  static base::string16 LocalizedObsoleteSystemString() {
-    return base::string16();
-  }
-#endif
-
-  // true if this is the final release that will run on 32-bit-only systems.
-  static bool Is32BitEndOfTheLine() {
-    return true;
-  }
-
- private:
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ObsoleteSystemMac);
-};
-
-#endif  // CHROME_BROWSER_MAC_OBSOLETE_SYSTEM_H_
diff --git a/chrome/browser/memory/tab_manager_browsertest.cc b/chrome/browser/memory/tab_manager_browsertest.cc
index 9a13eaa..71e5938 100644
--- a/chrome/browser/memory/tab_manager_browsertest.cc
+++ b/chrome/browser/memory/tab_manager_browsertest.cc
@@ -25,16 +25,7 @@
 
 namespace memory {
 
-class TabManagerTest : public InProcessBrowserTest {
- public:
-  // Tab discarding is enabled by default on CrOS, on other platforms, force it
-  // by setting the command line flag.
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-#if !defined(OS_CHROMEOS)
-    command_line->AppendSwitch(switches::kEnableTabDiscarding);
-#endif
-  }
-};
+using TabManagerTest = InProcessBrowserTest;
 
 IN_PROC_BROWSER_TEST_F(TabManagerTest, TabManagerBasics) {
   using content::WindowedNotificationObserver;
diff --git a/chrome/browser/notifications/message_center_notifications_unittest.cc b/chrome/browser/notifications/message_center_notifications_unittest.cc
index 99cb8d4..cdaf477 100644
--- a/chrome/browser/notifications/message_center_notifications_unittest.cc
+++ b/chrome/browser/notifications/message_center_notifications_unittest.cc
@@ -30,6 +30,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
+#include "components/signin/core/account_id/account_id.h"
 #endif
 
 namespace message_center {
@@ -114,7 +115,8 @@
 #if defined(OS_CHROMEOS)
 TEST_F(MessageCenterNotificationManagerTest, MultiUserUpdates) {
   TestingProfile profile;
-  std::string active_user_id = multi_user_util::GetUserIDFromProfile(&profile);
+  const AccountId active_user_id(
+      multi_user_util::GetAccountIdFromProfile(&profile));
   chrome::MultiUserWindowManagerChromeOS* multi_user_window_manager =
       new chrome::MultiUserWindowManagerChromeOS(active_user_id);
   multi_user_window_manager->Init();
diff --git a/chrome/browser/notifications/profile_notification.cc b/chrome/browser/notifications/profile_notification.cc
index 8c1b7ac..1109b796 100644
--- a/chrome/browser/notifications/profile_notification.cc
+++ b/chrome/browser/notifications/profile_notification.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
+#include "components/signin/core/account_id/account_id.h"
 
 // static
 std::string ProfileNotification::GetProfileNotificationId(
@@ -30,7 +31,8 @@
           notification) {
   DCHECK(profile);
 #if defined(OS_CHROMEOS)
-  notification_.set_profile_id(multi_user_util::GetUserIDFromProfile(profile));
+  notification_.set_profile_id(
+      multi_user_util::GetAccountIdFromProfile(profile).GetUserEmail());
 #endif
 }
 
diff --git a/chrome/browser/obsolete_system/obsolete_system.h b/chrome/browser/obsolete_system/obsolete_system.h
new file mode 100644
index 0000000..846dba0
--- /dev/null
+++ b/chrome/browser/obsolete_system/obsolete_system.h
@@ -0,0 +1,37 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_OBSOLETE_SYSTEM_OBSOLETE_SYSTEM_H_
+#define CHROME_BROWSER_OBSOLETE_SYSTEM_OBSOLETE_SYSTEM_H_
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+class ObsoleteSystem {
+ public:
+  // true if the system is already considered obsolete, or if it'll be
+  // considered obsolete soon. Used to control whether to show messaging about
+  // deprecation within the app.
+  static bool IsObsoleteNowOrSoon();
+
+  // Returns a localized string informing users that their system will either
+  // soon be unsupported by future versions of the application, or that they
+  // are already using the last version of the application that supports their
+  // system. Do not use the returned string unless IsObsoleteNowOrSoon() returns
+  // true.
+  static base::string16 LocalizedObsoleteString();
+
+  // true if this is the final release. This is only valid when
+  // IsObsoleteNowOrSoon() returns true.
+  static bool IsEndOfTheLine();
+
+  // A help URL to explain the deprecation. Do not use the returned string
+  // unless IsObsoleteNowOrSoon() returns true.
+  static const char* GetLinkURL();
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ObsoleteSystem);
+};
+
+#endif  // CHROME_BROWSER_OBSOLETE_SYSTEM_OBSOLETE_SYSTEM_H_
diff --git a/chrome/browser/obsolete_system/obsolete_system_linux.cc b/chrome/browser/obsolete_system/obsolete_system_linux.cc
new file mode 100644
index 0000000..10d94a57
--- /dev/null
+++ b/chrome/browser/obsolete_system/obsolete_system_linux.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/obsolete_system/obsolete_system.h"
+
+// static
+bool ObsoleteSystem::IsObsoleteNowOrSoon() {
+  return false;
+}
+
+// static
+base::string16 ObsoleteSystem::LocalizedObsoleteString() {
+  return base::string16();
+}
+
+// static
+bool ObsoleteSystem::IsEndOfTheLine() {
+  return false;
+}
+
+// static
+const char* ObsoleteSystem::GetLinkURL() {
+  return "";
+}
diff --git a/chrome/browser/obsolete_system/obsolete_system_mac.cc b/chrome/browser/obsolete_system/obsolete_system_mac.cc
new file mode 100644
index 0000000..5d00df2
--- /dev/null
+++ b/chrome/browser/obsolete_system/obsolete_system_mac.cc
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/obsolete_system/obsolete_system.h"
+
+// static
+bool ObsoleteSystem::IsObsoleteNowOrSoon() {
+  return false;
+}
+
+// static
+base::string16 ObsoleteSystem::LocalizedObsoleteString() {
+  return base::string16();
+}
+
+// static
+bool ObsoleteSystem::IsEndOfTheLine() {
+  return false;
+}
+
+// static
+const char* ObsoleteSystem::GetLinkURL() {
+  return "";
+}
diff --git a/chrome/browser/obsolete_system/obsolete_system_win.cc b/chrome/browser/obsolete_system/obsolete_system_win.cc
new file mode 100644
index 0000000..c356b481
--- /dev/null
+++ b/chrome/browser/obsolete_system/obsolete_system_win.cc
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/obsolete_system/obsolete_system.h"
+
+#include "base/win/windows_version.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/chromium_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+// static
+bool ObsoleteSystem::IsObsoleteNowOrSoon() {
+  return base::win::GetVersion() < base::win::VERSION_WIN7;
+}
+
+// static
+base::string16 ObsoleteSystem::LocalizedObsoleteString() {
+  return l10n_util::GetStringUTF16(IsEndOfTheLine()
+                                       ? IDS_WIN_XP_VISTA_OBSOLETE_NOW
+                                       : IDS_WIN_XP_VISTA_OBSOLETE_SOON);
+}
+
+// static
+bool ObsoleteSystem::IsEndOfTheLine() {
+  return false;
+}
+
+// static
+const char* ObsoleteSystem::GetLinkURL() {
+  return chrome::kWindowsXPVistaDeprecationURL;
+}
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index a9fee52..f08ac73 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -391,8 +391,8 @@
   return web_contents()->GetBrowserContext()->IsOffTheRecord();
 }
 
-password_manager::PasswordManager*
-ChromePasswordManagerClient::GetPasswordManager() {
+const password_manager::PasswordManager*
+ChromePasswordManagerClient::GetPasswordManager() const {
   return &password_manager_;
 }
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index f804306..1565545 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -74,7 +74,7 @@
   bool WasLastNavigationHTTPError() const override;
   bool DidLastPageLoadEncounterSSLErrors() const override;
   bool IsOffTheRecord() const override;
-  password_manager::PasswordManager* GetPasswordManager() override;
+  const password_manager::PasswordManager* GetPasswordManager() const override;
   autofill::AutofillManager* GetAutofillManagerForMainFrame() override;
   const GURL& GetMainFrameURL() const override;
   bool IsUpdatePasswordUIEnabled() const override;
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 5ed3968..25aa9bc 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -2561,7 +2561,8 @@
   // auth dialog, also create a mock observer, for a different realm.
   MockLoginModelObserver mock_login_model_observer;
   PasswordManager* password_manager =
-      ChromePasswordManagerClient::FromWebContents(WebContents())
+      static_cast<password_manager::PasswordManagerClient*>(
+          ChromePasswordManagerClient::FromWebContents(WebContents()))
           ->GetPasswordManager();
   autofill::PasswordForm other_form(creds);
   other_form.signon_realm = "https://example.com/other realm";
diff --git a/chrome/browser/password_manager/password_store_mac.cc b/chrome/browser/password_manager/password_store_mac.cc
index 1ad1dd6..b31cd51 100644
--- a/chrome/browser/password_manager/password_store_mac.cc
+++ b/chrome/browser/password_manager/password_store_mac.cc
@@ -1167,6 +1167,14 @@
   return changes;
 }
 
+bool PasswordStoreMac::RemoveStatisticsCreatedBetweenImpl(
+    base::Time delete_begin,
+    base::Time delete_end) {
+  return login_metadata_db_ &&
+         login_metadata_db_->stats_table().RemoveStatsBetween(delete_begin,
+                                                              delete_end);
+}
+
 ScopedVector<autofill::PasswordForm> PasswordStoreMac::FillMatchingLogins(
     const autofill::PasswordForm& form,
     AuthorizationPromptPolicy prompt_policy) {
diff --git a/chrome/browser/password_manager/password_store_mac.h b/chrome/browser/password_manager/password_store_mac.h
index 1d2f4bf..801b385 100644
--- a/chrome/browser/password_manager/password_store_mac.h
+++ b/chrome/browser/password_manager/password_store_mac.h
@@ -83,6 +83,8 @@
   password_manager::PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
       base::Time delete_begin,
       base::Time delete_end) override;
+  bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
+                                          base::Time delete_end) override;
   ScopedVector<autofill::PasswordForm> FillMatchingLogins(
       const autofill::PasswordForm& form,
       AuthorizationPromptPolicy prompt_policy) override;
diff --git a/chrome/browser/password_manager/password_store_proxy_mac.cc b/chrome/browser/password_manager/password_store_proxy_mac.cc
index ad34546..ecbf1a6 100644
--- a/chrome/browser/password_manager/password_store_proxy_mac.cc
+++ b/chrome/browser/password_manager/password_store_proxy_mac.cc
@@ -178,6 +178,13 @@
   return GetBackend()->RemoveLoginsSyncedBetweenImpl(delete_begin, delete_end);
 }
 
+bool PasswordStoreProxyMac::RemoveStatisticsCreatedBetweenImpl(
+    base::Time delete_begin,
+    base::Time delete_end) {
+  return GetBackend()->RemoveStatisticsCreatedBetweenImpl(delete_begin,
+                                                          delete_end);
+}
+
 ScopedVector<autofill::PasswordForm> PasswordStoreProxyMac::FillMatchingLogins(
     const autofill::PasswordForm& form,
     AuthorizationPromptPolicy prompt_policy) {
diff --git a/chrome/browser/password_manager/password_store_proxy_mac.h b/chrome/browser/password_manager/password_store_proxy_mac.h
index 2556af5..15a0c36 100644
--- a/chrome/browser/password_manager/password_store_proxy_mac.h
+++ b/chrome/browser/password_manager/password_store_proxy_mac.h
@@ -80,6 +80,8 @@
   password_manager::PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
       base::Time delete_begin,
       base::Time delete_end) override;
+  bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
+                                          base::Time delete_end) override;
   ScopedVector<autofill::PasswordForm> FillMatchingLogins(
       const autofill::PasswordForm& form,
       AuthorizationPromptPolicy prompt_policy) override;
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
index df0f1b92..374a337 100644
--- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc
+++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -49,7 +49,7 @@
 // Different platforms have slightly different pixel output, due to different
 // graphics implementations. Slightly different pixels (in BGR space) are still
 // counted as a matching pixel by this simple manhattan distance threshold.
-const int kPixelManhattanDistanceTolerance = 8;
+const int kPixelManhattanDistanceTolerance = 20;
 
 std::string RunTestScript(base::StringPiece test_script,
                           content::WebContents* contents,
@@ -204,8 +204,11 @@
                                abs(pixel_g - ref_pixel_g) +
                                abs(pixel_r - ref_pixel_r);
 
-      if (manhattan_distance > kPixelManhattanDistanceTolerance)
+      if (manhattan_distance > kPixelManhattanDistanceTolerance) {
+        ADD_FAILURE() << "Pixel test failed on (" << x << ", " << y << "). " <<
+            "Pixel manhattan distance: " << manhattan_distance << ".";
         return false;
+      }
     }
   }
 
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 7e08669..32950be7 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -60,7 +60,6 @@
 #include "chrome/browser/ui/network_profile_bubble.h"
 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
-#include "chrome/browser/ui/startup/autolaunch_prompt.h"
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
 #include "chrome/browser/ui/webui/flags_ui.h"
 #include "chrome/browser/ui/webui/instant_ui.h"
@@ -227,14 +226,11 @@
 
 namespace {
 
-#if !defined(OS_ANDROID)
-// The AutomaticProfileResetter service used this preference to save that the
-// profile reset prompt had already been shown, however, the preference has been
-// renamed in Local State. We keep the name here for now so that we can clear
-// out legacy values.
-// TODO(engedy): Remove this and usages in M42 or later. See crbug.com/398813.
-const char kLegacyProfileResetPromptMemento[] = "profile.reset_prompt_memento";
-#endif
+#if defined(OS_WIN)
+// Deprecated 11/2015 (M48). TODO(gab): delete in M52+.
+const char kShownAutoLaunchInfobarDeprecated[] =
+    "browser.shown_autolaunch_infobar";
+#endif  // defined(OS_WIN)
 
 }  // namespace
 
@@ -357,12 +353,6 @@
 #if defined(TOOLKIT_VIEWS)
   RegisterBrowserViewLocalPrefs(registry);
 #endif
-
-  // Preferences registered only for migration (clearing or moving to a new key)
-  // go here.
-#if !defined(OS_ANDROID)
-  registry->RegisterDictionaryPref(kLegacyProfileResetPromptMemento);
-#endif  // !defined(OS_ANDROID)
 }
 
 // Register prefs applicable to all profiles.
@@ -481,7 +471,6 @@
   NewTabUI::RegisterProfilePrefs(registry);
   PepperFlashSettingsManager::RegisterProfilePrefs(registry);
   PinnedTabCodec::RegisterProfilePrefs(registry);
-  RegisterAutolaunchUserPrefs(registry);
   signin::RegisterProfilePrefs(registry);
 #endif
 
@@ -521,6 +510,13 @@
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
   browser_sync::ForeignSessionHandler::RegisterProfilePrefs(registry);
 #endif
+
+  // Preferences registered only for migration (clearing or moving to a new key)
+  // go here.
+
+#if defined(OS_WIN)
+  registry->RegisterIntegerPref(kShownAutoLaunchInfobarDeprecated, 0);
+#endif  // defined(OS_WIN)
 }
 
 void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -549,11 +545,6 @@
   // Added 05/2014.
   MigrateBrowserTabStripPrefs(local_state);
 #endif
-
-#if !defined(OS_ANDROID)
-  // Added 08/2014.
-  local_state->ClearPref(kLegacyProfileResetPromptMemento);
-#endif
 }
 
 // This method should be periodically pruned of year+ old migrations.
@@ -568,6 +559,11 @@
   // Added 02/2015.
   MigrateGoogleNowPrefs(profile);
 #endif
+
+#if defined(OS_WIN)
+  // Added 11/2015.
+  profile_prefs->ClearPref(kShownAutoLaunchInfobarDeprecated);
+#endif
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/resources/help/help_content.html b/chrome/browser/resources/help/help_content.html
index 158c755..0e032aa 100644
--- a/chrome/browser/resources/help/help_content.html
+++ b/chrome/browser/resources/help/help_content.html
@@ -30,7 +30,7 @@
       <div id="update-status-message-container">
         <div id="update-status-message" i18n-content="updateCheckStarted">
         </div>
-<if expr="is_macosx">
+<if expr="is_macosx or is_win">
         <div id="update-obsolete-system-container" hidden>
           <span id="update-obsolete-system"
               i18n-content="updateObsoleteSystem"></span>
diff --git a/chrome/browser/resources/help/help_page.js b/chrome/browser/resources/help/help_page.js
index 79f3edd..139f966 100644
--- a/chrome/browser/resources/help/help_page.js
+++ b/chrome/browser/resources/help/help_page.js
@@ -427,7 +427,7 @@
      * @private
      */
     setObsoleteSystem_: function(obsolete) {
-      if (cr.isMac && $('update-obsolete-system-container')) {
+      if ($('update-obsolete-system-container')) {
         $('update-obsolete-system-container').hidden = !obsolete;
       }
     },
@@ -438,8 +438,7 @@
      * @private
      */
     setObsoleteSystemEndOfTheLine_: function(endOfTheLine) {
-      if (cr.isMac &&
-          $('update-obsolete-system-container') &&
+      if ($('update-obsolete-system-container') &&
           !$('update-obsolete-system-container').hidden &&
           $('update-status-message')) {
         $('update-status-message').hidden = endOfTheLine;
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 6b2577d8..3dd0fdd 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -278,12 +278,6 @@
       </button>
       <div id="default-browser-state" i18n-content="defaultBrowserUnknown">
       </div>
-      <div id="auto-launch-option" class="checkbox" hidden>
-        <label id="auto-launch-label">
-          <input id="auto-launch" type="checkbox">
-          <span i18n-content="autoLaunchText"></span>
-        </label>
-      </div>
     </div>
   </section>
 </if>  <!-- not chromeos -->
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 929c425..6df0cff 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -436,8 +436,6 @@
         $('set-as-default-browser').onclick = function(event) {
           chrome.send('becomeDefaultBrowser');
         };
-
-        $('auto-launch').onclick = this.handleAutoLaunchChanged_;
       }
 
       // Privacy section.
@@ -1326,16 +1324,6 @@
       return url.replace(/^http:\/\//, '');
     },
 
-   /**
-    * Shows the autoLaunch preference and initializes its checkbox value.
-    * @param {boolean} enabled Whether autolaunch is enabled or or not.
-    * @private
-    */
-    updateAutoLaunchState_: function(enabled) {
-      $('auto-launch-option').hidden = false;
-      $('auto-launch').checked = enabled;
-    },
-
     /**
      * Called when the value of the download.default_directory preference
      * changes.
@@ -1427,14 +1415,6 @@
       }
     },
 
-   /**
-     * Sets or clear whether Chrome should Auto-launch on computer startup.
-     * @private
-     */
-    handleAutoLaunchChanged_: function() {
-      chrome.send('toggleAutoLaunch', [$('auto-launch').checked]);
-    },
-
     /**
      * Get the selected profile item from the profile list. This also works
      * correctly if the list is not displayed.
diff --git a/chrome/browser/resources/settings/date_time_page/demo.html b/chrome/browser/resources/settings/date_time_page/demo.html
deleted file mode 100644
index e9129b3..0000000
--- a/chrome/browser/resources/settings/date_time_page/demo.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!doctype html>
-<html>
-<head>
-  <link href="date_time_page.html" rel="import">
-  <link href="../prefs/prefs.html" rel="import">
-  <script src="demo.js"></script>
-</head>
-<body unresolved>
-  <settings-prefs></settings-prefs>
-  <settings-date-time-page></settings-date-time-page>
-</body>
-</html>
diff --git a/chrome/browser/resources/settings/date_time_page/demo.js b/chrome/browser/resources/settings/date_time_page/demo.js
deleted file mode 100644
index b95aa39..0000000
--- a/chrome/browser/resources/settings/date_time_page/demo.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Wire up the prefs to the date/time page.
-window.addEventListener('polymer-ready', function() {
-  var page = document.querySelector('settings-date-time-page');
-  page.prefs = document.querySelector('settings-prefs');
-});
diff --git a/chrome/browser/signin/signin_error_notifier_ash.cc b/chrome/browser/signin/signin_error_notifier_ash.cc
index 60e5f49..ef86440 100644
--- a/chrome/browser/signin/signin_error_notifier_ash.cc
+++ b/chrome/browser/signin/signin_error_notifier_ash.cc
@@ -26,6 +26,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -174,7 +175,8 @@
       kProfileSigninNotificationId);
 
   // Set |profile_id| for multi-user notification blocker.
-  notifier_id.profile_id = multi_user_util::GetUserIDFromProfile(profile_);
+  notifier_id.profile_id =
+      multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail();
 
   Notification notification(
       message_center::NOTIFICATION_TYPE_SIMPLE,
diff --git a/chrome/browser/sync/sync_error_notifier_ash.cc b/chrome/browser/sync/sync_error_notifier_ash.cc
index 4205138..128a33a 100644
--- a/chrome/browser/sync/sync_error_notifier_ash.cc
+++ b/chrome/browser/sync/sync_error_notifier_ash.cc
@@ -20,6 +20,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "grit/theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -165,7 +166,8 @@
       kProfileSyncNotificationId);
 
   // Set |profile_id| for multi-user notification blocker.
-  notifier_id.profile_id = multi_user_util::GetUserIDFromProfile(profile_);
+  notifier_id.profile_id =
+      multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail();
 
   // Add a new notification.
   Notification notification(
diff --git a/chrome/browser/ui/app_list/search/app_search_provider.cc b/chrome/browser/ui/app_list/search/app_search_provider.cc
index c190f76..9fd5c76 100644
--- a/chrome/browser/ui/app_list/search/app_search_provider.cc
+++ b/chrome/browser/ui/app_list/search/app_search_provider.cc
@@ -186,11 +186,10 @@
     const extensions::Extension* extension,
     extensions::UninstallReason reason) {
   RefreshApps();
-  if (!update_results_factory_.HasWeakPtrs()) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::Bind(&AppSearchProvider::UpdateResults,
-                              update_results_factory_.GetWeakPtr()));
-  }
+
+  // This should not be batched as the UI needs to immediately be informed of
+  // deleted extensions to prevent use-after-frees.
+  UpdateResults();
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/ash/chrome_shell_content_state_chromeos.cc b/chrome/browser/ui/ash/chrome_shell_content_state_chromeos.cc
index feae1a6..0a220d3 100644
--- a/chrome/browser/ui/ash/chrome_shell_content_state_chromeos.cc
+++ b/chrome/browser/ui/ash/chrome_shell_content_state_chromeos.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_context.h"
 
@@ -25,18 +26,20 @@
 
 content::BrowserContext* ChromeShellContentState::GetBrowserContextForWindow(
     aura::Window* window) {
-  const std::string& user_id =
+  const AccountId& account_id =
       chrome::MultiUserWindowManager::GetInstance()->GetWindowOwner(window);
-  return user_id.empty() ? nullptr
-                         : multi_user_util::GetProfileFromUserID(user_id);
+  return account_id.is_valid()
+             ? multi_user_util::GetProfileFromAccountId(account_id)
+             : nullptr;
 }
 
 content::BrowserContext*
 ChromeShellContentState::GetUserPresentingBrowserContextForWindow(
     aura::Window* window) {
-  const std::string& user_id =
+  const AccountId& account_id =
       chrome::MultiUserWindowManager::GetInstance()->GetUserPresentingWindow(
           window);
-  return user_id.empty() ? nullptr
-                         : multi_user_util::GetProfileFromUserID(user_id);
+  return account_id.is_valid()
+             ? multi_user_util::GetProfileFromAccountId(account_id)
+             : nullptr;
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 1853c5b..edc4e597 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -68,6 +68,7 @@
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/favicon/content/content_favicon_driver.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
@@ -310,8 +311,8 @@
 
 void ChromeLauncherControllerUserSwitchObserver::UserAddedToSession(
     const user_manager::User* active_user) {
-  Profile* profile = multi_user_util::GetProfileFromUserID(
-      active_user->email());
+  Profile* profile =
+      multi_user_util::GetProfileFromAccountId(active_user->GetAccountId());
   // If we do not have a profile yet, we postpone forwarding the notification
   // until it is loaded.
   if (!profile)
@@ -324,7 +325,8 @@
     Profile* profile) {
   if (!added_user_ids_waiting_for_profiles_.empty()) {
     // Check if the profile is from a user which was on the waiting list.
-    std::string user_id = multi_user_util::GetUserIDFromProfile(profile);
+    std::string user_id =
+        multi_user_util::GetAccountIdFromProfile(profile).GetUserEmail();
     std::set<std::string>::iterator it = std::find(
         added_user_ids_waiting_for_profiles_.begin(),
         added_user_ids_waiting_for_profiles_.end(),
@@ -1056,14 +1058,14 @@
   if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
           chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
     aura::Window* native_window = window->GetNativeWindow();
-    const std::string& current_user =
-        multi_user_util::GetUserIDFromProfile(profile());
+    const AccountId& current_account_id =
+        multi_user_util::GetAccountIdFromProfile(profile());
     chrome::MultiUserWindowManager* manager =
         chrome::MultiUserWindowManager::GetInstance();
-    if (!manager->IsWindowOnDesktopOfUser(native_window, current_user)) {
+    if (!manager->IsWindowOnDesktopOfUser(native_window, current_account_id)) {
       ash::MultiProfileUMA::RecordTeleportAction(
           ash::MultiProfileUMA::TELEPORT_WINDOW_RETURN_BY_LAUNCHER);
-      manager->ShowWindowForUser(native_window, current_user);
+      manager->ShowWindowForUser(native_window, current_account_id);
       window->Activate();
       return ash::ShelfItemDelegate::kExistingWindowActivated;
     }
@@ -1406,8 +1408,9 @@
     if (type == ash::TYPE_WINDOWED_APP || type == ash::TYPE_PLATFORM_APP)
       list.push_back(GetAppIDForShelfID(model_->items()[i].id));
   }
-  last_used_running_application_order_[
-      multi_user_util::GetUserIDFromProfile(profile_)] = list;
+  const std::string user_email =
+      multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail();
+  last_used_running_application_order_[user_email] = list;
 }
 
 void ChromeLauncherController::RestoreUnpinnedRunningApplicationOrder(
@@ -1465,7 +1468,8 @@
 bool ChromeLauncherController::ShelfBoundsChangesProbablyWithUser(
     aura::Window* root_window,
     const std::string& user_id) const {
-  Profile* other_profile = multi_user_util::GetProfileFromUserID(user_id);
+  Profile* other_profile = multi_user_util::GetProfileFromAccountId(
+      AccountId::FromUserEmail(user_id));
   DCHECK_NE(other_profile, profile_);
 
   // Note: The Auto hide state from preferences is not the same as the actual
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
index 6d3d08c..7376625 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_unittest.cc
@@ -38,6 +38,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/syncable_prefs/testing_pref_service_syncable.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/extension.h"
@@ -63,7 +64,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
-#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/fake_user_manager.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/test_utils.h"
@@ -611,8 +611,9 @@
   }
 
   // Restore the order of running but unpinned applications for a given user.
-  void RestoreUnpinnedRunningApplicationOrder(const std::string& user_id) {
-    launcher_controller_->RestoreUnpinnedRunningApplicationOrder(user_id);
+  void RestoreUnpinnedRunningApplicationOrder(const AccountId& account_id) {
+    launcher_controller_->RestoreUnpinnedRunningApplicationOrder(
+        account_id.GetUserEmail());
   }
 
   // Needed for extension service & friends to work.
@@ -813,9 +814,9 @@
     const AccountId account_id(AccountId::FromUserEmail(email_string));
     static_cast<ash::test::TestSessionStateDelegate*>(
         ash::Shell::GetInstance()->session_state_delegate())
-        ->AddUser(account_id.GetUserEmail());
+        ->AddUser(account_id);
     // Add a user to the fake user manager.
-    session_delegate()->AddUser(account_id.GetUserEmail());
+    session_delegate()->AddUser(account_id);
     GetFakeUserManager()->AddUser(account_id);
 
     GetFakeUserManager()->LoginUser(account_id);
@@ -834,16 +835,15 @@
   }
 
   // Switch to another user.
-  void SwitchActiveUser(const std::string& name) {
-    const AccountId account_id(AccountId::FromUserEmail(name));
-    session_delegate()->SwitchActiveUser(account_id.GetUserEmail());
+  void SwitchActiveUser(const AccountId& account_id) {
+    session_delegate()->SwitchActiveUser(account_id);
     GetFakeUserManager()->SwitchActiveUser(account_id);
     chrome::MultiUserWindowManagerChromeOS* manager =
         static_cast<chrome::MultiUserWindowManagerChromeOS*>(
             chrome::MultiUserWindowManager::GetInstance());
     manager->SetAnimationSpeedForTest(
         chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
-    manager->ActiveUserChanged(account_id.GetUserEmail());
+    manager->ActiveUserChanged(account_id);
     launcher_controller_->browser_status_monitor_for_test()->ActiveUserChanged(
         account_id.GetUserEmail());
     launcher_controller_->app_window_controller_for_test()->ActiveUserChanged(
@@ -1283,19 +1283,21 @@
   EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
 
   // Remember the current order of applications for the current user.
-  const std::string& current_user_id =
-      multi_user_util::GetUserIDFromProfile(profile());
+  const AccountId& current_account_id =
+      multi_user_util::GetAccountIdFromProfile(profile());
   RememberUnpinnedRunningApplicationOrder();
 
   // Switch some items and check that restoring a user which was not yet
   // remembered changes nothing.
   model_->Move(2, 3);
   EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
-  RestoreUnpinnedRunningApplicationOrder("second-fake-user@fake.com");
+  const AccountId second_fake_account_id(
+      AccountId::FromUserEmail("second-fake-user@fake.com"));
+  RestoreUnpinnedRunningApplicationOrder(second_fake_account_id);
   EXPECT_EQ("AppList, Chrome, app2, app1, app3", GetPinnedAppStatus());
 
   // Restoring the stored user should however do the right thing.
-  RestoreUnpinnedRunningApplicationOrder(current_user_id);
+  RestoreUnpinnedRunningApplicationOrder(current_account_id);
   EXPECT_EQ("AppList, Chrome, app1, app2, app3", GetPinnedAppStatus());
 
   // Switch again some items and even delete one - making sure that the missing
@@ -1303,15 +1305,15 @@
   model_->Move(3, 4);
   launcher_controller_->UnlockV1AppWithID(extension1_->id());
   EXPECT_EQ("AppList, Chrome, app3, app2", GetPinnedAppStatus());
-  RestoreUnpinnedRunningApplicationOrder(current_user_id);
+  RestoreUnpinnedRunningApplicationOrder(current_account_id);
   EXPECT_EQ("AppList, Chrome, app2, app3", GetPinnedAppStatus());
 
   // Check that removing more items does not crash and changes nothing.
   launcher_controller_->UnlockV1AppWithID(extension2_->id());
-  RestoreUnpinnedRunningApplicationOrder(current_user_id);
+  RestoreUnpinnedRunningApplicationOrder(current_account_id);
   EXPECT_EQ("AppList, Chrome, app3", GetPinnedAppStatus());
   launcher_controller_->UnlockV1AppWithID(extension3_->id());
-  RestoreUnpinnedRunningApplicationOrder(current_user_id);
+  RestoreUnpinnedRunningApplicationOrder(current_account_id);
   EXPECT_EQ("AppList, Chrome", GetPinnedAppStatus());
 }
 
@@ -1331,11 +1333,15 @@
     // After switching to a second user the item should be gone.
     std::string user2 = "user2";
     TestingProfile* profile2 = CreateMultiUserProfile(user2);
-    SwitchActiveUser(profile2->GetProfileUserName());
+    const AccountId account_id2(
+        multi_user_util::GetAccountIdFromProfile(profile2));
+    const AccountId account_id(
+        multi_user_util::GetAccountIdFromProfile(profile()));
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
 
     // After switching back the item should be back.
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(3, model_->item_count());
     // Note we destroy now the gmail app with the closure end.
   }
@@ -1351,6 +1357,10 @@
   // First test: Create an app when the user is not active.
   std::string user2 = "user2";
   TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
   {
     // Create a "windowed gmail app".
     scoped_ptr<V1App> v1_app(CreateRunningV1App(
@@ -1358,19 +1368,19 @@
     EXPECT_EQ(2, model_->item_count());
 
     // However - switching to the user should show it.
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(3, model_->item_count());
 
     // Second test: Remove the app when the user is not active and see that it
     // works.
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(2, model_->item_count());
     // Note: the closure ends and the browser will go away.
   }
   EXPECT_EQ(2, model_->item_count());
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_EQ(2, model_->item_count());
-  SwitchActiveUser(profile()->GetProfileUserName());
+  SwitchActiveUser(account_id);
   EXPECT_EQ(2, model_->item_count());
 }
 
@@ -1386,6 +1396,10 @@
   // First create an app when the user is active.
   std::string user2 = "user2";
   TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
   {
     // Create a "windowed gmail app".
     scoped_ptr<V1App> v1_app(CreateRunningV1App(
@@ -1396,13 +1410,13 @@
 
     // Transfer the app to the other screen and switch users.
     manager->ShowWindowForUser(v1_app->browser()->window()->GetNativeWindow(),
-                               user2);
+                               account_id2);
     EXPECT_EQ(3, model_->item_count());
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
   }
   // After the app was destroyed, switch back. (which caused already a crash).
-  SwitchActiveUser(profile()->GetProfileUserName());
+  SwitchActiveUser(account_id);
 
   // Create the same app again - which was also causing the crash.
   EXPECT_EQ(2, model_->item_count());
@@ -1414,7 +1428,7 @@
         kGmailLaunchURL));
     EXPECT_EQ(3, model_->item_count());
   }
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_EQ(2, model_->item_count());
 }
 
@@ -1429,7 +1443,11 @@
   // First test: Create an app when the user is not active.
   std::string user2 = "user2";
   TestingProfile* profile2 = CreateMultiUserProfile(user2);
-  SwitchActiveUser(profile2->GetProfileUserName());
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
+  SwitchActiveUser(account_id2);
   {
     // Create a "windowed gmail app".
     scoped_ptr<V1App> v1_app(CreateRunningV1App(
@@ -1437,19 +1455,19 @@
     EXPECT_EQ(2, model_->item_count());
 
     // However - switching to the user should show it.
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(3, model_->item_count());
 
     // Second test: Remove the app when the user is not active and see that it
     // works.
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
     v1_app.reset();
   }
   EXPECT_EQ(2, model_->item_count());
-  SwitchActiveUser(profile()->GetProfileUserName());
+  SwitchActiveUser(account_id);
   EXPECT_EQ(2, model_->item_count());
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_EQ(2, model_->item_count());
 }
 
@@ -1467,8 +1485,8 @@
   // No need to add the profiles to the MultiUserWindowManager here.
   // CreateMultiUserProfile() already does that.
   TestingProfile* profile2 = CreateMultiUserProfile("user2");
-  const std::string& current_user =
-      multi_user_util::GetUserIDFromProfile(profile());
+  const AccountId current_user =
+      multi_user_util::GetAccountIdFromProfile(profile());
 
   // Create a browser window with a native window for the current user.
   Browser::CreateParams params(profile(), chrome::HOST_DESKTOP_TYPE_ASH);
@@ -1485,8 +1503,8 @@
 
   // Transfer the window to another user's desktop and check that activating it
   // does pull it back to that user.
-  manager->ShowWindowForUser(window,
-                             multi_user_util::GetUserIDFromProfile(profile2));
+  manager->ShowWindowForUser(
+      window, multi_user_util::GetAccountIdFromProfile(profile2));
   EXPECT_FALSE(manager->IsWindowOnDesktopOfUser(window, current_user));
   launcher_controller_->ActivateWindowOrMinimizeIfActive(browser_window, false);
   EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(window, current_user));
@@ -2002,6 +2020,8 @@
   // users running browser list.
   std::string user2 = "user2";
   TestingProfile* profile2 = CreateMultiUserProfile(user2);
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
   scoped_ptr<Browser> browser2(
       CreateBrowserAndTabWithProfile(profile2, user2, "http://test2"));
   base::string16 one_menu_item2[] = { ASCIIToUTF16(user2) };
@@ -2010,14 +2030,13 @@
 
   // Switch to the other user and make sure that only that browser window gets
   // shown.
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
 
   // Transferred browsers of other users should not show up in the list.
   chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
-      browser()->window()->GetNativeWindow(),
-      user2);
+      browser()->window()->GetNativeWindow(), account_id2);
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_browser, 1, one_menu_item2, true));
 
@@ -2141,7 +2160,9 @@
   // Create a second profile and switch to that user.
   std::string user2 = "user2";
   TestingProfile* profile2 = CreateMultiUserProfile(user2);
-  SwitchActiveUser(profile2->GetProfileUserName());
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
+  SwitchActiveUser(account_id2);
 
   // No item should have content yet.
   EXPECT_TRUE(CheckMenuCreation(
@@ -2151,8 +2172,7 @@
 
   // Transfer the browser of the first user - it should still not show up.
   chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
-      browser()->window()->GetNativeWindow(),
-      user2);
+      browser()->window()->GetNativeWindow(), account_id2);
 
   EXPECT_TRUE(CheckMenuCreation(
       launcher_controller_.get(), item_browser, 0, NULL, true));
@@ -2167,6 +2187,10 @@
   InitLauncherController();
   // Create a profile for our second user (will be destroyed by the framework).
   TestingProfile* profile2 = CreateMultiUserProfile("user2");
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
   // Check that there is a browser and a app launcher.
   EXPECT_EQ(2, model_->item_count());
 
@@ -2175,11 +2199,11 @@
   EXPECT_EQ(3, model_->item_count());
 
   // After switching users the item should go away.
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_EQ(2, model_->item_count());
 
   // And it should come back when switching back.
-  SwitchActiveUser(profile()->GetProfileUserName());
+  SwitchActiveUser(account_id);
   EXPECT_EQ(3, model_->item_count());
 }
 
@@ -2191,11 +2215,15 @@
   InitLauncherController();
   // Create a profile for our second user (will be destroyed by the framework).
   TestingProfile* profile2 = CreateMultiUserProfile("user2");
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
   // Check that there is a browser and a app launcher.
   EXPECT_EQ(2, model_->item_count());
 
   // Switch to an inactive user.
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_EQ(2, model_->item_count());
 
   // Add the v2 app to the inactive user and check that no item was added to
@@ -2205,12 +2233,12 @@
     EXPECT_EQ(2, model_->item_count());
 
     // Switch to the primary user and check that the item is shown.
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(3, model_->item_count());
 
     // Switch to the second user and check that the item goes away - even if the
     // item gets closed.
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
   }
 
@@ -2219,7 +2247,7 @@
 
   // Switching then back to the default user should not show the additional item
   // anymore.
-  SwitchActiveUser(profile()->GetProfileUserName());
+  SwitchActiveUser(account_id);
   EXPECT_EQ(2, model_->item_count());
 }
 
@@ -2235,13 +2263,19 @@
   TestingProfile* profile1 = CreateMultiUserProfile("user-1");
   TestingProfile* profile2 = CreateMultiUserProfile("user-2");
   TestingProfile* profile3 = CreateMultiUserProfile("user-3");
-  SwitchActiveUser(profile1->GetProfileUserName());
+  const AccountId account_id1(
+      multi_user_util::GetAccountIdFromProfile(profile1));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
+  const AccountId account_id3(
+      multi_user_util::GetAccountIdFromProfile(profile3));
+  SwitchActiveUser(account_id1);
 
   // A v2 app for user #1 should be shown first and get hidden when switching to
   // desktop #2.
   V2App v2_app_1(profile1, extension1_.get());
   EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
 
   // Add a v2 app for user #1 while on desktop #2 should not be shown.
@@ -2250,8 +2284,7 @@
   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
 
   // Teleport the app from user #1 to the desktop #2 should show it.
-  manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(),
-                             profile2->GetProfileUserName());
+  manager->ShowWindowForUser(v2_app_1.window()->GetNativeWindow(), account_id2);
   EXPECT_TRUE(v2_app_1.window()->GetNativeWindow()->IsVisible());
   EXPECT_FALSE(v2_app_2.window()->GetNativeWindow()->IsVisible());
 
@@ -2264,7 +2297,7 @@
 
   // Switching back to desktop#1 and creating an app for user #1 should move
   // the app on desktop #1.
-  SwitchActiveUser(profile1->GetProfileUserName());
+  SwitchActiveUser(account_id1);
   V2App v2_app_4(profile1, extension1_.get());
   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
   EXPECT_TRUE(v2_app_2.window()->GetNativeWindow()->IsVisible());
@@ -2273,15 +2306,15 @@
 
   // Switching to desktop #3 and create an app for user #1 there should land on
   // his own desktop (#1).
-  SwitchActiveUser(profile3->GetProfileUserName());
+  SwitchActiveUser(account_id3);
   V2App v2_app_5(profile1, extension1_.get());
   EXPECT_FALSE(v2_app_5.window()->GetNativeWindow()->IsVisible());
-  SwitchActiveUser(profile1->GetProfileUserName());
+  SwitchActiveUser(account_id1);
   EXPECT_TRUE(v2_app_5.window()->GetNativeWindow()->IsVisible());
 
   // Switching to desktop #2, hiding the app window and creating an app should
   // teleport there automatically.
-  SwitchActiveUser(profile2->GetProfileUserName());
+  SwitchActiveUser(account_id2);
   v2_app_1.window()->Hide();
   V2App v2_app_6(profile1, extension1_.get());
   EXPECT_FALSE(v2_app_1.window()->GetNativeWindow()->IsVisible());
@@ -2296,7 +2329,11 @@
   InitLauncherController();
 
   TestingProfile* profile2 = CreateMultiUserProfile("user-2");
-  SwitchActiveUser(profile()->GetProfileUserName());
+  const AccountId account_id(
+      multi_user_util::GetAccountIdFromProfile(profile()));
+  const AccountId account_id2(
+      multi_user_util::GetAccountIdFromProfile(profile2));
+  SwitchActiveUser(account_id);
   EXPECT_EQ(2, model_->item_count());
 
   V2App v2_app_1(profile(), extension1_.get());
@@ -2311,7 +2348,7 @@
   }
   {
     // Switch user, hide and show the app and switch back.
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
 
     v2_app_1.window()->Hide();
@@ -2320,18 +2357,18 @@
     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
     EXPECT_EQ(2, model_->item_count());
 
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(3, model_->item_count());
   }
   {
     // Switch user, hide the app, switch back and then show it again.
-    SwitchActiveUser(profile2->GetProfileUserName());
+    SwitchActiveUser(account_id2);
     EXPECT_EQ(2, model_->item_count());
 
     v2_app_1.window()->Hide();
     EXPECT_EQ(2, model_->item_count());
 
-    SwitchActiveUser(profile()->GetProfileUserName());
+    SwitchActiveUser(account_id);
     EXPECT_EQ(2, model_->item_count());
 
     v2_app_1.window()->Show(extensions::AppWindow::SHOW_ACTIVE);
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
index 00e8c73..c36f1a2b 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_app_window_launcher_controller.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "extensions/browser/app_window/app_window.h"
 #include "extensions/browser/app_window/native_app_window.h"
 #include "ui/aura/window.h"
@@ -86,7 +87,7 @@
   if (!multi_user_util::IsProfileFromActiveUser(profile) &&
       UserHasAppOnActiveDesktop(app_window)) {
     chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
-        app_window->GetNativeWindow(), multi_user_util::GetCurrentUserId());
+        app_window->GetNativeWindow(), multi_user_util::GetCurrentAccountId());
   }
 }
 
@@ -147,7 +148,7 @@
   const std::string& app_id = app_window->extension_id();
   content::BrowserContext* app_context = app_window->browser_context();
   DCHECK(!app_context->IsOffTheRecord());
-  const std::string& current_user = multi_user_util::GetCurrentUserId();
+  const AccountId current_account_id = multi_user_util::GetCurrentAccountId();
   chrome::MultiUserWindowManager* manager =
       chrome::MultiUserWindowManager::GetInstance();
   for (AppWindowList::iterator it = app_window_list_.begin();
@@ -156,7 +157,7 @@
     extensions::AppWindow* other_window = *it;
     DCHECK(!other_window->browser_context()->IsOffTheRecord());
     if (manager->IsWindowOnDesktopOfUser(other_window->GetNativeWindow(),
-                                         current_user) &&
+                                         current_account_id) &&
         app_id == other_window->extension_id() &&
         app_context == other_window->browser_context()) {
       return true;
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc
index 7d808f1..4cf0a184 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos.cc
@@ -76,8 +76,8 @@
     // If this window is not owned, we don't show the menu addition.
     chrome::MultiUserWindowManager* manager =
         chrome::MultiUserWindowManager::GetInstance();
-    const std::string user_id = manager->GetWindowOwner(window);
-    if (user_id.empty() || !window)
+    const AccountId& account_id = manager->GetWindowOwner(window);
+    if (!account_id.is_valid() || !window)
       return model.Pass();
     chromeos::MultiUserContextMenuChromeos* menu =
         new chromeos::MultiUserContextMenuChromeos(window);
@@ -105,8 +105,8 @@
   ash::MultiProfileUMA::RecordTeleportAction(
       ash::MultiProfileUMA::TELEPORT_WINDOW_CAPTION_MENU);
 
-  chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
-      window_, account_id.GetUserEmail());
+  chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(window_,
+                                                                   account_id);
 }
 
 void ExecuteVisitDesktopCommand(int command_id, aura::Window* window) {
@@ -131,9 +131,9 @@
       for (user_manager::UserList::const_iterator it = logged_in_users.begin();
            it != logged_in_users.end();
            ++it) {
-        if (multi_user_util::GetProfileFromUserID(
-            multi_user_util::GetUserIDFromEmail((*it)->email()))->GetPrefs()->
-            GetBoolean(prefs::kMultiProfileWarningShowDismissed)) {
+        if (multi_user_util::GetProfileFromAccountId((*it)->GetAccountId())
+                ->GetPrefs()
+                ->GetBoolean(prefs::kMultiProfileWarningShowDismissed)) {
           bool active_user_show_option =
               ProfileManager::GetActiveUserProfile()->
               GetPrefs()->GetBoolean(prefs::kMultiProfileWarningShowDismissed);
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
index ae0a23f..bd3fecc 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_context_menu_chromeos_unittest.cc
@@ -13,6 +13,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 #include "chrome/common/chrome_switches.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/base/ui_base_types.h"
 
@@ -59,7 +60,8 @@
   window_ = CreateTestWindowInShellWithId(0);
   window_->Show();
 
-  multi_user_window_manager_ = new chrome::MultiUserWindowManagerChromeOS("A");
+  multi_user_window_manager_ =
+      new chrome::MultiUserWindowManagerChromeOS(AccountId::FromUserEmail("A"));
   multi_user_window_manager_->Init();
   chrome::MultiUserWindowManager::SetInstanceForTest(multi_user_window_manager_,
         chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED);
@@ -86,7 +88,8 @@
 TEST_F(MultiUserContextMenuChromeOSTest, OwnedWindow) {
   // Make the window owned and check that there is no menu (since only a single
   // user exists).
-  multi_user_window_manager()->SetWindowOwner(window(), "A");
+  multi_user_window_manager()->SetWindowOwner(window(),
+                                              AccountId::FromUserEmail("A"));
   EXPECT_EQ(NULL, CreateMultiUserContextMenu(window()).get());
 
   // After adding another user a menu should get created.
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
index b515a90..c89b3ebd 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.cc
@@ -6,15 +6,15 @@
 
 #include "ash/system/system_notifier.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notifier_settings.h"
 
 MultiUserNotificationBlockerChromeOS::MultiUserNotificationBlockerChromeOS(
     message_center::MessageCenter* message_center,
-    const std::string& initial_user_id)
+    const AccountId& initial_account_id)
     : NotificationBlocker(message_center),
-      active_user_id_(initial_user_id) {
-}
+      active_account_id_(initial_account_id) {}
 
 MultiUserNotificationBlockerChromeOS::~MultiUserNotificationBlockerChromeOS() {
 }
@@ -27,7 +27,7 @@
   if (ash::system_notifier::IsAshSystemNotifier(notifier_id))
     return true;
 
-  return notifier_id.profile_id == active_user_id_;
+  return AccountId::FromUserEmail(notifier_id.profile_id) == active_account_id_;
 }
 
 bool MultiUserNotificationBlockerChromeOS::ShouldShowNotificationAsPopup(
@@ -36,14 +36,14 @@
 }
 
 void MultiUserNotificationBlockerChromeOS::ActiveUserChanged(
-    const std::string& user_id) {
-  if (active_user_id_ == user_id)
+    const AccountId& account_id) {
+  if (active_account_id_ == account_id)
     return;
 
-  quiet_modes_[active_user_id_] = message_center()->IsQuietMode();
-  active_user_id_ = user_id;
-  std::map<std::string, bool>::const_iterator iter =
-      quiet_modes_.find(active_user_id_);
+  quiet_modes_[active_account_id_] = message_center()->IsQuietMode();
+  active_account_id_ = account_id;
+  std::map<AccountId, bool>::const_iterator iter =
+      quiet_modes_.find(active_account_id_);
   if (iter != quiet_modes_.end() &&
       iter->second != message_center()->IsQuietMode()) {
     message_center()->SetQuietMode(iter->second);
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
index 3afc8eb..b39e537 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h
@@ -9,6 +9,7 @@
 #include <set>
 #include <string>
 
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/message_center/notification_blocker.h"
 
 // A notification blocker for per-profile stream switching. Owned and controlled
@@ -18,11 +19,11 @@
  public:
   MultiUserNotificationBlockerChromeOS(
       message_center::MessageCenter* message_center,
-      const std::string& initial_user_id);
+      const AccountId& initial_account_id);
   ~MultiUserNotificationBlockerChromeOS() override;
 
   // Called by MultiUserWindowManager when the active user has changed.
-  void ActiveUserChanged(const std::string& user_id);
+  void ActiveUserChanged(const AccountId& account_id);
 
   // message_center::NotificationBlocker overrides:
   bool ShouldShowNotification(
@@ -34,8 +35,8 @@
   // Returns true if this blocker is actively working.
   bool IsActive() const;
 
-  std::string active_user_id_;
-  std::map<std::string, bool> quiet_modes_;
+  AccountId active_account_id_;
+  std::map<AccountId, bool> quiet_modes_;
 
   DISALLOW_COPY_AND_ASSIGN(MultiUserNotificationBlockerChromeOS);
 };
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index f68e6fc..a5d807c 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/user_info.h"
 #include "ui/message_center/message_center.h"
@@ -48,7 +49,8 @@
     ash::test::TestSessionStateDelegate* session_state_delegate =
         static_cast<ash::test::TestSessionStateDelegate*>(
             ash::Shell::GetInstance()->session_state_delegate());
-    session_state_delegate->AddUser("test2@example.com");
+    session_state_delegate->AddUser(
+        AccountId::FromUserEmail("test2@example.com"));
 
     chromeos::WallpaperManager::Initialize();
 
@@ -95,12 +97,14 @@
   }
 
   void SwitchActiveUser(const std::string& name) {
-    ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(name);
+    const AccountId account_id(AccountId::FromUserEmail(name));
+    ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
+        account_id);
     if (chrome::MultiUserWindowManager::GetMultiProfileMode() ==
         chrome::MultiUserWindowManager::MULTI_PROFILE_MODE_SEPARATED) {
       static_cast<chrome::MultiUserWindowManagerChromeOS*>(
-          chrome::MultiUserWindowManager::GetInstance())->ActiveUserChanged(
-              name);
+          chrome::MultiUserWindowManager::GetInstance())
+          ->ActiveUserChanged(account_id);
     }
   }
 
@@ -128,7 +132,8 @@
 
   aura::Window* CreateWindowForProfile(const std::string& name) {
     aura::Window* window = CreateTestWindowInShellWithId(window_id_++);
-    chrome::MultiUserWindowManager::GetInstance()->SetWindowOwner(window, name);
+    chrome::MultiUserWindowManager::GetInstance()->SetWindowOwner(
+        window, AccountId::FromUserEmail(name));
     return window;
   }
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_util.cc b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
index 604749b..5194df2d 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_util.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_util.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 
 #if defined(OS_CHROMEOS)
@@ -19,18 +20,19 @@
 
 namespace multi_user_util {
 
-std::string GetUserIDFromProfile(Profile* profile) {
-  return GetUserIDFromEmail(
+AccountId GetAccountIdFromProfile(Profile* profile) {
+  return GetAccountIdFromEmail(
       profile->GetOriginalProfile()->GetProfileUserName());
 }
 
-std::string GetUserIDFromEmail(const std::string& email) {
+AccountId GetAccountIdFromEmail(const std::string& email) {
   // |email| and profile name could be empty if not yet logged in or guest mode.
-  return email.empty() ?
-      email : gaia::CanonicalizeEmail(gaia::SanitizeEmail(email));
+  return email.empty() ? EmptyAccountId()
+                       : AccountId::FromUserEmail(gaia::CanonicalizeEmail(
+                             gaia::SanitizeEmail(email)));
 }
 
-Profile* GetProfileFromUserID(const std::string& user_id) {
+Profile* GetProfileFromAccountId(const AccountId& account_id) {
   // Unit tests can end up here without a |g_browser_process|.
   if (!g_browser_process || !g_browser_process->profile_manager())
     return NULL;
@@ -40,7 +42,7 @@
 
   std::vector<Profile*>::const_iterator profile_iterator = profiles.begin();
   for (; profile_iterator != profiles.end(); ++profile_iterator) {
-    if (GetUserIDFromProfile(*profile_iterator) == user_id)
+    if (GetAccountIdFromProfile(*profile_iterator) == account_id)
       return *profile_iterator;
   }
   return NULL;
@@ -52,19 +54,18 @@
       chrome::MultiUserWindowManager::GetInstance();
   // We might come here before the manager got created - or in a unit test.
   if (!manager)
-    return NULL;
-  const std::string user_id = manager->GetUserPresentingWindow(window);
-  return user_id.empty() ? NULL :
-                           multi_user_util::GetProfileFromUserID(user_id);
+    return nullptr;
+  const AccountId account_id = manager->GetUserPresentingWindow(window);
+  return account_id.is_valid() ? GetProfileFromAccountId(account_id) : nullptr;
 #else
-  return NULL;
+  return nullptr;
 #endif
 }
 
 bool IsProfileFromActiveUser(Profile* profile) {
 #if defined(OS_CHROMEOS)
-  return GetUserIDFromProfile(profile) ==
-         user_manager::UserManager::Get()->GetActiveUser()->email();
+  return GetAccountIdFromProfile(profile) ==
+         user_manager::UserManager::Get()->GetActiveUser()->GetAccountId();
 #else
   // In non Chrome OS configurations this will be always true since this only
   // makes sense in separate desktop mode.
@@ -72,21 +73,24 @@
 #endif
 }
 
-const std::string& GetCurrentUserId() {
+const AccountId GetCurrentAccountId() {
 #if defined(OS_CHROMEOS)
-  return user_manager::UserManager::Get()->GetActiveUser()->email();
-#else
-  return base::EmptyString();
+  const user_manager::User* user =
+      user_manager::UserManager::Get()->GetActiveUser();
+  // In unit tests user login phase is usually skipped.
+  if (user)
+    return user->GetAccountId();
 #endif
+  return EmptyAccountId();
 }
 
 // Move the window to the current user's desktop.
 void MoveWindowToCurrentDesktop(aura::Window* window) {
 #if defined(OS_CHROMEOS)
   if (!chrome::MultiUserWindowManager::GetInstance()->IsWindowOnDesktopOfUser(
-          window, GetCurrentUserId())) {
+          window, GetCurrentAccountId())) {
     chrome::MultiUserWindowManager::GetInstance()->ShowWindowForUser(
-      window, GetCurrentUserId());
+        window, GetCurrentAccountId());
   }
 #endif
 }
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_util.h b/chrome/browser/ui/ash/multi_user/multi_user_util.h
index b85a4589a..476e68f 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_util.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_util.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+class AccountId;
 class Profile;
 
 namespace aura {
@@ -16,13 +17,13 @@
 namespace multi_user_util {
 
 // Get the user id from a given profile.
-std::string GetUserIDFromProfile(Profile* profile);
+AccountId GetAccountIdFromProfile(Profile* profile);
 
 // Get the user id from an email address.
-std::string GetUserIDFromEmail(const std::string& email);
+AccountId GetAccountIdFromEmail(const std::string& email);
 
 // Get a profile for a given user id.
-Profile* GetProfileFromUserID(const std::string& user_id);
+Profile* GetProfileFromAccountId(const AccountId& account_id);
 
 // Get a profile for a |window|. Returns NULL if window belongs to no profile.
 Profile* GetProfileFromWindow(aura::Window* window);
@@ -32,9 +33,9 @@
 // return false.
 bool IsProfileFromActiveUser(Profile* profile);
 
-// Gets the current user. Note that this will only return for ChromeOS a string.
-// All other operating systems will get an empty string.
-const std::string& GetCurrentUserId();
+// Gets the current user. Note that this will return a valid AccountId for
+// ChromeOS only. All other operating systems will get an empty AccountId.
+const AccountId GetCurrentAccountId();
 
 // Move the window to the current user's desktop.
 void MoveWindowToCurrentDesktop(aura::Window* window);
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
index 11da278..36d187e 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
@@ -47,8 +47,7 @@
         new MultiUserWindowManagerChromeOS(ash::Shell::GetInstance()
                                                ->session_state_delegate()
                                                ->GetUserInfo(0)
-                                               ->GetAccountId()
-                                               .GetUserEmail());
+                                               ->GetAccountId());
     g_instance = manager;
     manager->Init();
     multi_user_mode_ = MULTI_PROFILE_MODE_SEPARATED;
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
index 2496ea5..f48ee21 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.h
@@ -9,6 +9,7 @@
 #include <set>
 #include <string>
 
+class AccountId;
 class Browser;
 
 namespace content {
@@ -96,12 +97,12 @@
   // A user switch will automatically change the visibility - and - if the
   // current user is not the owner it will immediately hidden. If the window
   // had already be registered this function will run into a DCHECK violation.
-  virtual void SetWindowOwner(
-      aura::Window* window, const std::string& user_id) = 0;
+  virtual void SetWindowOwner(aura::Window* window,
+                              const AccountId& account_id) = 0;
 
-  // See who owns this window. The return value is the user id or an empty
-  // string if not assigned yet.
-  virtual const std::string& GetWindowOwner(aura::Window* window) const = 0;
+  // See who owns this window. The return value is the user account id or an
+  // empty AccountId if not assigned yet.
+  virtual const AccountId& GetWindowOwner(aura::Window* window) const = 0;
 
   // Allows to show an owned window for another users. If the window is not
   // owned, this call will return immediately. (The FileManager for example
@@ -109,24 +110,24 @@
   // Note that a window can only be shown on one desktop at a time. Note that
   // when the window gets minimized, it will automatically fall back to the
   // owner's desktop.
-  virtual void ShowWindowForUser(
-      aura::Window* window, const std::string& user_id) = 0;
+  virtual void ShowWindowForUser(aura::Window* window,
+                                 const AccountId& account_id) = 0;
 
   // Returns true when windows are shared among users.
   virtual bool AreWindowsSharedAmongUsers() const = 0;
 
-  // Get the owners for the visible windows and set them to |user_ids|.
+  // Get the owners for the visible windows and set them to |account_ids|.
   virtual void GetOwnersOfVisibleWindows(
-      std::set<std::string>* user_ids) const = 0;
+      std::set<AccountId>* account_ids) const = 0;
 
   // A query call for a given window to see if it is on the given user's
   // desktop.
   virtual bool IsWindowOnDesktopOfUser(aura::Window* window,
-                                       const std::string& user_id) const = 0;
+                                       const AccountId& account_id) const = 0;
 
   // Get the user on which the window is currently shown. If an empty string is
   // passed back the window will be presented for every user.
-  virtual const std::string& GetUserPresentingWindow(
+  virtual const AccountId& GetUserPresentingWindow(
       aura::Window* window) const = 0;
 
   // Adds user to monitor starting and running V1/V2 application windows.
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index 85837176..320288d 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -228,8 +228,8 @@
   void OnAppWindowAdded(extensions::AppWindow* app_window) override {
     aura::Window* window = app_window->GetNativeWindow();
     DCHECK(window);
-    MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(window,
-                                                                  user_id_);
+    MultiUserWindowManagerChromeOS::GetInstance()->SetWindowOwner(
+        window, AccountId::FromUserEmail(user_id_));
   }
 
  private:
@@ -245,13 +245,13 @@
 };
 
 MultiUserWindowManagerChromeOS::MultiUserWindowManagerChromeOS(
-    const std::string& current_user_id)
-    : current_user_id_(current_user_id),
+    const AccountId& current_account_id)
+    : current_account_id_(current_account_id),
       notification_blocker_(new MultiUserNotificationBlockerChromeOS(
-          message_center::MessageCenter::Get(), current_user_id)),
+          message_center::MessageCenter::Get(),
+          current_account_id)),
       suppress_visibility_changes_(false),
-      animation_speed_(ANIMATION_SPEED_NORMAL) {
-}
+      animation_speed_(ANIMATION_SPEED_NORMAL) {}
 
 MultiUserWindowManagerChromeOS::~MultiUserWindowManagerChromeOS() {
   // When the MultiUserWindowManager gets destroyed, ash::Shell is mostly gone.
@@ -268,14 +268,15 @@
   }
 
   // Remove all app observers.
-  UserIDToAppWindowObserver::iterator app_observer_iterator =
-      user_id_to_app_observer_.begin();
-  while (app_observer_iterator != user_id_to_app_observer_.end()) {
-    Profile* profile = multi_user_util::GetProfileFromUserID(
-        app_observer_iterator->first);
-    CHECK(profile) << "profile not found for:" << app_observer_iterator->first;
+  AccountIdToAppWindowObserver::iterator app_observer_iterator =
+      account_id_to_app_observer_.begin();
+  while (app_observer_iterator != account_id_to_app_observer_.end()) {
+    Profile* profile =
+        multi_user_util::GetProfileFromAccountId(app_observer_iterator->first);
+    CHECK(profile) << "profile not found for:"
+                   << app_observer_iterator->first.GetUserEmail();
     RemoveUser(app_observer_iterator->first, profile);
-    app_observer_iterator = user_id_to_app_observer_.begin();
+    app_observer_iterator = account_id_to_app_observer_.begin();
   }
 
   if (ash::Shell::HasInstance())
@@ -286,8 +287,8 @@
 void MultiUserWindowManagerChromeOS::Init() {
   // Since we are setting the SessionStateObserver and adding the user, this
   // function should get called only once.
-  DCHECK(user_id_to_app_observer_.find(current_user_id_) ==
-             user_id_to_app_observer_.end());
+  DCHECK(account_id_to_app_observer_.find(current_account_id_) ==
+         account_id_to_app_observer_.end());
 
   // Add a session state observer to be able to monitor session changes.
   if (ash::Shell::HasInstance()) {
@@ -301,21 +302,22 @@
                  content::NotificationService::AllSources());
 
   // Add an app window observer & all already running apps.
-  Profile* profile = multi_user_util::GetProfileFromUserID(current_user_id_);
+  Profile* profile =
+      multi_user_util::GetProfileFromAccountId(current_account_id_);
   if (profile)
     AddUser(profile);
 }
 
 void MultiUserWindowManagerChromeOS::SetWindowOwner(
     aura::Window* window,
-    const std::string& user_id) {
+    const AccountId& account_id) {
   // Make sure the window is valid and there was no owner yet.
   DCHECK(window);
-  DCHECK(!user_id.empty());
-  if (GetWindowOwner(window) == user_id)
+  DCHECK(account_id.is_valid());
+  if (GetWindowOwner(window) == account_id)
     return;
   DCHECK(GetWindowOwner(window).empty());
-  window_to_entry_[window] = new WindowEntry(user_id);
+  window_to_entry_[window] = new WindowEntry(account_id);
 
   // Remember the initial visibility of the window.
   window_to_entry_[window]->set_show(window->IsVisible());
@@ -327,7 +329,7 @@
   // Check if this window was created due to a user interaction. If it was,
   // transfer it to the current user.
   if (IsProcessingUserEvent())
-    window_to_entry_[window]->set_show_for_user(current_user_id_);
+    window_to_entry_[window]->set_show_for_user(current_account_id_);
 
   // Add all transient children to our set of windows. Note that the function
   // will add the children but not the owner to the transient children map.
@@ -336,31 +338,31 @@
   // Notify entry adding.
   FOR_EACH_OBSERVER(Observer, observers_, OnOwnerEntryAdded(window));
 
-  if (!IsWindowOnDesktopOfUser(window, current_user_id_))
+  if (!IsWindowOnDesktopOfUser(window, current_account_id_))
     SetWindowVisibility(window, false, 0);
 }
 
-const std::string& MultiUserWindowManagerChromeOS::GetWindowOwner(
+const AccountId& MultiUserWindowManagerChromeOS::GetWindowOwner(
     aura::Window* window) const {
   WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
-  return it != window_to_entry_.end() ? it->second->owner()
-                                      : base::EmptyString();
+  return it != window_to_entry_.end() ? it->second->owner() : EmptyAccountId();
 }
 
 void MultiUserWindowManagerChromeOS::ShowWindowForUser(
     aura::Window* window,
-    const std::string& user_id) {
-  std::string previous_owner(GetUserPresentingWindow(window));
-  if (!ShowWindowForUserIntern(window, user_id))
+    const AccountId& account_id) {
+  const AccountId previous_owner(GetUserPresentingWindow(window));
+  if (!ShowWindowForUserIntern(window, account_id))
     return;
   // The window switched to a new desktop and we have to switch to that desktop,
   // but only when it was on the visible desktop and the the target is not the
   // visible desktop.
-  if (user_id == current_user_id_ || previous_owner != current_user_id_)
+  if (account_id == current_account_id_ ||
+      previous_owner != current_account_id_)
     return;
 
   ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
-      user_id);
+      account_id);
 }
 
 bool MultiUserWindowManagerChromeOS::AreWindowsSharedAmongUsers() const {
@@ -373,50 +375,52 @@
 }
 
 void MultiUserWindowManagerChromeOS::GetOwnersOfVisibleWindows(
-    std::set<std::string>* user_ids) const {
+    std::set<AccountId>* account_ids) const {
   for (WindowToEntryMap::const_iterator it = window_to_entry_.begin();
        it != window_to_entry_.end();
        ++it) {
     if (it->first->IsVisible())
-      user_ids->insert(it->second->owner());
+      account_ids->insert(it->second->owner());
   }
 }
 
 bool MultiUserWindowManagerChromeOS::IsWindowOnDesktopOfUser(
     aura::Window* window,
-    const std::string& user_id) const {
-  const std::string& presenting_user = GetUserPresentingWindow(window);
-  return presenting_user.empty() || presenting_user == user_id;
+    const AccountId& account_id) const {
+  const AccountId& presenting_user = GetUserPresentingWindow(window);
+  return (!presenting_user.is_valid()) || presenting_user == account_id;
 }
 
-const std::string& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
+const AccountId& MultiUserWindowManagerChromeOS::GetUserPresentingWindow(
     aura::Window* window) const {
   WindowToEntryMap::const_iterator it = window_to_entry_.find(window);
   // If the window is not owned by anyone it is shown on all desktops and we
   // return the empty string.
   if (it == window_to_entry_.end())
-    return base::EmptyString();
+    return EmptyAccountId();
   // Otherwise we ask the object for its desktop.
   return it->second->show_for_user();
 }
 
 void MultiUserWindowManagerChromeOS::AddUser(content::BrowserContext* context) {
   Profile* profile = Profile::FromBrowserContext(context);
-  const std::string& user_id = multi_user_util::GetUserIDFromProfile(profile);
-  if (user_id_to_app_observer_.find(user_id) != user_id_to_app_observer_.end())
+  const AccountId& account_id(
+      multi_user_util::GetAccountIdFromProfile(profile));
+  if (account_id_to_app_observer_.find(account_id) !=
+      account_id_to_app_observer_.end())
     return;
 
   scoped_ptr<KeyedServiceShutdownNotifier::Subscription> notification =
       MultiUserWindowManagerCrOSShutdownNotifierFactory::GetInstance()
           ->Get(profile)
           ->Subscribe(base::Bind(&MultiUserWindowManagerChromeOS::RemoveUser,
-                                 base::Unretained(this), user_id,
+                                 base::Unretained(this), account_id,
                                  base::Unretained(profile)));
 
-  user_id_to_app_observer_[user_id] =
-      new AppObserver(user_id, notification.release());
+  account_id_to_app_observer_[account_id] =
+      new AppObserver(account_id.GetUserEmail(), notification.release());
   extensions::AppWindowRegistry::Get(profile)
-      ->AddObserver(user_id_to_app_observer_[user_id]);
+      ->AddObserver(account_id_to_app_observer_[account_id]);
 
   // Account all existing application windows of this user accordingly.
   const extensions::AppWindowRegistry::AppWindowList& app_windows =
@@ -424,7 +428,7 @@
   extensions::AppWindowRegistry::AppWindowList::const_iterator it =
       app_windows.begin();
   for (; it != app_windows.end(); ++it)
-    user_id_to_app_observer_[user_id]->OnAppWindowAdded(*it);
+    account_id_to_app_observer_[account_id]->OnAppWindowAdded(*it);
 
   // Account all existing browser windows of this user accordingly.
   BrowserList* browser_list = BrowserList::GetInstance(HOST_DESKTOP_TYPE_ASH);
@@ -434,7 +438,7 @@
       AddBrowserWindow(*browser_it);
   }
   // When adding another user to the session, we auto switch users.
-  if (user_id_to_app_observer_.size() == 1)
+  if (account_id_to_app_observer_.size() == 1)
     return;
 
   // Don't do anything special in case of user session restore after crash.
@@ -445,7 +449,7 @@
     // Immediately hide the windows of the current user.
     base::AutoReset<AnimationSpeed> animation_speed(&animation_speed_,
                                                     ANIMATION_SPEED_DISABLED);
-    ActiveUserChanged(user_id);
+    ActiveUserChanged(account_id);
   }
 }
 
@@ -458,18 +462,17 @@
 }
 
 void MultiUserWindowManagerChromeOS::ActiveUserChanged(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   // This needs to be set before the animation starts.
-  current_user_id_ = user_id;
+  current_account_id_ = account_id;
 
   // Here to avoid a very nasty race condition, we must destruct any previously
   // created animation before creating a new one. Otherwise, the newly
   // constructed will hide all windows of the old user in the first step of the
   // animation only to be reshown again by the destructor of the old animation.
   animation_.reset();
-  animation_.reset(
-      new UserSwitchAnimatorChromeOS(
-          this, user_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS)));
+  animation_.reset(new UserSwitchAnimatorChromeOS(
+      this, account_id, GetAdjustedAnimationTimeInMS(kUserFadeTimeMS)));
   // Call notifier here instead of observing ActiveUserChanged because
   // this must happen after MultiUserWindowManagerChromeOS is notified.
   ash::Shell::GetInstance()
@@ -523,13 +526,13 @@
     return;
 
   // Don't allow to make the window visible if it shouldn't be.
-  if (visible && !IsWindowOnDesktopOfUser(window, current_user_id_)) {
+  if (visible && !IsWindowOnDesktopOfUser(window, current_account_id_)) {
     SetWindowVisibility(window, false, 0);
     return;
   }
   aura::Window* owned_parent = GetOwningWindowInTransientChain(window);
   if (owned_parent && owned_parent != window && visible &&
-      !IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
+      !IsWindowOnDesktopOfUser(owned_parent, current_account_id_))
     SetWindowVisibility(window, false, 0);
 }
 
@@ -575,24 +578,23 @@
   return animation_.get() != NULL && !animation_->IsAnimationFinished();
 }
 
-const std::string& MultiUserWindowManagerChromeOS::GetCurrentUserForTest()
-    const {
-  return current_user_id_;
+const AccountId& MultiUserWindowManagerChromeOS::GetCurrentUserForTest() const {
+  return current_account_id_;
 }
 
 bool MultiUserWindowManagerChromeOS::ShowWindowForUserIntern(
     aura::Window* window,
-    const std::string& user_id) {
+    const AccountId& account_id) {
   // If there is either no owner, or the owner is the current user, no action
   // is required.
-  const std::string& owner = GetWindowOwner(window);
-  if (owner.empty() ||
-      (owner == user_id && IsWindowOnDesktopOfUser(window, user_id)))
+  const AccountId& owner = GetWindowOwner(window);
+  if ((!owner.is_valid()) ||
+      (owner == account_id && IsWindowOnDesktopOfUser(window, account_id)))
     return false;
 
   bool minimized = ash::wm::GetWindowState(window)->IsMinimized();
   // Check that we are not trying to transfer ownership of a minimized window.
-  if (user_id != owner && minimized)
+  if (account_id != owner && minimized)
     return false;
 
   if (minimized) {
@@ -606,10 +608,10 @@
   }
 
   WindowToEntryMap::iterator it = window_to_entry_.find(window);
-  it->second->set_show_for_user(user_id);
+  it->second->set_show_for_user(account_id);
 
   // Show the window if the added user is the current one.
-  if (user_id == current_user_id_) {
+  if (account_id == current_account_id_) {
     // Only show the window if it should be shown according to its state.
     if (it->second->show())
       SetWindowVisibility(window, true, kTeleportAnimationTimeMS);
@@ -639,15 +641,15 @@
     if (window->parent() == system_modal_container) {
       // The window is system modal and we need to find the parent which owns
       // it so that we can switch to the desktop accordingly.
-      std::string user_id = GetUserPresentingWindow(window);
-      if (user_id.empty()) {
+      AccountId account_id = GetUserPresentingWindow(window);
+      if (!account_id.is_valid()) {
         aura::Window* owning_window = GetOwningWindowInTransientChain(window);
         DCHECK(owning_window);
-        user_id = GetUserPresentingWindow(owning_window);
-        DCHECK(!user_id.empty());
+        account_id = GetUserPresentingWindow(owning_window);
+        DCHECK(account_id.is_valid());
       }
       ash::Shell::GetInstance()->session_state_delegate()->SwitchActiveUser(
-          user_id);
+          account_id);
       return;
     }
   }
@@ -668,7 +670,7 @@
   if (!browser->window() || !browser->window()->GetNativeWindow())
     return;
   SetWindowOwner(browser->window()->GetNativeWindow(),
-                 multi_user_util::GetUserIDFromProfile(browser->profile()));
+                 multi_user_util::GetAccountIdFromProfile(browser->profile()));
 }
 
 void MultiUserWindowManagerChromeOS::ShowWithTransientChildrenRecursive(
@@ -723,7 +725,7 @@
   // Hide the window if it should not be shown. Note that this hide operation
   // will hide recursively this and all children - but we have already collected
   // their initial view state.
-  if (!IsWindowOnDesktopOfUser(owned_parent, current_user_id_))
+  if (!IsWindowOnDesktopOfUser(owned_parent, current_account_id_))
     SetWindowVisibility(window, false, kAnimationTimeMS);
 }
 
@@ -787,20 +789,20 @@
       (animation_speed_ == ANIMATION_SPEED_FAST ? 10 : 0);
 }
 
-void MultiUserWindowManagerChromeOS::RemoveUser(const std::string& user_id,
+void MultiUserWindowManagerChromeOS::RemoveUser(const AccountId& account_id,
                                                 Profile* profile) {
-  UserIDToAppWindowObserver::iterator app_observer_iterator =
-      user_id_to_app_observer_.find(user_id);
-  DCHECK(app_observer_iterator != user_id_to_app_observer_.end())
-      << "User id '" << user_id << "', profile=" << profile
+  AccountIdToAppWindowObserver::iterator app_observer_iterator =
+      account_id_to_app_observer_.find(account_id);
+  DCHECK(app_observer_iterator != account_id_to_app_observer_.end())
+      << "User id '" << account_id.GetUserEmail() << "', profile=" << profile
       << " was not found.";
-  if (app_observer_iterator == user_id_to_app_observer_.end())
+  if (app_observer_iterator == account_id_to_app_observer_.end())
     return;
 
   extensions::AppWindowRegistry::Get(profile)
       ->RemoveObserver(app_observer_iterator->second);
   delete app_observer_iterator->second;
-  user_id_to_app_observer_.erase(app_observer_iterator);
+  account_id_to_app_observer_.erase(app_observer_iterator);
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
index 90788f7..53f1a41e 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "ui/aura/window_observer.h"
@@ -69,34 +70,31 @@
     ANIMATION_SPEED_DISABLED  // Unit tests which do not require animations.
   };
 
-  // Create the manager and use |active_user_id| as the active user.
-  explicit MultiUserWindowManagerChromeOS(const std::string& active_user_id);
+  // Create the manager and use |active_account_id| as the active user.
+  explicit MultiUserWindowManagerChromeOS(const AccountId& active_account_id);
   ~MultiUserWindowManagerChromeOS() override;
 
   // Initializes the manager after its creation. Should only be called once.
   void Init();
 
   // MultiUserWindowManager overrides:
-  void SetWindowOwner(
-      aura::Window* window, const std::string& user_id) override;
-  const std::string& GetWindowOwner(
-      aura::Window* window) const override;
-  void ShowWindowForUser(
-      aura::Window* window, const std::string& user_id) override;
+  void SetWindowOwner(aura::Window* window,
+                      const AccountId& account_id) override;
+  const AccountId& GetWindowOwner(aura::Window* window) const override;
+  void ShowWindowForUser(aura::Window* window,
+                         const AccountId& account_id) override;
   bool AreWindowsSharedAmongUsers() const override;
   void GetOwnersOfVisibleWindows(
-      std::set<std::string>* user_ids) const override;
-  bool IsWindowOnDesktopOfUser(
-      aura::Window* window,
-      const std::string& user_id) const override;
-  const std::string& GetUserPresentingWindow(
-      aura::Window* window) const override;
+      std::set<AccountId>* account_ids) const override;
+  bool IsWindowOnDesktopOfUser(aura::Window* window,
+                               const AccountId& account_id) const override;
+  const AccountId& GetUserPresentingWindow(aura::Window* window) const override;
   void AddUser(content::BrowserContext* context) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
   // SessionStateObserver overrides:
-  void ActiveUserChanged(const std::string& user_id) override;
+  void ActiveUserChanged(const AccountId& account_id) override;
 
   // WindowObserver overrides:
   void OnWindowDestroyed(aura::Window* window) override;
@@ -121,32 +119,30 @@
   bool IsAnimationRunningForTest();
 
   // Returns the current user for unit tests.
-  const std::string& GetCurrentUserForTest() const;
+  const AccountId& GetCurrentUserForTest() const;
 
  protected:
   friend class UserSwitchAnimatorChromeOS;
 
   class WindowEntry {
    public:
-    explicit WindowEntry(const std::string& user_id)
-        : owner_(user_id),
-          show_for_user_(user_id),
-          show_(true) {}
+    explicit WindowEntry(const AccountId& account_id)
+        : owner_(account_id), show_for_user_(account_id), show_(true) {}
     virtual ~WindowEntry() {}
 
     // Returns the owner of this window. This cannot be changed.
-    const std::string& owner() const { return owner_; }
+    const AccountId& owner() const { return owner_; }
 
     // Returns the user for which this should be shown.
-    const std::string& show_for_user() const { return show_for_user_; }
+    const AccountId& show_for_user() const { return show_for_user_; }
 
     // Returns if the window should be shown for the "show user" or not.
     bool show() const { return show_; }
 
     // Set the user which will display the window on the owned desktop. If
     // an empty user id gets passed the owner will be used.
-    void set_show_for_user(const std::string& user_id) {
-      show_for_user_ = user_id.empty() ? owner_ : user_id;
+    void set_show_for_user(const AccountId& account_id) {
+      show_for_user_ = account_id.is_valid() ? account_id : owner_;
     }
 
     // Sets if the window gets shown for the active user or not.
@@ -154,10 +150,10 @@
 
    private:
     // The user id of the owner of this window.
-    const std::string owner_;
+    const AccountId owner_;
 
     // The user id of the user on which desktop the window gets shown.
-    std::string show_for_user_;
+    AccountId show_for_user_;
 
     // True if the window should be visible for the user which shows the window.
     bool show_;
@@ -170,7 +166,7 @@
   // Show a window for a user without switching the user.
   // Returns true when the window moved to a new desktop.
   bool ShowWindowForUserIntern(aura::Window* window,
-                               const std::string& user_id);
+                               const AccountId& account_id);
 
   // Show / hide the given window. Note: By not doing this within the functions,
   // this allows to either switching to different ways to show/hide and / or to
@@ -192,7 +188,7 @@
   friend class ::MultiUserNotificationBlockerChromeOSTest;
   friend class ash::test::MultiUserWindowManagerChromeOSTest;
 
-  typedef std::map<std::string, AppObserver*> UserIDToAppWindowObserver;
+  typedef std::map<AccountId, AppObserver*> AccountIdToAppWindowObserver;
   typedef std::map<aura::Window*, bool> TransientWindowToVisibility;
 
   // Add a browser window to the system so that the owner can be remembered.
@@ -227,18 +223,18 @@
   // from the passed |default_time_in_ms|.
   int GetAdjustedAnimationTimeInMS(int default_time_in_ms) const;
 
-  // This is called when KeyedService (for |iser_id| and |profile|) is
+  // This is called when KeyedService (for |account_id| and |profile|) is
   // destroyed, or when MultiUserWindowManagerChromeOS is destroyed.
   // This happens on shutdown, before profile prefs are stored to
   // disk.
-  void RemoveUser(const std::string& user_id, Profile* profile);
+  void RemoveUser(const AccountId& account_id, Profile* profile);
 
   // A lookup to see to which user the given window belongs to, where and if it
   // should get shown.
   WindowToEntryMap window_to_entry_;
 
   // A list of all known users and their app window observers.
-  UserIDToAppWindowObserver user_id_to_app_observer_;
+  AccountIdToAppWindowObserver account_id_to_app_observer_;
 
   // An observer list to be notified upon window owner changes.
   base::ObserverList<Observer> observers_;
@@ -249,7 +245,7 @@
   // The currently selected active user. It is used to find the proper
   // visibility state in various cases. The state is stored here instead of
   // being read from the user manager to be in sync while a switch occurs.
-  std::string current_user_id_;
+  AccountId current_account_id_;
 
   // The blocker which controls the desktop notification visibility based on the
   // current multi-user status.
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index 4faee0c..3e06d308 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -32,6 +32,7 @@
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_info.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -55,8 +56,8 @@
     const user_manager::UserManager* user_manager =
         user_manager::UserManager::Get();
     const user_manager::User* active_user = user_manager->GetActiveUser();
-    return active_user ? multi_user_util::GetProfileFromUserID(
-                             active_user->GetAccountId().GetUserEmail())
+    return active_user ? multi_user_util::GetProfileFromAccountId(
+                             active_user->GetAccountId())
                        : NULL;
   }
 
@@ -67,19 +68,21 @@
 
   content::BrowserContext* GetBrowserContextForWindow(
       aura::Window* window) override {
-    const std::string& user_id =
+    const AccountId& account_id =
         chrome::MultiUserWindowManager::GetInstance()->GetWindowOwner(window);
-    return user_id.empty() ? NULL
-                           : multi_user_util::GetProfileFromUserID(user_id);
+    return account_id.is_valid()
+               ? multi_user_util::GetProfileFromAccountId(account_id)
+               : nullptr;
   }
 
   content::BrowserContext* GetUserPresentingBrowserContextForWindow(
       aura::Window* window) override {
-    const std::string& user_id =
+    const AccountId& account_id =
         chrome::MultiUserWindowManager::GetInstance()->GetUserPresentingWindow(
             window);
-    return user_id.empty() ? NULL
-                           : multi_user_util::GetProfileFromUserID(user_id);
+    return account_id.is_valid()
+               ? multi_user_util::GetProfileFromAccountId(account_id)
+               : nullptr;
   }
 
   DISALLOW_COPY_AND_ASSIGN(TestShellContentState);
@@ -126,8 +129,8 @@
   void SetUpForThisManyWindows(int windows);
 
   // Switch the user and wait until the animation is finished.
-  void SwitchUserAndWaitForAnimation(const std::string& user_id) {
-    multi_user_window_manager_->ActiveUserChanged(user_id);
+  void SwitchUserAndWaitForAnimation(const AccountId& account_id) {
+    multi_user_window_manager_->ActiveUserChanged(account_id);
     base::TimeTicks now = base::TimeTicks::Now();
     while (multi_user_window_manager_->IsAnimationRunningForTest()) {
       // This should never take longer then a second.
@@ -157,13 +160,12 @@
 
   TestingProfileManager* profile_manager() { return profile_manager_.get(); }
 
-  const user_manager::User* AddTestUser(const std::string& user_email) {
-    const user_manager::User* user =
-        fake_user_manager_->AddUser(AccountId::FromUserEmail(user_email));
-    fake_user_manager_->LoginUser(AccountId::FromUserEmail(user_email));
-    session_state_delegate_->AddUser(user_email);
+  const user_manager::User* AddTestUser(const AccountId& account_id) {
+    const user_manager::User* user = fake_user_manager_->AddUser(account_id);
+    fake_user_manager_->LoginUser(account_id);
+    session_state_delegate_->AddUser(account_id);
     TestingProfile* profile =
-        profile_manager()->CreateTestingProfile(user_email);
+        profile_manager()->CreateTestingProfile(account_id.GetUserEmail());
     chromeos::ProfileHelper::Get()->SetUserToProfileMappingForTesting(user,
                                                                       profile);
     return user;
@@ -192,8 +194,8 @@
   }
 
   void ShowWindowForUserNoUserTransition(aura::Window* window,
-                                         const std::string& user_id) {
-    multi_user_window_manager_->ShowWindowForUserIntern(window, user_id);
+                                         const AccountId& account_id) {
+    multi_user_window_manager_->ShowWindowForUserIntern(window, account_id);
   }
 
   // The test session state observer does not automatically call the window
@@ -202,15 +204,15 @@
   AccountId GetAndValidateCurrentUserFromSessionStateObserver() {
     const AccountId account_id =
         session_state_delegate()->GetActiveUserInfo()->GetAccountId();
-    if (account_id.GetUserEmail() !=
-        multi_user_window_manager_->GetCurrentUserForTest())
-      multi_user_window_manager()->ActiveUserChanged(account_id.GetUserEmail());
+    if (account_id != multi_user_window_manager_->GetCurrentUserForTest())
+      multi_user_window_manager()->ActiveUserChanged(account_id);
+
     return account_id;
   }
 
   // Initiate a user transition.
-  void StartUserTransitionAnimation(const std::string& user_id) {
-    multi_user_window_manager_->ActiveUserChanged(user_id);
+  void StartUserTransitionAnimation(const AccountId& account_id) {
+    multi_user_window_manager_->ActiveUserChanged(account_id);
   }
 
   // Call next animation step.
@@ -219,7 +221,7 @@
   }
 
   // Return the user id of the wallpaper which is currently set.
-  const std::string& GetWallaperUserIdForTest() {
+  const std::string& GetWallpaperUserIdForTest() {
     return multi_user_window_manager_->animation_->wallpaper_user_id_for_test();
   }
 
@@ -272,9 +274,9 @@
   profile_manager_.reset(
       new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
   ASSERT_TRUE(profile_manager_.get()->SetUp());
-  session_state_delegate_->AddUser("a");
-  session_state_delegate_->AddUser("b");
-  session_state_delegate_->AddUser("c");
+  session_state_delegate_->AddUser(AccountId::FromUserEmail("a"));
+  session_state_delegate_->AddUser(AccountId::FromUserEmail("b"));
+  session_state_delegate_->AddUser(AccountId::FromUserEmail("c"));
 }
 
 void MultiUserWindowManagerChromeOSTest::SetUpForThisManyWindows(int windows) {
@@ -283,7 +285,8 @@
     window_.push_back(CreateTestWindowInShellWithId(i));
     window_[i]->Show();
   }
-  multi_user_window_manager_ = new chrome::MultiUserWindowManagerChromeOS("A");
+  multi_user_window_manager_ =
+      new chrome::MultiUserWindowManagerChromeOS(AccountId::FromUserEmail("A"));
   multi_user_window_manager_->Init();
   multi_user_window_manager_->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_DISABLED);
@@ -317,14 +320,14 @@
       continue;
     }
     s += window(i)->IsVisible() ? "S[" : "H[";
-    const std::string& owner =
+    const AccountId& owner =
         multi_user_window_manager_->GetWindowOwner(window(i));
-    s += owner;
-    const std::string& presenter =
+    s += owner.GetUserEmail();
+    const AccountId& presenter =
         multi_user_window_manager_->GetUserPresentingWindow(window(i));
     if (!owner.empty() && owner != presenter) {
       s += ",";
-      s += presenter;
+      s += presenter.GetUserEmail();
     }
     s += "]";
   }
@@ -333,11 +336,12 @@
 
 std::string
 MultiUserWindowManagerChromeOSTest::GetOwnersOfVisibleWindowsAsString() {
-  std::set<std::string> owners;
+  std::set<AccountId> owners;
   multi_user_window_manager_->GetOwnersOfVisibleWindows(&owners);
 
   std::vector<std::string> owner_list;
-  owner_list.insert(owner_list.begin(), owners.begin(), owners.end());
+  std::transform(owners.begin(), owners.end(), std::back_inserter(owner_list),
+                 std::mem_fun_ref(&AccountId::GetUserEmail));
   return base::JoinString(owner_list, " ");
 }
 
@@ -351,62 +355,74 @@
             chrome::MultiUserWindowManager::GetInstance());
   EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
 
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
   // The owner of an unowned window should be empty and it should be shown on
   // all windows.
-  EXPECT_EQ("", multi_user_window_manager()->GetWindowOwner(window(0)));
-  EXPECT_EQ("",
-      multi_user_window_manager()->GetUserPresentingWindow(window(0)));
-  EXPECT_TRUE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
-  EXPECT_TRUE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
+  EXPECT_FALSE(
+      multi_user_window_manager()->GetWindowOwner(window(0)).is_valid());
+  EXPECT_FALSE(multi_user_window_manager()
+                   ->GetUserPresentingWindow(window(0))
+                   .is_valid());
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_A));
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_B));
 
   // Set the owner of one window should remember it as such. It should only be
   // drawn on the owners desktop - not on any other.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
-  EXPECT_EQ("A",
-      multi_user_window_manager()->GetUserPresentingWindow(window(0)));
-  EXPECT_TRUE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
-  EXPECT_FALSE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  EXPECT_EQ(account_id_A,
+            multi_user_window_manager()->GetWindowOwner(window(0)));
+  EXPECT_EQ(account_id_A,
+            multi_user_window_manager()->GetUserPresentingWindow(window(0)));
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_A));
+  EXPECT_FALSE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_B));
 
   // Overriding it with another state should show it on the other user's
   // desktop.
-  ShowWindowForUserNoUserTransition(window(0), "B");
-  EXPECT_EQ("A", multi_user_window_manager()->GetWindowOwner(window(0)));
-  EXPECT_EQ("B",
-      multi_user_window_manager()->GetUserPresentingWindow(window(0)));
-  EXPECT_FALSE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "A"));
-  EXPECT_TRUE(
-      multi_user_window_manager()->IsWindowOnDesktopOfUser(window(0), "B"));
+  ShowWindowForUserNoUserTransition(window(0), account_id_B);
+  EXPECT_EQ(account_id_A,
+            multi_user_window_manager()->GetWindowOwner(window(0)));
+  EXPECT_EQ(account_id_B,
+            multi_user_window_manager()->GetUserPresentingWindow(window(0)));
+  EXPECT_FALSE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_A));
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(0), account_id_B));
 }
 
 // Testing simple owner changes.
 TEST_F(MultiUserWindowManagerChromeOSTest, OwnerTests) {
   SetUpForThisManyWindows(5);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Set some windows to the active owner.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
   EXPECT_EQ("S[A], S[], S[], S[], S[]", GetStatus());
-  multi_user_window_manager()->SetWindowOwner(window(2), "A");
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_A);
   EXPECT_EQ("S[A], S[], S[A], S[], S[]", GetStatus());
 
   // Set some windows to an inactive owner. Note that the windows should hide.
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
   EXPECT_EQ("S[A], H[B], S[A], S[], S[]", GetStatus());
-  multi_user_window_manager()->SetWindowOwner(window(3), "B");
+  multi_user_window_manager()->SetWindowOwner(window(3), account_id_B);
   EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
 
   // Assume that the user has now changed to C - which should show / hide
   // accordingly.
-  multi_user_window_manager()->ActiveUserChanged("C");
+  StartUserTransitionAnimation(account_id_C);
   EXPECT_EQ("H[A], H[B], H[A], H[B], S[]", GetStatus());
 
   // If someone tries to show an inactive window it should only work if it can
   // be shown / hidden.
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
   window(3)->Show();
   EXPECT_EQ("S[A], H[B], S[A], H[B], S[]", GetStatus());
@@ -418,21 +434,23 @@
 
 TEST_F(MultiUserWindowManagerChromeOSTest, CloseWindowTests) {
   SetUpForThisManyWindows(1);
-  multi_user_window_manager()->SetWindowOwner(window(0), "B");
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_B);
   EXPECT_EQ("H[B]", GetStatus());
-  ShowWindowForUserNoUserTransition(window(0), "A");
+  ShowWindowForUserNoUserTransition(window(0), account_id_A);
   EXPECT_EQ("S[B,A]", GetStatus());
   EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
   EXPECT_EQ("B", GetOwnersOfVisibleWindowsAsString());
 
   aura::Window* to_be_deleted = window(0);
 
-  EXPECT_EQ(std::string("A"),
-            multi_user_window_manager()->GetUserPresentingWindow(
-                to_be_deleted));
-  EXPECT_EQ(std::string("B"),
-            multi_user_window_manager()->GetWindowOwner(
-                to_be_deleted));
+  EXPECT_EQ(account_id_A, multi_user_window_manager()->GetUserPresentingWindow(
+                              to_be_deleted));
+  EXPECT_EQ(account_id_B,
+            multi_user_window_manager()->GetWindowOwner(to_be_deleted));
 
   // Close the window.
   delete_window_at(0);
@@ -441,82 +459,90 @@
   EXPECT_EQ("", GetOwnersOfVisibleWindowsAsString());
   // There should be no owner anymore for that window and the shared windows
   // should be gone as well.
-  EXPECT_EQ(std::string(),
-            multi_user_window_manager()->GetUserPresentingWindow(
-                to_be_deleted));
-  EXPECT_EQ(std::string(),
-            multi_user_window_manager()->GetWindowOwner(
-                to_be_deleted));
+  EXPECT_FALSE(multi_user_window_manager()
+                   ->GetUserPresentingWindow(to_be_deleted)
+                   .is_valid());
+  EXPECT_FALSE(
+      multi_user_window_manager()->GetWindowOwner(to_be_deleted).is_valid());
 }
 
 TEST_F(MultiUserWindowManagerChromeOSTest, SharedWindowTests) {
   SetUpForThisManyWindows(5);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "A");
-  multi_user_window_manager()->SetWindowOwner(window(2), "B");
-  multi_user_window_manager()->SetWindowOwner(window(3), "B");
-  multi_user_window_manager()->SetWindowOwner(window(4), "C");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(3), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(4), account_id_C);
   EXPECT_EQ("S[A], S[A], H[B], H[B], H[C]", GetStatus());
   EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
   EXPECT_EQ("A", GetOwnersOfVisibleWindowsAsString());
 
   // For all following tests we override window 2 to be shown by user B.
-  ShowWindowForUserNoUserTransition(window(1), "B");
+  ShowWindowForUserNoUserTransition(window(1), account_id_B);
 
   // Change window 3 between two users and see that it changes
   // accordingly (or not).
-  ShowWindowForUserNoUserTransition(window(2), "A");
+  ShowWindowForUserNoUserTransition(window(2), account_id_A);
   EXPECT_EQ("S[A], H[A,B], S[B,A], H[B], H[C]", GetStatus());
   EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
   EXPECT_EQ("A B", GetOwnersOfVisibleWindowsAsString());
-  ShowWindowForUserNoUserTransition(window(2), "C");
+  ShowWindowForUserNoUserTransition(window(2), account_id_C);
   EXPECT_EQ("S[A], H[A,B], H[B,C], H[B], H[C]", GetStatus());
   EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
   EXPECT_EQ("A", GetOwnersOfVisibleWindowsAsString());
 
   // Switch the users and see that the results are correct.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[A,B], H[B,C], S[B], H[C]", GetStatus());
   EXPECT_EQ("A B", GetOwnersOfVisibleWindowsAsString());
-  multi_user_window_manager()->ActiveUserChanged("C");
+  StartUserTransitionAnimation(account_id_C);
   EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
   EXPECT_EQ("B C", GetOwnersOfVisibleWindowsAsString());
 
   // Showing on the desktop of the already owning user should have no impact.
-  ShowWindowForUserNoUserTransition(window(4), "C");
+  ShowWindowForUserNoUserTransition(window(4), account_id_C);
   EXPECT_EQ("H[A], H[A,B], S[B,C], H[B], S[C]", GetStatus());
   EXPECT_EQ("B C", GetOwnersOfVisibleWindowsAsString());
 
   // Changing however a shown window back to the original owner should hide it.
-  ShowWindowForUserNoUserTransition(window(2), "B");
+  ShowWindowForUserNoUserTransition(window(2), account_id_B);
   EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
   EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
   EXPECT_EQ("C", GetOwnersOfVisibleWindowsAsString());
 
   // And the change should be "permanent" - switching somewhere else and coming
   // back.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[A,B], S[B], S[B], H[C]", GetStatus());
   EXPECT_EQ("A B", GetOwnersOfVisibleWindowsAsString());
-  multi_user_window_manager()->ActiveUserChanged("C");
+  StartUserTransitionAnimation(account_id_C);
   EXPECT_EQ("H[A], H[A,B], H[B], H[B], S[C]", GetStatus());
   EXPECT_EQ("C", GetOwnersOfVisibleWindowsAsString());
 
   // After switching window 2 back to its original desktop, all desktops should
   // be "clean" again.
-  ShowWindowForUserNoUserTransition(window(1), "A");
+  ShowWindowForUserNoUserTransition(window(1), account_id_A);
   EXPECT_FALSE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
 }
 
 // Make sure that adding a window to another desktop does not cause harm.
 TEST_F(MultiUserWindowManagerChromeOSTest, DoubleSharedWindowTests) {
   SetUpForThisManyWindows(1);
-  multi_user_window_manager()->SetWindowOwner(window(0), "B");
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_B);
 
   // Add two references to the same window.
-  ShowWindowForUserNoUserTransition(window(0), "A");
-  ShowWindowForUserNoUserTransition(window(0), "A");
+  ShowWindowForUserNoUserTransition(window(0), account_id_A);
+  ShowWindowForUserNoUserTransition(window(0), account_id_A);
   EXPECT_TRUE(multi_user_window_manager()->AreWindowsSharedAmongUsers());
 
   // Close the window.
@@ -532,14 +558,19 @@
 // hiding does not interfere with the "normal operation".
 TEST_F(MultiUserWindowManagerChromeOSTest, PreserveWindowVisibilityTests) {
   SetUpForThisManyWindows(5);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Set some owners and make sure we got what we asked for.
   // Note that we try to cover all combinations in one go.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "A");
-  multi_user_window_manager()->SetWindowOwner(window(2), "B");
-  multi_user_window_manager()->SetWindowOwner(window(3), "B");
-  ShowWindowForUserNoUserTransition(window(2), "A");
-  ShowWindowForUserNoUserTransition(window(3), "A");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(3), account_id_B);
+  ShowWindowForUserNoUserTransition(window(2), account_id_A);
+  ShowWindowForUserNoUserTransition(window(3), account_id_A);
   EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
 
   // Hiding a window should be respected - no matter if it is owned by that user
@@ -550,10 +581,10 @@
   EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
 
   // Flipping to another user and back should preserve all show / hide states.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], H[]", GetStatus());
 
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("H[A], S[A], H[B,A], S[B,A], H[]", GetStatus());
 
   // After making them visible and switching fore and back everything should be
@@ -563,21 +594,21 @@
   window(4)->Show();
   EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
 
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
 
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
 
   // Now test that making windows visible through "normal operation" while the
   // user's desktop is hidden leads to the correct result.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
   window(0)->Show();
   window(2)->Show();
   window(4)->Show();
   EXPECT_EQ("H[A], H[A], H[B,A], H[B,A], S[]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], S[A], S[B,A], S[B,A], S[]", GetStatus());
 }
 
@@ -585,22 +616,26 @@
 // back and gets restored upon switching back to the original user.
 TEST_F(MultiUserWindowManagerChromeOSTest, MinimizeChangesOwnershipBack) {
   SetUpForThisManyWindows(4);
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
-  multi_user_window_manager()->SetWindowOwner(window(2), "B");
-  ShowWindowForUserNoUserTransition(window(1), "A");
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_B);
+  ShowWindowForUserNoUserTransition(window(1), account_id_A);
   EXPECT_EQ("S[A], S[B,A], H[B], S[]", GetStatus());
-  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
-                                                                   "A"));
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(1), account_id_A));
   wm::GetWindowState(window(1))->Minimize();
   // At this time the window is still on the desktop of that user, but the user
   // does not have a way to get to it.
   EXPECT_EQ("S[A], H[B,A], H[B], S[]", GetStatus());
-  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(window(1),
-                                                                   "A"));
+  EXPECT_TRUE(multi_user_window_manager()->IsWindowOnDesktopOfUser(
+      window(1), account_id_A));
   EXPECT_TRUE(wm::GetWindowState(window(1))->IsMinimized());
   // Change to user B and make sure that minimizing does not change anything.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[B], S[B], S[]", GetStatus());
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMinimized());
 }
@@ -608,12 +643,16 @@
 // Check that we cannot transfer the ownership of a minimized window.
 TEST_F(MultiUserWindowManagerChromeOSTest, MinimizeSuppressesViewTransfer) {
   SetUpForThisManyWindows(1);
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
   wm::GetWindowState(window(0))->Minimize();
   EXPECT_EQ("H[A]", GetStatus());
 
   // Try to transfer the window to user B - which should get ignored.
-  ShowWindowForUserNoUserTransition(window(0), "B");
+  ShowWindowForUserNoUserTransition(window(0), account_id_B);
   EXPECT_EQ("H[A]", GetStatus());
 }
 
@@ -621,42 +660,46 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, ActiveWindowTests) {
   SetUpForThisManyWindows(4);
 
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   aura::client::ActivationClient* activation_client =
       aura::client::GetActivationClient(window(0)->GetRootWindow());
 
   // Set some windows to the active owner.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "A");
-  multi_user_window_manager()->SetWindowOwner(window(2), "B");
-  multi_user_window_manager()->SetWindowOwner(window(3), "B");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(3), account_id_B);
   EXPECT_EQ("S[A], S[A], H[B], H[B]", GetStatus());
 
   // Set the active window for user A to be #1
   activation_client->ActivateWindow(window(1));
 
   // Change to user B and make sure that one of its windows is active.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[A], S[B], S[B]", GetStatus());
   EXPECT_TRUE(window(3) == activation_client->GetActiveWindow() ||
               window(2) == activation_client->GetActiveWindow());
   // Set the active window for user B now to be #2
   activation_client->ActivateWindow(window(2));
 
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ(window(1), activation_client->GetActiveWindow());
 
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ(window(2), activation_client->GetActiveWindow());
 
-  multi_user_window_manager()->ActiveUserChanged("C");
+  StartUserTransitionAnimation(account_id_C);
   EXPECT_EQ(NULL, activation_client->GetActiveWindow());
 
   // Now test that a minimized window stays minimized upon switch and back.
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   wm::GetWindowState(window(0))->Minimize();
 
-  multi_user_window_manager()->ActiveUserChanged("B");
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_B);
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_TRUE(wm::GetWindowState(window(0))->IsMinimized());
   EXPECT_EQ(window(1), activation_client->GetActiveWindow());
 }
@@ -665,6 +708,9 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, TransientWindows) {
   SetUpForThisManyWindows(10);
 
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
   // We create a hierarchy like this:
   //    0 (A)  4 (B)   7 (-)   - The top level owned/not owned windows
   //    |      |       |
@@ -673,8 +719,8 @@
   //    2              9       - A transtient child of a transient child.
   //    |
   //    3                      - ..
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(4), "B");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(4), account_id_B);
   ::wm::AddTransientChild(window(0), window(1));
   // We first attach 2->3 and then 1->2 to see that the ownership gets
   // properly propagated through the sub tree upon assigning.
@@ -704,9 +750,9 @@
   EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], H[], S[], S[], H[]", GetStatus());
 
   // Switching users and switch back should return to the previous state.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[], H[], H[], S[B], S[], S[], S[], S[], H[]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], S[], H[], H[], H[B], H[], H[], S[], S[], H[]", GetStatus());
 
   // Removing a window from its transient parent should return to the previously
@@ -735,6 +781,9 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, PreserveInitialVisibility) {
   SetUpForThisManyWindows(4);
 
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
   // Set our initial show state before we assign an owner.
   window(0)->Show();
   window(1)->Hide();
@@ -743,26 +792,26 @@
   EXPECT_EQ("S[], H[], S[], H[]", GetStatus());
 
   // First test: The show state gets preserved upon user switch.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "A");
-  multi_user_window_manager()->SetWindowOwner(window(2), "B");
-  multi_user_window_manager()->SetWindowOwner(window(3), "B");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(3), account_id_B);
   EXPECT_EQ("S[A], H[A], H[B], H[B]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], H[A], S[B], H[B]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], H[A], H[B], H[B]", GetStatus());
 
   // Second test: Transferring the window to another desktop preserves the
   // show state.
-  ShowWindowForUserNoUserTransition(window(0), "B");
-  ShowWindowForUserNoUserTransition(window(1), "B");
-  ShowWindowForUserNoUserTransition(window(2), "A");
-  ShowWindowForUserNoUserTransition(window(3), "A");
+  ShowWindowForUserNoUserTransition(window(0), account_id_B);
+  ShowWindowForUserNoUserTransition(window(1), account_id_B);
+  ShowWindowForUserNoUserTransition(window(2), account_id_A);
+  ShowWindowForUserNoUserTransition(window(3), account_id_A);
   EXPECT_EQ("H[A,B], H[A,B], S[B,A], H[B,A]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("S[A,B], H[A,B], H[B,A], H[B,A]", GetStatus());
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("H[A,B], H[A,B], S[B,A], H[B,A]", GetStatus());
 }
 
@@ -771,8 +820,11 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, MaximizeModeInteraction) {
   SetUpForThisManyWindows(2);
 
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
 
   EXPECT_FALSE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMaximized());
@@ -784,7 +836,7 @@
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMaximized());
 
   // After we start switching to B, the windows of user B should maximize.
-  StartUserTransitionAnimation("B");
+  StartUserTransitionAnimation(account_id_B);
 
   EXPECT_TRUE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_TRUE(wm::GetWindowState(window(1))->IsMaximized());
@@ -794,42 +846,42 @@
 // user.
 TEST_F(MultiUserWindowManagerChromeOSTest, SwitchUsersUponModalityChange) {
   SetUpForThisManyWindows(1);
-  session_state_delegate()->SwitchActiveUser("a");
+
+  const AccountId account_id_a(AccountId::FromUserEmail("a"));
+  const AccountId account_id_b(AccountId::FromUserEmail("b"));
+
+  session_state_delegate()->SwitchActiveUser(account_id_a);
 
   // Making the window system modal should not change anything.
   MakeWindowSystemModal(window(0));
-  EXPECT_EQ("a", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  EXPECT_EQ(account_id_a,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 
   // Making the window owned by user B should switch users.
-  multi_user_window_manager()->SetWindowOwner(window(0), "b");
-  EXPECT_EQ("b", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_b);
+  EXPECT_EQ(account_id_b,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 }
 
 // Test that a system modal dialog will not switch desktop if active user has
 // shows window.
 TEST_F(MultiUserWindowManagerChromeOSTest, DontSwitchUsersUponModalityChange) {
   SetUpForThisManyWindows(1);
-  session_state_delegate()->SwitchActiveUser("a");
+
+  const AccountId account_id_a(AccountId::FromUserEmail("a"));
+  const AccountId account_id_b(AccountId::FromUserEmail("b"));
+
+  session_state_delegate()->SwitchActiveUser(account_id_a);
 
   // Making the window system modal should not change anything.
   MakeWindowSystemModal(window(0));
-  EXPECT_EQ("a", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  EXPECT_EQ(account_id_a,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 
   // Making the window owned by user a should not switch users.
-  multi_user_window_manager()->SetWindowOwner(window(0), "a");
-  EXPECT_EQ("a", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_a);
+  EXPECT_EQ(account_id_a,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 }
 
 // Test that a system modal dialog will not switch if shown on correct desktop
@@ -837,18 +889,20 @@
 TEST_F(MultiUserWindowManagerChromeOSTest,
        DontSwitchUsersUponModalityChangeWhenShownButNotOwned) {
   SetUpForThisManyWindows(1);
-  session_state_delegate()->SwitchActiveUser("a");
+
+  const AccountId account_id_a(AccountId::FromUserEmail("a"));
+  const AccountId account_id_b(AccountId::FromUserEmail("b"));
+
+  session_state_delegate()->SwitchActiveUser(account_id_a);
 
   window(0)->Hide();
-  multi_user_window_manager()->SetWindowOwner(window(0), "b");
-  ShowWindowForUserNoUserTransition(window(0), "a");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_b);
+  ShowWindowForUserNoUserTransition(window(0), account_id_a);
   MakeWindowSystemModal(window(0));
   // Showing the window should trigger no user switch.
   window(0)->Show();
-  EXPECT_EQ("a", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  EXPECT_EQ(account_id_a,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 }
 
 // Test that a system modal dialog will switch if shown on incorrect desktop but
@@ -856,49 +910,56 @@
 TEST_F(MultiUserWindowManagerChromeOSTest,
        SwitchUsersUponModalityChangeWhenShownButNotOwned) {
   SetUpForThisManyWindows(1);
-  session_state_delegate()->SwitchActiveUser("a");
+
+  const AccountId account_id_a(AccountId::FromUserEmail("a"));
+  const AccountId account_id_b(AccountId::FromUserEmail("b"));
+
+  session_state_delegate()->SwitchActiveUser(account_id_a);
 
   window(0)->Hide();
-  multi_user_window_manager()->SetWindowOwner(window(0), "a");
-  ShowWindowForUserNoUserTransition(window(0), "b");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_a);
+  ShowWindowForUserNoUserTransition(window(0), account_id_b);
   MakeWindowSystemModal(window(0));
   // Showing the window should trigger a user switch.
   window(0)->Show();
-  EXPECT_EQ("b", session_state_delegate()
-                     ->GetActiveUserInfo()
-                     ->GetAccountId()
-                     .GetUserEmail());
+  EXPECT_EQ(account_id_b,
+            session_state_delegate()->GetActiveUserInfo()->GetAccountId());
 }
 
 // Test that using the full user switch animations are working as expected.
 TEST_F(MultiUserWindowManagerChromeOSTest, FullUserSwitchAnimationTests) {
   SetUpForThisManyWindows(3);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
-  multi_user_window_manager()->SetWindowOwner(window(2), "C");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_C);
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
   EXPECT_EQ("A", GetOwnersOfVisibleWindowsAsString());
 
   // Switch the user fore and back and see that the results are correct.
-  SwitchUserAndWaitForAnimation("B");
+  SwitchUserAndWaitForAnimation(account_id_B);
 
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
   EXPECT_EQ("B", GetOwnersOfVisibleWindowsAsString());
 
-  SwitchUserAndWaitForAnimation("A");
+  SwitchUserAndWaitForAnimation(account_id_A);
 
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
 
   // Switch the user quickly to another user and before the animation is done
   // switch back and see that this works.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
   // Check that after switching to C, C is fully visible.
-  SwitchUserAndWaitForAnimation("C");
+  SwitchUserAndWaitForAnimation(account_id_C);
   EXPECT_EQ("H[A], H[B], S[C]", GetStatus());
   EXPECT_EQ("C", GetOwnersOfVisibleWindowsAsString());
 }
@@ -907,13 +968,17 @@
 // a shutdown happens.
 TEST_F(MultiUserWindowManagerChromeOSTest, SystemShutdownWithActiveAnimation) {
   SetUpForThisManyWindows(2);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
-  StartUserTransitionAnimation("B");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
+  StartUserTransitionAnimation(account_id_B);
   // We don't do anything more here - the animations are pending and with the
   // shutdown of the framework the animations should get cancelled. If not a
   // crash would happen.
@@ -923,13 +988,18 @@
 // we expect them to in all animation steps.
 TEST_F(MultiUserWindowManagerChromeOSTest, AnimationSteps) {
   SetUpForThisManyWindows(3);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
-  multi_user_window_manager()->SetWindowOwner(window(2), "C");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_C);
   EXPECT_FALSE(CoversScreen(window(0)));
   EXPECT_FALSE(CoversScreen(window(1)));
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
@@ -945,8 +1015,8 @@
   // Start the animation and see that the old window is becoming invisible, the
   // new one is becoming visible, the background starts transitionining and the
   // shelf hides.
-  StartUserTransitionAnimation("B");
-  EXPECT_EQ("->B", GetWallaperUserIdForTest());
+  StartUserTransitionAnimation(account_id_B);
+  EXPECT_EQ("->B", GetWallpaperUserIdForTest());
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
@@ -960,7 +1030,7 @@
   // which should set the shelf to its users state. Since that isn't there we
   // can only make sure that it stays where it is.
   AdvanceUserTransitionAnimation();
-  EXPECT_EQ("->B", GetWallaperUserIdForTest());
+  EXPECT_EQ("->B", GetWallpaperUserIdForTest());
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
@@ -972,7 +1042,7 @@
   // After the finalize the animation of the wallpaper should be finished.
   AdvanceUserTransitionAnimation();
   EXPECT_FALSE(shelf->IsShelfHiddenBehindBlackBar());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
 }
 
 // Test that the screen coverage is properly determined.
@@ -996,14 +1066,19 @@
 // which has no maximized window will produce the proper animation.
 TEST_F(MultiUserWindowManagerChromeOSTest, AnimationStepsMaximizeToNormal) {
   SetUpForThisManyWindows(3);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
   wm::GetWindowState(window(0))->Maximize();
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
-  multi_user_window_manager()->SetWindowOwner(window(2), "C");
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_C);
   EXPECT_TRUE(CoversScreen(window(0)));
   EXPECT_FALSE(CoversScreen(window(1)));
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
@@ -1011,23 +1086,23 @@
   EXPECT_EQ(1.0f, window(0)->layer()->GetTargetOpacity());
 
   // Start the animation and see that the new background is immediately set.
-  StartUserTransitionAnimation("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The next step will not change anything.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The final step will also not have any visible impact.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 }
@@ -1036,14 +1111,19 @@
 // which has a maximized window will produce the proper animation.
 TEST_F(MultiUserWindowManagerChromeOSTest, AnimationStepsNormalToMaximized) {
   SetUpForThisManyWindows(3);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
   wm::GetWindowState(window(1))->Maximize();
-  multi_user_window_manager()->SetWindowOwner(window(2), "C");
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_C);
   EXPECT_FALSE(CoversScreen(window(0)));
   EXPECT_TRUE(CoversScreen(window(1)));
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
@@ -1052,23 +1132,23 @@
 
   // Start the animation and see that the old window is becoming invisible, the
   // new one visible and the background remains as is.
-  StartUserTransitionAnimation("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("", GetWallaperUserIdForTest());
+  EXPECT_EQ("", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The next step will not change anything.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("", GetWallaperUserIdForTest());
+  EXPECT_EQ("", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The final step however will switch the background.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 }
@@ -1077,15 +1157,20 @@
 // which has a maximized window will produce the proper animation.
 TEST_F(MultiUserWindowManagerChromeOSTest, AnimationStepsMaximizedToMaximized) {
   SetUpForThisManyWindows(3);
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+  const AccountId account_id_C(AccountId::FromUserEmail("C"));
+
   // Turn the use of delays and animation on.
   multi_user_window_manager()->SetAnimationSpeedForTest(
       chrome::MultiUserWindowManagerChromeOS::ANIMATION_SPEED_FAST);
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
   wm::GetWindowState(window(0))->Maximize();
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
   wm::GetWindowState(window(1))->Maximize();
-  multi_user_window_manager()->SetWindowOwner(window(2), "C");
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_C);
   EXPECT_TRUE(CoversScreen(window(0)));
   EXPECT_TRUE(CoversScreen(window(1)));
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
@@ -1094,44 +1179,44 @@
 
   // Start the animation and see that the all windows are hidden (except that of
   // the new user).
-  StartUserTransitionAnimation("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The next step will not change anything.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // The final step however will hide the old window.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("H[A], S[B], H[C]", GetStatus());
-  EXPECT_EQ("B", GetWallaperUserIdForTest());
+  EXPECT_EQ("B", GetWallpaperUserIdForTest());
   EXPECT_EQ(0.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(1.0f, window(1)->layer()->GetTargetOpacity());
 
   // Switching back will do the exact same thing.
-  StartUserTransitionAnimation("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
-  EXPECT_EQ("A", GetWallaperUserIdForTest());
+  EXPECT_EQ("A", GetWallpaperUserIdForTest());
   EXPECT_EQ(1.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(0.0f, window(1)->layer()->GetTargetOpacity());
 
   // The next step will not change anything.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
-  EXPECT_EQ("A", GetWallaperUserIdForTest());
+  EXPECT_EQ("A", GetWallpaperUserIdForTest());
   EXPECT_EQ(1.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(0.0f, window(1)->layer()->GetTargetOpacity());
 
   // The final step is also not changing anything to the status.
   AdvanceUserTransitionAnimation();
   EXPECT_EQ("S[A], H[B], H[C]", GetStatus());
-  EXPECT_EQ("A", GetWallaperUserIdForTest());
+  EXPECT_EQ("A", GetWallpaperUserIdForTest());
   EXPECT_EQ(1.0f, window(0)->layer()->GetTargetOpacity());
   EXPECT_EQ(0.0f, window(1)->layer()->GetTargetOpacity());
 }
@@ -1139,41 +1224,41 @@
 // Test that showing a window for another user also switches the desktop.
 TEST_F(MultiUserWindowManagerChromeOSTest, ShowForUserSwitchesDesktop) {
   SetUpForThisManyWindows(3);
-  multi_user_window_manager()->ActiveUserChanged("a");
-  session_state_delegate()->SwitchActiveUser("a");
+
+  const AccountId account_id_a(AccountId::FromUserEmail("a"));
+  const AccountId account_id_b(AccountId::FromUserEmail("b"));
+  const AccountId account_id_c(AccountId::FromUserEmail("c"));
+
+  StartUserTransitionAnimation(account_id_a);
+  session_state_delegate()->SwitchActiveUser(account_id_a);
 
   // Set some owners and make sure we got what we asked for.
-  multi_user_window_manager()->SetWindowOwner(window(0), "a");
-  multi_user_window_manager()->SetWindowOwner(window(1), "b");
-  multi_user_window_manager()->SetWindowOwner(window(2), "c");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_a);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_b);
+  multi_user_window_manager()->SetWindowOwner(window(2), account_id_c);
   EXPECT_EQ("S[a], H[b], H[c]", GetStatus());
 
   // SetWindowOwner should not have changed the active user.
-  EXPECT_EQ("a",
-            GetAndValidateCurrentUserFromSessionStateObserver().GetUserEmail());
+  EXPECT_EQ(account_id_a, GetAndValidateCurrentUserFromSessionStateObserver());
 
   // Check that teleporting the window of the currently active user will
   // teleport to the new desktop.
-  multi_user_window_manager()->ShowWindowForUser(window(0), "b");
-  EXPECT_EQ("b",
-            GetAndValidateCurrentUserFromSessionStateObserver().GetUserEmail());
+  multi_user_window_manager()->ShowWindowForUser(window(0), account_id_b);
+  EXPECT_EQ(account_id_b, GetAndValidateCurrentUserFromSessionStateObserver());
   EXPECT_EQ("S[a,b], S[b], H[c]", GetStatus());
 
   // Check that teleporting a window from a currently inactive user will not
   // trigger a switch.
-  multi_user_window_manager()->ShowWindowForUser(window(2), "a");
-  EXPECT_EQ("b",
-            GetAndValidateCurrentUserFromSessionStateObserver().GetUserEmail());
+  multi_user_window_manager()->ShowWindowForUser(window(2), account_id_a);
+  EXPECT_EQ(account_id_b, GetAndValidateCurrentUserFromSessionStateObserver());
   EXPECT_EQ("S[a,b], S[b], H[c,a]", GetStatus());
-  multi_user_window_manager()->ShowWindowForUser(window(2), "b");
-  EXPECT_EQ("b",
-            GetAndValidateCurrentUserFromSessionStateObserver().GetUserEmail());
+  multi_user_window_manager()->ShowWindowForUser(window(2), account_id_b);
+  EXPECT_EQ(account_id_b, GetAndValidateCurrentUserFromSessionStateObserver());
   EXPECT_EQ("S[a,b], S[b], S[c,b]", GetStatus());
 
   // Check that teleporting back will also change the desktop.
-  multi_user_window_manager()->ShowWindowForUser(window(2), "c");
-  EXPECT_EQ("c",
-            GetAndValidateCurrentUserFromSessionStateObserver().GetUserEmail());
+  multi_user_window_manager()->ShowWindowForUser(window(2), account_id_c);
+  EXPECT_EQ(account_id_c, GetAndValidateCurrentUserFromSessionStateObserver());
   EXPECT_EQ("H[a,b], H[b], S[c]", GetStatus());
 }
 
@@ -1200,8 +1285,12 @@
 // will get covered with a black bar instead being hidden and re-shown.
 TEST_F(MultiUserWindowManagerChromeOSTest, TestBlackBarCover) {
   SetUpForThisManyWindows(2);
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
-  multi_user_window_manager()->SetWindowOwner(window(1), "B");
+
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
+  multi_user_window_manager()->SetWindowOwner(window(1), account_id_B);
   aura::Window* root_window = ash::Shell::GetInstance()->GetPrimaryRootWindow();
 
   // Turn the use of delays and animation on.
@@ -1214,7 +1303,7 @@
   EXPECT_FALSE(shelf->IsShelfHiddenBehindBlackBar());
 
   // First test that with no maximized window we show/hide the shelf.
-  StartUserTransitionAnimation("B");
+  StartUserTransitionAnimation(account_id_B);
   EXPECT_FALSE(shelf->IsShelfHiddenBehindBlackBar());
   EXPECT_EQ(ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN,
             ash::Shell::GetInstance()->GetShelfAutoHideBehavior(root_window));
@@ -1239,7 +1328,7 @@
 
   // Start the animation and see that the shelf gets hidden by the black bar,
   // and the AutoHide behavior remains as it was.
-  StartUserTransitionAnimation("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_TRUE(shelf->IsShelfHiddenBehindBlackBar());
   EXPECT_NE(ash::SHELF_AUTO_HIDE_ALWAYS_HIDDEN,
             ash::Shell::GetInstance()->GetShelfAutoHideBehavior(root_window));
@@ -1263,6 +1352,9 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, TransientWindowActivationTest) {
   SetUpForThisManyWindows(3);
 
+  const AccountId account_id_A(AccountId::FromUserEmail("A"));
+  const AccountId account_id_B(AccountId::FromUserEmail("B"));
+
   // Create a window hierarchy like this:
   // 0 (A)          - The normal windows
   // |
@@ -1270,7 +1362,7 @@
   // |
   // 2              - A transient child of a transient child.
 
-  multi_user_window_manager()->SetWindowOwner(window(0), "A");
+  multi_user_window_manager()->SetWindowOwner(window(0), account_id_A);
 
   ::wm::AddTransientChild(window(0), window(1));
   window(1)->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_WINDOW);
@@ -1288,10 +1380,10 @@
   EXPECT_FALSE(::wm::CanActivateWindow(window(1)));
 
   // Change active user to User B.
-  multi_user_window_manager()->ActiveUserChanged("B");
+  StartUserTransitionAnimation(account_id_B);
 
   // Change active user back to User A.
-  multi_user_window_manager()->ActiveUserChanged("A");
+  StartUserTransitionAnimation(account_id_A);
   EXPECT_EQ(window(2), activation_client->GetActiveWindow());
   EXPECT_FALSE(::wm::CanActivateWindow(window(0)));
   EXPECT_FALSE(::wm::CanActivateWindow(window(1)));
@@ -1313,8 +1405,8 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, MinimizedWindowActivatableTests) {
   SetUpForThisManyWindows(4);
 
-  const std::string user1 = "a@test.com";
-  const std::string user2 = "b@test.com";
+  const AccountId user1(AccountId::FromUserEmail("a@test.com"));
+  const AccountId user2(AccountId::FromUserEmail("b@test.com"));
   AddTestUser(user1);
   AddTestUser(user2);
   session_state_delegate()->set_logged_in_users(2);
@@ -1329,7 +1421,7 @@
   wm::GetWindowState(window(2))->Minimize();
 
   // Windows belonging to user2 (window #2 and #3) can't be activated by user1.
-  user_manager()->SwitchActiveUser(AccountId::FromUserEmail(user1));
+  user_manager()->SwitchActiveUser(user1);
   multi_user_window_manager()->ActiveUserChanged(user1);
   EXPECT_TRUE(::wm::CanActivateWindow(window(0)));
   EXPECT_TRUE(::wm::CanActivateWindow(window(1)));
@@ -1337,7 +1429,7 @@
   EXPECT_FALSE(::wm::CanActivateWindow(window(3)));
 
   // Windows belonging to user1 (window #0 and #1) can't be activated by user2.
-  user_manager()->SwitchActiveUser(AccountId::FromUserEmail(user2));
+  user_manager()->SwitchActiveUser(user2);
   multi_user_window_manager()->ActiveUserChanged(user2);
   EXPECT_FALSE(::wm::CanActivateWindow(window(0)));
   EXPECT_FALSE(::wm::CanActivateWindow(window(1)));
@@ -1349,8 +1441,8 @@
 TEST_F(MultiUserWindowManagerChromeOSTest, TeleportedWindowActivatableTests) {
   SetUpForThisManyWindows(2);
 
-  const std::string user1 = "a@test.com";
-  const std::string user2 = "b@test.com";
+  const AccountId user1(AccountId::FromUserEmail("a@test.com"));
+  const AccountId user2(AccountId::FromUserEmail("b@test.com"));
   AddTestUser(user1);
   AddTestUser(user2);
   session_state_delegate()->set_logged_in_users(2);
@@ -1358,7 +1450,7 @@
   multi_user_window_manager()->SetWindowOwner(window(0), user1);
   multi_user_window_manager()->SetWindowOwner(window(1), user2);
 
-  user_manager()->SwitchActiveUser(AccountId::FromUserEmail(user1));
+  user_manager()->SwitchActiveUser(user1);
   multi_user_window_manager()->ActiveUserChanged(user1);
   EXPECT_TRUE(::wm::CanActivateWindow(window(0)));
   EXPECT_FALSE(::wm::CanActivateWindow(window(1)));
@@ -1369,7 +1461,7 @@
   EXPECT_FALSE(::wm::CanActivateWindow(window(0)));
 
   // Test that window #0 can be activated by user2.
-  user_manager()->SwitchActiveUser(AccountId::FromUserEmail(user2));
+  user_manager()->SwitchActiveUser(user2);
   multi_user_window_manager()->ActiveUserChanged(user2);
   EXPECT_TRUE(::wm::CanActivateWindow(window(0)));
   EXPECT_TRUE(::wm::CanActivateWindow(window(1)));
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
index 0fcf0ce..e7d4d41f 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.cc
@@ -6,21 +6,23 @@
 
 #include "base/logging.h"
 #include "base/strings/string_util.h"
+#include "components/signin/core/account_id/account_id.h"
 
 namespace chrome {
 
 void MultiUserWindowManagerStub::SetWindowOwner(aura::Window* window,
-                                               const std::string& user_id) {
+                                                const AccountId& account_id) {
   NOTIMPLEMENTED();
 }
 
-const std::string& MultiUserWindowManagerStub::GetWindowOwner(
+const AccountId& MultiUserWindowManagerStub::GetWindowOwner(
     aura::Window* window) const {
-  return base::EmptyString();
+  return EmptyAccountId();
 }
 
-void MultiUserWindowManagerStub::ShowWindowForUser(aura::Window* window,
-                                                  const std::string& user_id) {
+void MultiUserWindowManagerStub::ShowWindowForUser(
+    aura::Window* window,
+    const AccountId& account_id) {
   NOTIMPLEMENTED();
 }
 
@@ -29,18 +31,17 @@
 }
 
 void MultiUserWindowManagerStub::GetOwnersOfVisibleWindows(
-    std::set<std::string>* user_ids) const {
-}
+    std::set<AccountId>* account_ids) const {}
 
 bool MultiUserWindowManagerStub::IsWindowOnDesktopOfUser(
     aura::Window* window,
-    const std::string& user_id) const {
+    const AccountId& account_id) const {
   return true;
 }
 
-const std::string& MultiUserWindowManagerStub::GetUserPresentingWindow(
+const AccountId& MultiUserWindowManagerStub::GetUserPresentingWindow(
     aura::Window* window) const {
-  return base::EmptyString();
+  return EmptyAccountId();
 }
 
 void MultiUserWindowManagerStub::AddUser(content::BrowserContext* context) {
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.h
index 46df924..f7f7faf 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_stub.h
@@ -12,6 +12,8 @@
 #include "base/compiler_specific.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 
+class AccountId;
+
 namespace chrome {
 
 // This is the implementation of MultiUserWindowManager for single user mode.
@@ -22,17 +24,16 @@
 
   // MultiUserWindowManager overrides:
   void SetWindowOwner(aura::Window* window,
-                      const std::string& user_id) override;
-  const std::string& GetWindowOwner(aura::Window* window) const override;
+                      const AccountId& account_id) override;
+  const AccountId& GetWindowOwner(aura::Window* window) const override;
   void ShowWindowForUser(aura::Window* window,
-                         const std::string& user_id) override;
+                         const AccountId& account_id) override;
   bool AreWindowsSharedAmongUsers() const override;
   void GetOwnersOfVisibleWindows(
-      std::set<std::string>* user_ids) const override;
+      std::set<AccountId>* account_ids) const override;
   bool IsWindowOnDesktopOfUser(aura::Window* window,
-                               const std::string& user_id) const override;
-  const std::string& GetUserPresentingWindow(
-      aura::Window* window) const override;
+                               const AccountId& account_id) const override;
+  const AccountId& GetUserPresentingWindow(aura::Window* window) const override;
   void AddUser(content::BrowserContext* context) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
index 4b39f93..c4d1227 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.cc
@@ -6,18 +6,19 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/aura/window.h"
 
 TestMultiUserWindowManager::TestMultiUserWindowManager(
     Browser* visiting_browser,
-    const std::string& desktop_owner)
+    const AccountId& desktop_owner)
     : browser_window_(visiting_browser->window()->GetNativeWindow()),
-      browser_owner_(
-          multi_user_util::GetUserIDFromProfile(visiting_browser->profile())),
+      browser_owner_(multi_user_util::GetAccountIdFromProfile(
+          visiting_browser->profile())),
       desktop_owner_(desktop_owner),
       created_window_(NULL),
       created_window_shown_for_(browser_owner_),
-      current_user_id_(desktop_owner) {
+      current_account_id_(desktop_owner) {
   // Register this object with the system (which will take ownership). It will
   // be deleted by ChromeLauncherController::~ChromeLauncherController().
   chrome::MultiUserWindowManager::SetInstanceForTest(
@@ -29,37 +30,39 @@
   // SetInstanceForTest call. As such no uninstall is required.
 }
 
-void TestMultiUserWindowManager::SetWindowOwner(aura::Window* window,
-                                                const std::string& user_id) {
+void TestMultiUserWindowManager::SetWindowOwner(
+    aura::Window* window,
+    const AccountId& account_id) {
   NOTREACHED();
 }
 
-const std::string& TestMultiUserWindowManager::GetWindowOwner(
+const AccountId& TestMultiUserWindowManager::GetWindowOwner(
     aura::Window* window) const {
   // No matter which window will get queried - all browsers belong to the
   // original browser's user.
   return browser_owner_;
 }
 
-void TestMultiUserWindowManager::ShowWindowForUser(aura::Window* window,
-                                                   const std::string& user_id) {
+void TestMultiUserWindowManager::ShowWindowForUser(
+    aura::Window* window,
+    const AccountId& account_id) {
   // This class is only able to handle one additional window <-> user
   // association beside the creation parameters.
   // If no association has yet been requested remember it now.
   DCHECK(!created_window_);
   created_window_ = window;
-  created_window_shown_for_ = user_id;
+  created_window_shown_for_ = account_id;
 
   if (browser_window_ == window)
-    desktop_owner_ = user_id;
+    desktop_owner_ = account_id;
 
-  if (user_id == current_user_id_)
+  if (account_id == current_account_id_)
     return;
 
   // Change the visibility of the window to update the view recursively.
   window->Hide();
   window->Show();
-  current_user_id_ = user_id;
+  current_account_id_ = account_id;
 }
 
 bool TestMultiUserWindowManager::AreWindowsSharedAmongUsers() const {
@@ -67,16 +70,15 @@
 }
 
 void TestMultiUserWindowManager::GetOwnersOfVisibleWindows(
-    std::set<std::string>* user_ids) const {
-}
+    std::set<AccountId>* account_ids) const {}
 
 bool TestMultiUserWindowManager::IsWindowOnDesktopOfUser(
     aura::Window* window,
-    const std::string& user_id) const {
-  return GetUserPresentingWindow(window) == user_id;
+    const AccountId& account_id) const {
+  return GetUserPresentingWindow(window) == account_id;
 }
 
-const std::string& TestMultiUserWindowManager::GetUserPresentingWindow(
+const AccountId& TestMultiUserWindowManager::GetUserPresentingWindow(
     aura::Window* window) const {
   if (window == browser_window_)
     return desktop_owner_;
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.h b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.h
index c0f89fff..fcc9033 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.h
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 
 // This is a test implementation of a MultiUserWindowManager which allows to
 // test a visiting window on another desktop. It will install and remove itself
@@ -16,24 +17,23 @@
 class TestMultiUserWindowManager : public chrome::MultiUserWindowManager {
  public:
   TestMultiUserWindowManager(Browser* visiting_browser,
-                             const std::string& desktop_owner);
+                             const AccountId& desktop_owner);
   ~TestMultiUserWindowManager() override;
 
   aura::Window* created_window() { return created_window_; }
 
   // MultiUserWindowManager overrides:
   void SetWindowOwner(aura::Window* window,
-                      const std::string& user_id) override;
-  const std::string& GetWindowOwner(aura::Window* window) const override;
+                      const AccountId& account_id) override;
+  const AccountId& GetWindowOwner(aura::Window* window) const override;
   void ShowWindowForUser(aura::Window* window,
-                         const std::string& user_id) override;
+                         const AccountId& account_id) override;
   bool AreWindowsSharedAmongUsers() const override;
   void GetOwnersOfVisibleWindows(
-      std::set<std::string>* user_ids) const override;
+      std::set<AccountId>* account_ids) const override;
   bool IsWindowOnDesktopOfUser(aura::Window* window,
-                               const std::string& user_id) const override;
-  const std::string& GetUserPresentingWindow(
-      aura::Window* window) const override;
+                               const AccountId& account_id) const override;
+  const AccountId& GetUserPresentingWindow(aura::Window* window) const override;
   void AddUser(content::BrowserContext* profile) override;
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
@@ -42,15 +42,15 @@
   // The window of the visiting browser.
   aura::Window* browser_window_;
   // The owner of the visiting browser.
-  std::string browser_owner_;
+  AccountId browser_owner_;
   // The owner of the currently shown desktop.
-  std::string desktop_owner_;
+  AccountId desktop_owner_;
   // The created window.
   aura::Window* created_window_;
   // The location of the window.
-  std::string created_window_shown_for_;
+  AccountId created_window_shown_for_;
   // The current selected active user.
-  std::string current_user_id_;
+  AccountId current_account_id_;
 
   DISALLOW_COPY_AND_ASSIGN(TestMultiUserWindowManager);
 };
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
index 5c49d80..4f194dd 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.cc
@@ -102,14 +102,14 @@
 
 UserSwitchAnimatorChromeOS::UserSwitchAnimatorChromeOS(
     MultiUserWindowManagerChromeOS* owner,
-    const std::string& new_user_id,
+    const AccountId& new_account_id,
     int animation_speed_ms)
     : owner_(owner),
-      new_user_id_(new_user_id),
+      new_account_id_(new_account_id),
       animation_speed_ms_(animation_speed_ms),
       animation_step_(ANIMATION_STEP_HIDE_OLD_USER),
       screen_cover_(GetScreenCover(NULL)),
-      windows_by_user_id_() {
+      windows_by_account_id_() {
   BuildUserToWindowsListMap();
   AdvanceUserTransitionAnimation();
 
@@ -193,20 +193,22 @@
     wallpaper_delegate->SetAnimationDurationOverride(
         std::max(duration, kMinimalAnimationTimeMS));
     if (screen_cover_ != NEW_USER_COVERS_SCREEN) {
-      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_user_id_);
-      wallpaper_user_id_ =
+      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(
+          new_account_id_.GetUserEmail());
+      wallpaper_user_id_for_test_ =
           (NO_USER_COVERS_SCREEN == screen_cover_ ? "->" : "") +
-          new_user_id_;
+          new_account_id_.GetUserEmail();
     }
   } else if (animation_step == ANIMATION_STEP_FINALIZE) {
     // Revert the wallpaper cross dissolve animation duration back to the
     // default.
     if (screen_cover_ == NEW_USER_COVERS_SCREEN)
-      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(new_user_id_);
+      chromeos::WallpaperManager::Get()->SetUserWallpaperNow(
+          new_account_id_.GetUserEmail());
 
     // Coming here the wallpaper user id is the final result. No matter how we
     // got here.
-    wallpaper_user_id_ = new_user_id_;
+    wallpaper_user_id_for_test_ = new_account_id_.GetUserEmail();
     wallpaper_delegate->SetAnimationDurationOverride(0);
   }
 }
@@ -221,7 +223,8 @@
   if (animation_step == ANIMATION_STEP_SHOW_NEW_USER) {
     // Some unit tests have no ChromeLauncherController.
     if (chrome_launcher_controller)
-      chrome_launcher_controller->ActiveUserChanged(new_user_id_);
+      chrome_launcher_controller->ActiveUserChanged(
+          new_account_id_.GetUserEmail());
     // Hide the black rectangle on top of each shelf again.
     aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
     for (aura::Window::Windows::const_iterator iter = root_windows.begin();
@@ -265,7 +268,7 @@
     if (GetScreenCover(*iter) != NO_USER_COVERS_SCREEN &&
         (!chrome_launcher_controller ||
          !chrome_launcher_controller->ShelfBoundsChangesProbablyWithUser(
-             *iter, new_user_id_))) {
+             *iter, new_account_id_.GetUserEmail()))) {
       ash::ShelfWidget* shelf =
           ash::RootWindowController::ForWindow(*iter)->shelf();
       shelf->HideShelfBehindBlackBar(true, duration_override);
@@ -290,9 +293,9 @@
   switch (animation_step) {
     case ANIMATION_STEP_HIDE_OLD_USER: {
       // Hide the old users.
-      for (auto& user_pair : windows_by_user_id_) {
-        auto& show_for_user_id = user_pair.first;
-        if (show_for_user_id == new_user_id_)
+      for (auto& user_pair : windows_by_account_id_) {
+        auto& show_for_account_id = user_pair.first;
+        if (show_for_account_id == new_account_id_)
           continue;
 
         bool found_foreground_maximized_window = false;
@@ -307,12 +310,13 @@
           auto window_state = ash::wm::GetWindowState(window);
 
           // Minimized visiting windows (minimized windows with an owner
-          // different than that of the for_show_user_id) should retrun to their
+          // different than that of the for_show_account_id) should retrun to
+          // their
           // original owners' desktops.
           MultiUserWindowManagerChromeOS::WindowToEntryMap::const_iterator itr =
               owner_->window_to_entry().find(window);
           DCHECK(itr != owner_->window_to_entry().end());
-          if (show_for_user_id != itr->second->owner() &&
+          if (show_for_account_id != itr->second->owner() &&
               window_state->IsMinimized()) {
             owner_->ShowWindowForUserIntern(window, itr->second->owner());
             window_state->Unminimize();
@@ -342,8 +346,8 @@
       }
 
       // Show new user.
-      auto new_user_itr = windows_by_user_id_.find(new_user_id_);
-      if (new_user_itr == windows_by_user_id_.end())
+      auto new_user_itr = windows_by_account_id_.find(new_account_id_);
+      if (new_user_itr == windows_by_account_id_.end())
         return;
 
       for (auto& window : new_user_itr->second) {
@@ -369,7 +373,7 @@
       if (!mru_list.empty()) {
         aura::Window* window = mru_list[0];
         ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
-        if (owner_->IsWindowOnDesktopOfUser(window, new_user_id_) &&
+        if (owner_->IsWindowOnDesktopOfUser(window, new_account_id_) &&
             !window_state->IsMinimized()) {
           // Several unit tests come here without an activation client.
           aura::client::ActivationClient* client =
@@ -388,7 +392,7 @@
           client->ActivateWindow(nullptr);
       }
 
-      owner_->notification_blocker()->ActiveUserChanged(new_user_id_);
+      owner_->notification_blocker()->ActiveUserChanged(new_account_id_);
       break;
     }
     case ANIMATION_STEP_ENDED:
@@ -412,7 +416,7 @@
         return BOTH_USERS_COVER_SCREEN;
       else
         cover = OLD_USER_COVERS_SCREEN;
-    } else if (owner_->IsWindowOnDesktopOfUser(window, new_user_id_) &&
+    } else if (owner_->IsWindowOnDesktopOfUser(window, new_account_id_) &&
                CoversScreen(window)) {
       if (cover == OLD_USER_COVERS_SCREEN)
         return BOTH_USERS_COVER_SCREEN;
@@ -425,11 +429,11 @@
 
 void UserSwitchAnimatorChromeOS::BuildUserToWindowsListMap() {
   // This is to be called only at the time this animation is constructed.
-  DCHECK(windows_by_user_id_.empty());
+  DCHECK(windows_by_account_id_.empty());
 
   // For each unique parent window, we enumerate its children windows, and
   // for each child if it's in the |window_to_entry()| map, we add it to the
-  // |windows_by_user_id_| map.
+  // |windows_by_account_id_| map.
   // This gives us a list of windows per each user that is in the same order
   // they were created in their parent windows.
   std::set<aura::Window*> parent_windows;
@@ -441,7 +445,7 @@
       for (auto& child_window : parent_window->children()) {
         auto itr = window_to_entry_map.find(child_window);
         if (itr != window_to_entry_map.end()) {
-          windows_by_user_id_[itr->second->show_for_user()].push_back(
+          windows_by_account_id_[itr->second->show_for_user()].push_back(
               child_window);
         }
       }
diff --git a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h
index e3e627a..76e67ca9 100644
--- a/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h
+++ b/chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h
@@ -10,6 +10,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/timer/timer.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "ui/aura/window.h"
 
 namespace chrome {
@@ -32,7 +33,7 @@
   };
 
   UserSwitchAnimatorChromeOS(MultiUserWindowManagerChromeOS* owner,
-                             const std::string& new_user_id,
+                             const AccountId& new_account_id,
                              int animation_speed_ms);
   ~UserSwitchAnimatorChromeOS();
 
@@ -45,7 +46,9 @@
 
   // Returns the user id for which the wallpaper is currently shown.
   // If a wallpaper is transitioning to B it will be returned as "->B".
-  const std::string& wallpaper_user_id_for_test() { return wallpaper_user_id_; }
+  const std::string& wallpaper_user_id_for_test() {
+    return wallpaper_user_id_for_test_;
+  }
 
   // Advances the user switch animation to the next step. It reads the current
   // step from |animation_step_| and increments it thereafter. When
@@ -95,7 +98,7 @@
   MultiUserWindowManagerChromeOS* owner_;
 
   // The new user to set.
-  std::string new_user_id_;
+  AccountId new_account_id_;
 
   // The animation speed in ms. If 0, animations are disabled.
   int animation_speed_ms_;
@@ -107,15 +110,15 @@
   TransitioningScreenCover screen_cover_;
 
   // Mapping users IDs to the list of windows to show for these users.
-  typedef std::map<std::string, aura::Window::Windows> UserToWindowsMap;
-  UserToWindowsMap windows_by_user_id_;
+  typedef std::map<AccountId, aura::Window::Windows> UserToWindowsMap;
+  UserToWindowsMap windows_by_account_id_;
 
   // A timer which watches to executes the second part of a "user changed"
   // animation. Note that this timer exists only during such an animation.
   scoped_ptr<base::Timer> user_changed_animation_timer_;
 
   // For unit tests: Check which wallpaper was set.
-  std::string wallpaper_user_id_;
+  std::string wallpaper_user_id_for_test_;
 
   DISALLOW_COPY_AND_ASSIGN(UserSwitchAnimatorChromeOS);
 };
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
index c37dd6d..662dfcd8 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.cc
@@ -158,14 +158,16 @@
 }
 
 void SessionStateDelegateChromeos::SwitchActiveUser(
-    const std::string& user_id) {
+    const AccountId& account_id) {
   // Disallow switching to an already active user since that might crash.
   // Also check that we got a user id and not an email address.
-  DCHECK_EQ(user_id,
-            gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_id)));
-  if (user_id == user_manager::UserManager::Get()->GetActiveUser()->email())
+  DCHECK_EQ(
+      account_id.GetUserEmail(),
+      gaia::CanonicalizeEmail(gaia::SanitizeEmail(account_id.GetUserEmail())));
+  if (account_id ==
+      user_manager::UserManager::Get()->GetActiveUser()->GetAccountId())
     return;
-  TryToSwitchUser(user_id);
+  TryToSwitchUser(account_id);
 }
 
 void SessionStateDelegateChromeos::CycleActiveUser(CycleUser cycle_user) {
@@ -176,14 +178,14 @@
   const user_manager::UserList& logged_in_users =
       user_manager::UserManager::Get()->GetLoggedInUsers();
 
-  std::string user_id =
-      user_manager::UserManager::Get()->GetActiveUser()->email();
+  AccountId account_id =
+      user_manager::UserManager::Get()->GetActiveUser()->GetAccountId();
 
   // Get an iterator positioned at the active user.
   user_manager::UserList::const_iterator it;
   for (it = logged_in_users.begin();
        it != logged_in_users.end(); ++it) {
-    if ((*it)->email() == user_id)
+    if ((*it)->GetAccountId() == account_id)
       break;
   }
 
@@ -196,19 +198,19 @@
   switch (cycle_user) {
     case CYCLE_TO_NEXT_USER:
       if (++it == logged_in_users.end())
-        user_id = (*logged_in_users.begin())->email();
+        account_id = (*logged_in_users.begin())->GetAccountId();
       else
-        user_id = (*it)->email();
+        account_id = (*it)->GetAccountId();
       break;
     case CYCLE_TO_PREVIOUS_USER:
       if (it == logged_in_users.begin())
         it = logged_in_users.end();
-      user_id = (*(--it))->email();
+      account_id = (*(--it))->GetAccountId();
       break;
   }
 
-  // Switch using the transformed |user_id|.
-  TryToSwitchUser(user_id);
+  // Switch using the transformed |account_id|.
+  TryToSwitchUser(account_id);
 }
 
 bool SessionStateDelegateChromeos::IsMultiProfileAllowedByPrimaryUserPolicy()
@@ -234,16 +236,14 @@
 
 void SessionStateDelegateChromeos::ActiveUserChanged(
     const user_manager::User* active_user) {
-  FOR_EACH_OBSERVER(ash::SessionStateObserver,
-                    session_state_observer_list_,
-                    ActiveUserChanged(active_user->email()));
+  FOR_EACH_OBSERVER(ash::SessionStateObserver, session_state_observer_list_,
+                    ActiveUserChanged(active_user->GetAccountId()));
 }
 
 void SessionStateDelegateChromeos::UserAddedToSession(
     const user_manager::User* added_user) {
-  FOR_EACH_OBSERVER(ash::SessionStateObserver,
-                    session_state_observer_list_,
-                    UserAddedToSession(added_user->email()));
+  FOR_EACH_OBSERVER(ash::SessionStateObserver, session_state_observer_list_,
+                    UserAddedToSession(added_user->GetAccountId()));
 }
 
 void SessionStateDelegateChromeos::OnUserAddingStarted() {
@@ -269,12 +269,11 @@
                     SessionStateChanged(session_state_));
 }
 
-void DoSwitchUser(const std::string& user_id) {
-  user_manager::UserManager::Get()->SwitchActiveUser(
-      AccountId::FromUserEmail(user_id));
+void DoSwitchUser(const AccountId& account_id) {
+  user_manager::UserManager::Get()->SwitchActiveUser(account_id);
 }
 
 void SessionStateDelegateChromeos::TryToSwitchUser(
-    const std::string& user_id) {
-  ash::TrySwitchingActiveUser(base::Bind(&DoSwitchUser, user_id));
+    const AccountId& account_id) {
+  ash::TrySwitchingActiveUser(base::Bind(&DoSwitchUser, account_id));
 }
diff --git a/chrome/browser/ui/ash/session_state_delegate_chromeos.h b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
index bbdf6b2..04ce9a4 100644
--- a/chrome/browser/ui/ash/session_state_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/session_state_delegate_chromeos.h
@@ -42,7 +42,7 @@
       ash::UserIndex index) const override;
   bool ShouldShowAvatar(aura::Window* window) const override;
   gfx::ImageSkia GetAvatarImageForWindow(aura::Window* window) const override;
-  void SwitchActiveUser(const std::string& user_id) override;
+  void SwitchActiveUser(const AccountId& account_id) override;
   void CycleActiveUser(CycleUser cycle_user) override;
   bool IsMultiProfileAllowedByPrimaryUserPolicy() const override;
   void AddSessionStateObserver(ash::SessionStateObserver* observer) override;
@@ -70,7 +70,7 @@
 
   // Switches to a new user. This call might show a dialog asking the user if he
   // wants to stop desktop casting before switching.
-  void TryToSwitchUser(const std::string& user_id);
+  void TryToSwitchUser(const AccountId& account_id);
 
   // List of observers is only used on Chrome OS for now.
   base::ObserverList<ash::SessionStateObserver> session_state_observer_list_;
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.cc b/chrome/browser/ui/ash/session_state_delegate_views.cc
index 5a15ec59..e543b697 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.cc
+++ b/chrome/browser/ui/ash/session_state_delegate_views.cc
@@ -71,7 +71,7 @@
   return gfx::ImageSkia();
 }
 
-void SessionStateDelegate::SwitchActiveUser(const std::string& user_id) {
+void SessionStateDelegate::SwitchActiveUser(const AccountId& account_id) {
   NOTIMPLEMENTED();
 }
 
diff --git a/chrome/browser/ui/ash/session_state_delegate_views.h b/chrome/browser/ui/ash/session_state_delegate_views.h
index c7ebb22..f8b5659 100644
--- a/chrome/browser/ui/ash/session_state_delegate_views.h
+++ b/chrome/browser/ui/ash/session_state_delegate_views.h
@@ -35,7 +35,7 @@
       ash::UserIndex index) const override;
   bool ShouldShowAvatar(aura::Window* window) const override;
   gfx::ImageSkia GetAvatarImageForWindow(aura::Window* window) const override;
-  void SwitchActiveUser(const std::string& user_id) override;
+  void SwitchActiveUser(const AccountId& account_id) override;
   void CycleActiveUser(CycleUser cycle_user) override;
   bool IsMultiProfileAllowedByPrimaryUserPolicy() const override;
   void AddSessionStateObserver(ash::SessionStateObserver* observer) override;
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 55d34c0..b27844c 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -575,10 +575,10 @@
     for (user_manager::UserList::const_iterator it = logged_in_users.begin();
          it != logged_in_users.end();
          ++it) {
-      show_intro &= !multi_user_util::GetProfileFromUserID(
-                         multi_user_util::GetUserIDFromEmail((*it)->email()))
-                         ->GetPrefs()
-                         ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
+      show_intro &=
+          !multi_user_util::GetProfileFromAccountId((*it)->GetAccountId())
+               ->GetPrefs()
+               ->GetBoolean(prefs::kMultiProfileNeverShowIntro);
       if (!show_intro)
         break;
     }
@@ -818,18 +818,19 @@
 
 ash::tray::UserAccountsDelegate*
 SystemTrayDelegateChromeOS::GetUserAccountsDelegate(
-    const std::string& user_id) {
-  if (!accounts_delegates_.contains(user_id)) {
-    const user_manager::User* user = user_manager::UserManager::Get()->FindUser(
-        AccountId::FromUserEmail(user_id));
+    const AccountId& account_id) {
+  auto it = accounts_delegates_.find(account_id);
+  if (it == accounts_delegates_.end()) {
+    const user_manager::User* user =
+        user_manager::UserManager::Get()->FindUser(account_id);
     Profile* user_profile = ProfileHelper::Get()->GetProfileByUserUnsafe(user);
     CHECK(user_profile);
     accounts_delegates_.set(
-        user_id,
-        scoped_ptr<ash::tray::UserAccountsDelegate>(
-            new UserAccountsDelegateChromeOS(user_profile)));
+        account_id, scoped_ptr<ash::tray::UserAccountsDelegate>(
+                        new UserAccountsDelegateChromeOS(user_profile)));
+    it = accounts_delegates_.find(account_id);
   }
-  return accounts_delegates_.get(user_id);
+  return it->second;
 }
 
 void SystemTrayDelegateChromeOS::AddCustodianInfoTrayObserver(
@@ -1253,13 +1254,12 @@
 
 // Overridden from ash::SessionStateObserver
 void SystemTrayDelegateChromeOS::UserAddedToSession(
-    const std::string& user_id) {
+    const AccountId& /*account_id*/) {
   GetSystemTrayNotifier()->NotifyUserAddedToSession();
 }
 
 void SystemTrayDelegateChromeOS::ActiveUserChanged(
-    const std::string& /* user_id */) {
-}
+    const AccountId& /* user_id */) {}
 
 // Overridden from chrome::BrowserListObserver.
 void SystemTrayDelegateChromeOS::OnBrowserRemoved(Browser* browser) {
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
index 2a04e44..1d65136 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.h
@@ -31,6 +31,7 @@
 #include "chromeos/audio/cras_audio_handler.h"
 #include "chromeos/dbus/session_manager_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -136,7 +137,7 @@
   void ActiveUserWasChanged() override;
   bool IsSearchKeyMappedToCapsLock() override;
   ash::tray::UserAccountsDelegate* GetUserAccountsDelegate(
-      const std::string& user_id) override;
+      const AccountId& account_id) override;
   void AddCustodianInfoTrayObserver(
       ash::CustodianInfoTrayObserver* observer) override;
   void RemoveCustodianInfoTrayObserver(
@@ -249,8 +250,8 @@
   void OnStoreError(policy::CloudPolicyStore* store) override;
 
   // Overridden from ash::SessionStateObserver
-  void UserAddedToSession(const std::string& user_id) override;
-  void ActiveUserChanged(const std::string& user_id) override;
+  void UserAddedToSession(const AccountId& account_id) override;
+  void ActiveUserChanged(const AccountId& account_id) override;
 
   // Overridden from chrome::BrowserListObserver:
   void OnBrowserRemoved(Browser* browser) override;
@@ -292,8 +293,7 @@
   scoped_ptr<ash::NetworkingConfigDelegate> networking_config_delegate_;
   scoped_ptr<ash::VolumeControlDelegate> volume_control_delegate_;
   scoped_ptr<AccessibilityStatusSubscription> accessibility_subscription_;
-  base::ScopedPtrHashMap<std::string,
-                         scoped_ptr<ash::tray::UserAccountsDelegate>>
+  base::ScopedPtrMap<AccountId, scoped_ptr<ash::tray::UserAccountsDelegate>>
       accounts_delegates_;
   scoped_ptr<ShutdownPolicyHandler> shutdown_policy_handler_;
   scoped_ptr<ash::VPNDelegate> vpn_delegate_;
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 26a8c50d..43dba05 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -161,7 +161,7 @@
   autofill::SaveCardBubbleControllerImpl* controller =
       autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents());
   controller->SetCallback(callback);
-  controller->ShowBubble();
+  controller->ShowBubble(false);
 #else
   AutofillCCInfoBarDelegate::Create(
       InfoBarService::FromWebContents(web_contents()), this, callback);
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
index 2e43699e..b7a80429 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.cc
@@ -34,7 +34,7 @@
 
 SaveCardBubbleControllerImpl::~SaveCardBubbleControllerImpl() {
   if (save_card_bubble_view_)
-    save_card_bubble_view_->ControllerGone();
+    save_card_bubble_view_->Hide();
 }
 
 void SaveCardBubbleControllerImpl::SetCallback(
@@ -42,7 +42,7 @@
   save_card_callback_ = save_card_callback;
 }
 
-void SaveCardBubbleControllerImpl::ShowBubble() {
+void SaveCardBubbleControllerImpl::ShowBubble(bool user_action) {
   DCHECK(!save_card_callback_.is_null());
 
   // Need to create location bar icon before bubble, otherwise bubble will be
@@ -50,8 +50,8 @@
   UpdateIcon();
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
-  save_card_bubble_view_ =
-      browser->window()->ShowSaveCreditCardBubble(web_contents(), this);
+  save_card_bubble_view_ = browser->window()->ShowSaveCreditCardBubble(
+      web_contents(), this, user_action);
   DCHECK(save_card_bubble_view_);
 
   // Update icon after creating |save_card_bubble_view_| so that icon will show
@@ -65,10 +65,6 @@
   return !save_card_callback_.is_null();
 }
 
-bool SaveCardBubbleControllerImpl::IsIconToggled() const {
-  return !!save_card_bubble_view_;
-}
-
 SaveCardBubbleView* SaveCardBubbleControllerImpl::save_card_bubble_view()
     const {
   return save_card_bubble_view_;
@@ -119,10 +115,12 @@
 
   // Otherwise, get rid of the bubble and icon.
   save_card_callback_.Reset();
-  if (save_card_bubble_view_)
-    save_card_bubble_view_->Close();
-  else
+  if (save_card_bubble_view_) {
+    save_card_bubble_view_->Hide();
+    OnBubbleClosed();
+  } else {
     UpdateIcon();
+  }
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
index 921b0a6..5368b5f 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_controller_impl.h
@@ -28,15 +28,11 @@
   void SetCallback(const base::Closure& save_card_callback);
 
   // SetCallback() must be called first.
-  void ShowBubble();
+  void ShowBubble(bool user_action);
 
   // Returns true if Omnibox save credit card icon should be visible.
   bool IsIconVisible() const;
 
-  // Returns true if Omnibox save credit card should be shown in its "toggled
-  // on" state.
-  bool IsIconToggled() const;
-
   // Returns nullptr if no bubble is currently shown.
   SaveCardBubbleView* save_card_bubble_view() const;
 
diff --git a/chrome/browser/ui/autofill/save_card_bubble_view.h b/chrome/browser/ui/autofill/save_card_bubble_view.h
index c4410ee..694d6cb 100644
--- a/chrome/browser/ui/autofill/save_card_bubble_view.h
+++ b/chrome/browser/ui/autofill/save_card_bubble_view.h
@@ -13,16 +13,9 @@
 // bubble. This object is responsible for its own lifetime.
 class SaveCardBubbleView {
  public:
-  virtual void Show() = 0;
-  virtual void Close() = 0;
-  virtual void ControllerGone() = 0;
-
- protected:
-  SaveCardBubbleView() {}
-  virtual ~SaveCardBubbleView() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleView);
+  // Called to close the bubble and prevent future callbacks into the
+  // controller.
+  virtual void Hide() = 0;
 };
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 8b7e06b..8c6d72f7 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -816,7 +816,7 @@
   autofill::SaveCardBubbleControllerImpl* controller =
       autofill::SaveCardBubbleControllerImpl::FromWebContents(web_contents);
   DCHECK(controller);
-  controller->ShowBubble();
+  controller->ShowBubble(true);
 }
 #endif
 
diff --git a/chrome/browser/ui/browser_finder.cc b/chrome/browser/ui/browser_finder.cc
index e4198d4..cd485ee 100644
--- a/chrome/browser/ui/browser_finder.cc
+++ b/chrome/browser/ui/browser_finder.cc
@@ -15,6 +15,7 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #endif
 
 using content::WebContents;
@@ -54,11 +55,12 @@
       chrome::MultiUserWindowManager::GetInstance();
   Profile* shown_profile = nullptr;
   if (window_manager) {
-    const std::string& shown_user_id = window_manager->GetUserPresentingWindow(
+    const AccountId& shown_account_id = window_manager->GetUserPresentingWindow(
         browser->window()->GetNativeWindow());
-    shown_profile = shown_user_id.empty()
-                        ? nullptr
-                        : multi_user_util::GetProfileFromUserID(shown_user_id);
+    shown_profile =
+        shown_account_id.is_valid()
+            ? multi_user_util::GetProfileFromAccountId(shown_account_id)
+            : nullptr;
   }
 #endif
 
diff --git a/chrome/browser/ui/browser_finder_chromeos_unittest.cc b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
index 73018399..a05c7ec 100644
--- a/chrome/browser/ui/browser_finder_chromeos_unittest.cc
+++ b/chrome/browser/ui/browser_finder_chromeos_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/test/base/test_browser_window_aura.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 
 namespace test {
 
@@ -35,7 +36,7 @@
   chrome::MultiUserWindowManagerChromeOS* GetUserWindowManager() {
     if (!multi_user_window_manager_) {
       multi_user_window_manager_ =
-          new chrome::MultiUserWindowManagerChromeOS(kTestAccount1);
+          new chrome::MultiUserWindowManagerChromeOS(test_account_id1_);
       multi_user_window_manager_->Init();
       chrome::MultiUserWindowManager::SetInstanceForTest(
           multi_user_window_manager_,
@@ -44,15 +45,20 @@
     return multi_user_window_manager_;
   }
 
+  AccountId test_account_id1_ = EmptyAccountId();
+  AccountId test_account_id2_ = EmptyAccountId();
+
  private:
   void SetUp() override {
     profile_manager_.reset(
         new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
     ASSERT_TRUE(profile_manager_->SetUp());
+    test_account_id1_ = AccountId::FromUserEmail(kTestAccount1);
+    test_account_id2_ = AccountId::FromUserEmail(kTestAccount2);
     profile_manager_->SetLoggedIn(true);
     chromeos::WallpaperManager::Initialize();
     BrowserWithTestWindowTest::SetUp();
-    second_profile_ = CreateMultiUserProfile(kTestAccount2);
+    second_profile_ = CreateMultiUserProfile(test_account_id2_.GetUserEmail());
   }
 
   void TearDown() override {
@@ -66,7 +72,7 @@
   }
 
   TestingProfile* CreateProfile() override {
-    return CreateMultiUserProfile(kTestAccount1);
+    return CreateMultiUserProfile(test_account_id1_.GetUserEmail());
   }
 
   void DestroyProfile(TestingProfile* test_profile) override {
@@ -113,7 +119,7 @@
   scoped_ptr<Browser> browser(
       chrome::CreateBrowserWithAuraTestWindowForParams(nullptr, &params));
   GetUserWindowManager()->SetWindowOwner(browser->window()->GetNativeWindow(),
-                                         kTestAccount1);
+                                         test_account_id1_);
   EXPECT_EQ(1u,
             chrome::GetBrowserCount(profile(), chrome::HOST_DESKTOP_TYPE_ASH));
   EXPECT_TRUE(
@@ -124,7 +130,7 @@
   // Move the browser window to another user's desktop. Then no window should
   // be available for the current profile.
   GetUserWindowManager()->ShowWindowForUser(
-      browser->window()->GetNativeWindow(), kTestAccount2);
+      browser->window()->GetNativeWindow(), test_account_id2_);
   EXPECT_EQ(0u,
             chrome::GetBrowserCount(profile(), chrome::HOST_DESKTOP_TYPE_ASH));
   EXPECT_FALSE(
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index d5573b1..0bbf877a 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -39,6 +39,7 @@
 
 #if defined(USE_ASH)
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
+#include "components/signin/core/account_id/account_id.h"
 #endif
 
 #if defined(USE_AURA)
@@ -446,14 +447,14 @@
     if (manager) {
       aura::Window* src_window = source_browser->window()->GetNativeWindow();
       aura::Window* new_window = params->browser->window()->GetNativeWindow();
-      const std::string& src_user =
+      const AccountId& src_account_id =
           manager->GetUserPresentingWindow(src_window);
-      if (src_user != manager->GetUserPresentingWindow(new_window)) {
+      if (src_account_id != manager->GetUserPresentingWindow(new_window)) {
         // Once the window gets presented, it should be shown on the same
         // desktop as the desktop of the creating browser. Note that this
         // command will not show the window if it wasn't shown yet by the
         // browser creation.
-        manager->ShowWindowForUser(new_window, src_user);
+        manager->ShowWindowForUser(new_window, src_account_id);
       }
     }
   }
diff --git a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
index de7baec..e125acb 100644
--- a/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest_chromeos.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chromeos/chromeos_switches.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "content/public/browser/web_contents.h"
 
 namespace {
@@ -73,9 +74,10 @@
   // Test 1: Test that a browser created from a visiting browser will be on the
   // same visiting desktop.
   {
-    const std::string desktop_user_id = "desktop_user_id@fake.com";
+    const AccountId desktop_account_id(
+        AccountId::FromUserEmail("desktop_user_id@fake.com"));
     TestMultiUserWindowManager* manager =
-        new TestMultiUserWindowManager(browser(), desktop_user_id);
+        new TestMultiUserWindowManager(browser(), desktop_account_id);
 
     EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
 
@@ -92,14 +94,14 @@
 
     aura::Window* created_window = manager->created_window();
     ASSERT_TRUE(created_window);
-    EXPECT_TRUE(manager->IsWindowOnDesktopOfUser(created_window,
-                                                 desktop_user_id));
+    EXPECT_TRUE(
+        manager->IsWindowOnDesktopOfUser(created_window, desktop_account_id));
   }
   // Test 2: Test that a window which is not visiting does not cause an owner
   // assignment of a newly created browser.
   {
-    std::string browser_owner =
-        multi_user_util::GetUserIDFromProfile(browser()->profile());
+    const AccountId browser_owner =
+        multi_user_util::GetAccountIdFromProfile(browser()->profile());
     TestMultiUserWindowManager* manager =
         new TestMultiUserWindowManager(browser(), browser_owner);
 
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 784bc75..26480f02 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -253,7 +253,8 @@
   // Shows the "Save credit card" bubble.
   virtual autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
       content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller) = 0;
+      autofill::SaveCardBubbleController* controller,
+      bool is_user_gesture) = 0;
 
   // Shows the translate bubble.
   //
diff --git a/chrome/browser/ui/chrome_bubble_manager.cc b/chrome/browser/ui/chrome_bubble_manager.cc
index 0c346dd..33890dc 100644
--- a/chrome/browser/ui/chrome_bubble_manager.cc
+++ b/chrome/browser/ui/chrome_bubble_manager.cc
@@ -29,6 +29,9 @@
   // Translation-related bubbles:
   BUBBLE_TYPE_TRANSLATE = 20,  // Displays a request to translate a page.
 
+  // Permissions-related bubbles:
+  BUBBLE_TYPE_PERMISSION = 30,  // Displays a permission request to the user.
+
   // Upper boundary for metrics.
   BUBBLE_TYPE_MAX,
 };
@@ -45,6 +48,8 @@
     bubble_type = BUBBLE_TYPE_EXTENSION_INSTALLED;
   else if (bubble->GetName().compare("TranslateBubble") == 0)
     bubble_type = BUBBLE_TYPE_TRANSLATE;
+  else if (bubble->GetName().compare("PermissionBubble") == 0)
+    bubble_type = BUBBLE_TYPE_PERMISSION;
 
   DCHECK_NE(bubble_type, BUBBLE_TYPE_UNKNOWN);
   DCHECK_NE(bubble_type, BUBBLE_TYPE_MAX);
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index cf08dd5..446e98d 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -116,7 +116,8 @@
       const ShowBookmarkAppBubbleCallback& callback) override;
   autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
       content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller) override;
+      autofill::SaveCardBubbleController* controller,
+      bool user_gesture) override;
   void ShowTranslateBubble(content::WebContents* contents,
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index 3b3606a3..3bfa7c3 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -631,7 +631,8 @@
 
 autofill::SaveCardBubbleView* BrowserWindowCocoa::ShowSaveCreditCardBubble(
     content::WebContents* web_contents,
-    autofill::SaveCardBubbleController* controller) {
+    autofill::SaveCardBubbleController* controller,
+    bool user_gesture) {
   NOTIMPLEMENTED();
   return nullptr;
 }
diff --git a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm
index 197f3df1..fb8e64f 100644
--- a/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm
+++ b/chrome/browser/ui/cocoa/exclusive_access_bubble_window_controller.mm
@@ -224,9 +224,9 @@
     exitLinkText = @"";
     exitLinkedText =
         [@" " stringByAppendingString:l10n_util::GetNSStringF(
-                                          IDS_FULLSCREEN_PRESS_ESC_TO_EXIT,
-                                          l10n_util::GetStringUTF16(
-                                              IDS_APP_ESC_KEY))];
+                                      IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_SENTENCE,
+                                      l10n_util::GetStringUTF16(
+                                          IDS_APP_ESC_KEY))];
   } else {
     exitLinkText = l10n_util::GetNSString(IDS_EXIT_FULLSCREEN_MODE);
     NSString* messageText = l10n_util::GetNSStringF(
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
index 2d0233c..abf28c2 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.cc
@@ -165,6 +165,12 @@
 }
 
 base::string16 ExclusiveAccessBubble::GetInstructionText() const {
+  if (!ExclusiveAccessManager::IsSimplifiedFullscreenUIEnabled()) {
+    return l10n_util::GetStringFUTF16(
+        IDS_FULLSCREEN_PRESS_ESC_TO_EXIT_SENTENCE,
+        l10n_util::GetStringUTF16(IDS_APP_ESC_KEY));
+  }
+
   return l10n_util::GetStringFUTF16(IDS_FULLSCREEN_PRESS_ESC_TO_EXIT,
                                     l10n_util::GetStringUTF16(IDS_APP_ESC_KEY));
 }
diff --git a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
index 90e4816..de663813 100644
--- a/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
+++ b/chrome/browser/ui/exclusive_access/exclusive_access_bubble.h
@@ -90,6 +90,8 @@
   base::string16 GetCurrentAllowButtonText() const;
 
   // The following strings never change.
+  // This string *may* contain the name of the key surrounded in pipe characters
+  // ('|'), which should be drawn graphically as a key, not displayed literally.
   base::string16 GetInstructionText() const;
 
   // The Manager associated with this bubble.
diff --git a/chrome/browser/ui/login/login_prompt.cc b/chrome/browser/ui/login/login_prompt.cc
index 6f69a2b..f810175 100644
--- a/chrome/browser/ui/login/login_prompt.cc
+++ b/chrome/browser/ui/login/login_prompt.cc
@@ -236,7 +236,7 @@
 }
 
 password_manager::PasswordManager* LoginHandler::GetPasswordManagerForLogin() {
-  ChromePasswordManagerClient* client =
+  password_manager::PasswordManagerClient* client =
       ChromePasswordManagerClient::FromWebContents(GetWebContentsForLogin());
   return client ? client->GetPasswordManager() : nullptr;
 }
diff --git a/chrome/browser/ui/passwords/manage_passwords_icon.h b/chrome/browser/ui/passwords/manage_passwords_icon.h
index e9329c7e..64ec3c8 100644
--- a/chrome/browser/ui/passwords/manage_passwords_icon.h
+++ b/chrome/browser/ui/passwords/manage_passwords_icon.h
@@ -19,7 +19,7 @@
   void SetState(password_manager::ui::State state) override;
   password_manager::ui::State state() const { return state_; }
 
-  void SetActive(bool active) override;
+  void SetActive(bool active);
   bool active() const { return active_; }
 
  protected:
diff --git a/chrome/browser/ui/passwords/manage_passwords_icon_view.h b/chrome/browser/ui/passwords/manage_passwords_icon_view.h
index 7645742..c0b2df0 100644
--- a/chrome/browser/ui/passwords/manage_passwords_icon_view.h
+++ b/chrome/browser/ui/passwords/manage_passwords_icon_view.h
@@ -14,7 +14,6 @@
   ManagePasswordsIconView() {}
 
   virtual void SetState(password_manager::ui::State state) = 0;
-  virtual void SetActive(bool active) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ManagePasswordsIconView);
diff --git a/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc
index eb67b34..b4bdb66 100644
--- a/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_state_unittest.cc
@@ -25,11 +25,21 @@
 
 namespace {
 
+class MockPasswordManagerClient
+    : public password_manager::StubPasswordManagerClient {
+ public:
+  MOCK_CONST_METHOD0(GetPasswordManager,
+                     const password_manager::PasswordManager*());
+};
+
 class ManagePasswordsStateTest : public testing::Test {
  public:
-  ManagePasswordsStateTest() : password_manager_(&client_) {}
+  ManagePasswordsStateTest() : password_manager_(&mock_client_) {}
 
   void SetUp() override {
+    ON_CALL(mock_client_, GetPasswordManager())
+        .WillByDefault(testing::Return(&password_manager_));
+
     test_local_form_.origin = GURL("http://example.com");
     test_local_form_.username_value = base::ASCIIToUTF16("username");
     test_local_form_.password_value = base::ASCIIToUTF16("12345");
@@ -41,7 +51,7 @@
     test_federated_form_.origin = GURL("https://idp.com");
     test_federated_form_.username_value = base::ASCIIToUTF16("username");
 
-    passwords_data_.set_client(&client_);
+    passwords_data_.set_client(&mock_client_);
   }
 
   autofill::PasswordForm& test_local_form() { return test_local_form_; }
@@ -66,7 +76,7 @@
                void(const password_manager::CredentialInfo&));
 
  private:
-  password_manager::StubPasswordManagerClient client_;
+  MockPasswordManagerClient mock_client_;
   password_manager::StubPasswordManagerDriver driver_;
   password_manager::PasswordManager password_manager_;
 
@@ -79,9 +89,9 @@
 scoped_ptr<password_manager::PasswordFormManager>
 ManagePasswordsStateTest::CreateFormManager() {
   scoped_ptr<password_manager::PasswordFormManager> test_form_manager(
-      new password_manager::PasswordFormManager(&password_manager_, &client_,
-                                                driver_.AsWeakPtr(),
-                                                test_local_form(), false));
+      new password_manager::PasswordFormManager(
+          &password_manager_, &mock_client_, driver_.AsWeakPtr(),
+          test_local_form(), false));
   test_form_manager->SimulateFetchMatchingLoginsFromPasswordStore();
   ScopedVector<autofill::PasswordForm> stored_forms;
   stored_forms.push_back(new autofill::PasswordForm(test_local_form()));
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.cc b/chrome/browser/ui/passwords/manage_passwords_test.cc
index 8d30573d..13634587 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_test.cc
@@ -16,6 +16,7 @@
 #include "chrome/test/base/interactive_test_utils.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_form_manager.h"
+#include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
@@ -54,9 +55,10 @@
 void ManagePasswordsTest::SetupPendingPassword() {
   password_manager::StubPasswordManagerClient client;
   password_manager::StubPasswordManagerDriver driver;
+  password_manager::PasswordManager password_manager(&client);
   scoped_ptr<password_manager::PasswordFormManager> test_form_manager(
       new password_manager::PasswordFormManager(
-          NULL, &client, driver.AsWeakPtr(), *test_form(), false));
+          &password_manager, &client, driver.AsWeakPtr(), *test_form(), false));
   test_form_manager->SimulateFetchMatchingLoginsFromPasswordStore();
   ScopedVector<autofill::PasswordForm> best_matches;
   test_form_manager->OnGetPasswordStoreResults(best_matches.Pass());
@@ -66,9 +68,10 @@
 void ManagePasswordsTest::SetupAutomaticPassword() {
   password_manager::StubPasswordManagerClient client;
   password_manager::StubPasswordManagerDriver driver;
+  password_manager::PasswordManager password_manager(&client);
   scoped_ptr<password_manager::PasswordFormManager> test_form_manager(
       new password_manager::PasswordFormManager(
-          NULL, &client, driver.AsWeakPtr(), *test_form(), false));
+          &password_manager, &client, driver.AsWeakPtr(), *test_form(), false));
   GetController()->OnAutomaticPasswordSave(test_form_manager.Pass());
 }
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.cc
index 9c09b94a..611f739 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.cc
@@ -5,10 +5,31 @@
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
 
 #include "components/password_manager/core/browser/password_form_manager.h"
+#include "components/password_manager/core/browser/password_manager.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
 #include "content/public/browser/web_contents.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+
+class MockPasswordManagerDriver
+    : public password_manager::StubPasswordManagerDriver {
+ public:
+  MOCK_METHOD0(GetPasswordManager, password_manager::PasswordManager*());
+};
+
+class MockPasswordManagerClient
+    : public password_manager::StubPasswordManagerClient {
+ public:
+  MOCK_CONST_METHOD0(GetPasswordManager,
+                     const password_manager::PasswordManager*());
+};
+
+}  // namespace
+
 ManagePasswordsUIControllerMock::ManagePasswordsUIControllerMock(
     content::WebContents* contents)
     : ManagePasswordsUIController(contents),
@@ -18,13 +39,24 @@
       never_saved_password_(false),
       choose_credential_(false),
       state_overridden_(false),
-      state_(password_manager::ui::INACTIVE_STATE),
-      password_manager_(&client_) {
+      state_(password_manager::ui::INACTIVE_STATE) {
   // Do not silently replace an existing ManagePasswordsUIController because it
   // unregisters itself in WebContentsDestroyed().
   EXPECT_FALSE(contents->GetUserData(UserDataKey()));
   contents->SetUserData(UserDataKey(), this);
-  set_client(&client_);
+  scoped_ptr<MockPasswordManagerClient> mock_client(
+      new MockPasswordManagerClient());
+  scoped_ptr<MockPasswordManagerDriver> mock_driver(
+      new MockPasswordManagerDriver());
+  password_manager_.reset(
+      new password_manager::PasswordManager(mock_client.get()));
+  ON_CALL(*mock_driver, GetPasswordManager())
+      .WillByDefault(testing::Return(password_manager_.get()));
+  ON_CALL(*mock_client, GetPasswordManager())
+      .WillByDefault(testing::Return(password_manager_.get()));
+  client_ = mock_client.Pass();
+  driver_ = mock_driver.Pass();
+  set_client(client_.get());
 }
 
 ManagePasswordsUIControllerMock::
@@ -93,9 +125,9 @@
   ASSERT_FALSE(best_matches.empty());
   autofill::PasswordForm observed_form = *best_matches[0];
   scoped_ptr<password_manager::PasswordFormManager> form_manager(
-      new password_manager::PasswordFormManager(&password_manager_, &client_,
-                                                driver_.AsWeakPtr(),
-                                                observed_form, true));
+      new password_manager::PasswordFormManager(
+          password_manager_.get(), client_.get(), driver_->AsWeakPtr(),
+          observed_form, true));
   form_manager->SimulateFetchMatchingLoginsFromPasswordStore();
   form_manager->OnGetPasswordStoreResults(best_matches.Pass());
   OnPasswordSubmitted(form_manager.Pass());
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h b/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h
index 5fad88b..7e4cfb0 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h
@@ -6,10 +6,8 @@
 #define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_UI_CONTROLLER_MOCK_H_
 
 #include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
-#include "components/password_manager/core/browser/password_manager.h"
-#include "components/password_manager/core/browser/stub_password_manager_client.h"
-#include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/common/password_manager_ui.h"
 #include "content/public/browser/navigation_details.h"
 
@@ -18,6 +16,9 @@
 }  // namespace content
 
 namespace password_manager {
+class PasswordManager;
+class PasswordManagerClient;
+class PasswordManagerDriver;
 enum class CredentialType;
 }
 
@@ -88,9 +89,9 @@
   autofill::PasswordForm chosen_credential_;
   autofill::PasswordForm pending_password_;
 
-  password_manager::StubPasswordManagerClient client_;
-  password_manager::StubPasswordManagerDriver driver_;
-  password_manager::PasswordManager password_manager_;
+  scoped_ptr<password_manager::PasswordManagerClient> client_;
+  scoped_ptr<password_manager::PasswordManagerDriver> driver_;
+  scoped_ptr<password_manager::PasswordManager> password_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(ManagePasswordsUIControllerMock);
 };
diff --git a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
index 0be4b106..0a4fa82 100644
--- a/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
+++ b/chrome/browser/ui/passwords/manage_passwords_ui_controller_unittest.cc
@@ -44,14 +44,9 @@
     state_ = state;
   }
   password_manager::ui::State state() { return state_; }
-  void SetActive(bool active) override {
-    active_ = active;
-  }
-  bool active() { return active_; }
 
  private:
   password_manager::ui::State state_;
-  bool active_;
 
   DISALLOW_COPY_AND_ASSIGN(TestManagePasswordsIconView);
 };
@@ -125,19 +120,30 @@
   OnLoginsChanged(list);
 }
 
+// TODO(crbug.com/554886) Centralise mock clients.
+class MockPasswordManagerClient
+    : public password_manager::StubPasswordManagerClient {
+ public:
+  MOCK_CONST_METHOD0(GetPasswordManager,
+                     const password_manager::PasswordManager*());
+};
+
 }  // namespace
 
 class ManagePasswordsUIControllerTest : public ChromeRenderViewHostTestHarness {
  public:
-  ManagePasswordsUIControllerTest() : password_manager_(&client_) {}
+  ManagePasswordsUIControllerTest() : password_manager_(&mock_client_) {}
 
   void SetUp() override {
     ChromeRenderViewHostTestHarness::SetUp();
 
+    ON_CALL(mock_client_, GetPasswordManager())
+        .WillByDefault(testing::Return(&password_manager_));
+
     // Create the test UIController here so that it's bound to
     // |test_web_contents_|, and will be retrieved correctly via
     // ManagePasswordsUIController::FromWebContents in |controller()|.
-    new TestManagePasswordsUIController(web_contents(), &client_);
+    new TestManagePasswordsUIController(web_contents(), &mock_client_);
 
     test_local_form_.origin = GURL("http://example.com");
     test_local_form_.username_value = base::ASCIIToUTF16("username");
@@ -189,7 +195,7 @@
   scoped_ptr<password_manager::PasswordFormManager> CreateFormManager();
 
  private:
-  password_manager::StubPasswordManagerClient client_;
+  MockPasswordManagerClient mock_client_;
   password_manager::StubPasswordManagerDriver driver_;
   password_manager::PasswordManager password_manager_;
 
@@ -203,9 +209,9 @@
     const autofill::PasswordForm& observed_form,
     ScopedVector<autofill::PasswordForm> best_matches) {
   scoped_ptr<password_manager::PasswordFormManager> test_form_manager(
-      new password_manager::PasswordFormManager(&password_manager_, &client_,
-                                                driver_.AsWeakPtr(),
-                                                observed_form, true));
+      new password_manager::PasswordFormManager(
+          &password_manager_, &mock_client_, driver_.AsWeakPtr(), observed_form,
+          true));
   test_form_manager->SimulateFetchMatchingLoginsFromPasswordStore();
   test_form_manager->OnGetPasswordStoreResults(best_matches.Pass());
   return test_form_manager.Pass();
diff --git a/chrome/browser/ui/startup/autolaunch_prompt.cc b/chrome/browser/ui/startup/autolaunch_prompt.cc
deleted file mode 100644
index f67414f..0000000
--- a/chrome/browser/ui/startup/autolaunch_prompt.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/startup/autolaunch_prompt.h"
-
-#include "components/pref_registry/pref_registry_syncable.h"
-
-namespace chrome {
-
-bool ShowAutolaunchPrompt(Browser* browser) {
-  // Autolaunch is only implemented on Windows right now.
-  return false;
-}
-
-void RegisterAutolaunchUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
-  // Autolaunch is only implemented on Windows right now.
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/startup/autolaunch_prompt.h b/chrome/browser/ui/startup/autolaunch_prompt.h
deleted file mode 100644
index e56e3304..0000000
--- a/chrome/browser/ui/startup/autolaunch_prompt.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_STARTUP_AUTOLAUNCH_PROMPT_H_
-#define CHROME_BROWSER_UI_STARTUP_AUTOLAUNCH_PROMPT_H_
-
-class Browser;
-
-namespace user_prefs {
-class PrefRegistrySyncable;
-}
-
-namespace chrome {
-
-// Determines whether or not the auto-launch prompt should be shown, and shows
-// it as needed. Returns true if it was shown, false otherwise.
-bool ShowAutolaunchPrompt(Browser* browser);
-
-// Registers auto-launch specific prefs.
-void RegisterAutolaunchUserPrefs(user_prefs::PrefRegistrySyncable* registry);
-
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_UI_STARTUP_AUTOLAUNCH_PROMPT_H_
diff --git a/chrome/browser/ui/startup/autolaunch_prompt_win.cc b/chrome/browser/ui/startup/autolaunch_prompt_win.cc
deleted file mode 100644
index 039133f..0000000
--- a/chrome/browser/ui/startup/autolaunch_prompt_win.cc
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/startup/autolaunch_prompt.h"
-
-#include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/prefs/pref_service.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/auto_launch_trial.h"
-#include "chrome/browser/first_run/first_run.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/installer/util/auto_launch_util.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-#include "components/infobars/core/infobar.h"
-#include "components/pref_registry/pref_registry_syncable.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
-#include "grit/theme_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-
-// AutolaunchInfoBarDelegate --------------------------------------------------
-
-namespace {
-
-// The delegate for the infobar shown when Chrome is auto-launched.
-class AutolaunchInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  // Creates an autolaunch infobar and delegate and adds the infobar to
-  // |infobar_service|.
-  static void Create(InfoBarService* infobar_service, Profile* profile);
-
- private:
-  explicit AutolaunchInfoBarDelegate(Profile* profile);
-  ~AutolaunchInfoBarDelegate() override;
-
-  void set_should_expire() { should_expire_ = true; }
-
-  // ConfirmInfoBarDelegate:
-  int GetIconId() const override;
-  bool ShouldExpire(const NavigationDetails& details) const override;
-  base::string16 GetMessageText() const override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-
-  // Weak pointer to the profile, not owned by us.
-  Profile* profile_;
-
-  // Whether the info-bar should be dismissed on the next navigation.
-  bool should_expire_;
-
-  // Used to delay the expiration of the info-bar.
-  base::WeakPtrFactory<AutolaunchInfoBarDelegate> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutolaunchInfoBarDelegate);
-};
-
-// static
-void AutolaunchInfoBarDelegate::Create(InfoBarService* infobar_service,
-                                       Profile* profile) {
-  infobar_service->AddInfoBar(
-      infobar_service->CreateConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate>(
-          new AutolaunchInfoBarDelegate(profile))));
-}
-
-AutolaunchInfoBarDelegate::AutolaunchInfoBarDelegate(
-    Profile* profile)
-    : ConfirmInfoBarDelegate(),
-      profile_(profile),
-      should_expire_(false),
-      weak_factory_(this) {
-  PrefService* prefs = profile->GetPrefs();
-  prefs->SetInteger(prefs::kShownAutoLaunchInfobar,
-                    prefs->GetInteger(prefs::kShownAutoLaunchInfobar) + 1);
-
-  // We want the info-bar to stick-around for a few seconds and then be hidden
-  // on the next navigation after that.
-  base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&AutolaunchInfoBarDelegate::set_should_expire,
-                 weak_factory_.GetWeakPtr()),
-      base::TimeDelta::FromSeconds(8));
-}
-
-AutolaunchInfoBarDelegate::~AutolaunchInfoBarDelegate() {
-}
-
-int AutolaunchInfoBarDelegate::GetIconId() const {
-  return IDR_PRODUCT_LOGO_32;
-}
-
-bool AutolaunchInfoBarDelegate::ShouldExpire(
-    const NavigationDetails& details) const {
-  return should_expire_ && ConfirmInfoBarDelegate::ShouldExpire(details);
-}
-
-base::string16 AutolaunchInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringUTF16(IDS_AUTO_LAUNCH_INFOBAR_TEXT);
-}
-
-base::string16 AutolaunchInfoBarDelegate::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
-      IDS_AUTO_LAUNCH_OK : IDS_AUTO_LAUNCH_REVERT);
-}
-
-bool AutolaunchInfoBarDelegate::Accept() {
-  return true;
-}
-
-bool AutolaunchInfoBarDelegate::Cancel() {
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      base::Bind(&auto_launch_util::DisableForegroundStartAtLogin,
-                 profile_->GetPath().BaseName().value()));
-  return true;
-}
-
-}  // namespace
-
-
-// Functions ------------------------------------------------------------------
-
-namespace chrome {
-
-bool ShowAutolaunchPrompt(Browser* browser) {
-  if (!auto_launch_trial::IsInAutoLaunchGroup())
-    return false;
-
-  // Only supported on the main profile for now.
-  Profile* profile = browser->profile();
-  if (profile->GetPath().BaseName() !=
-      base::FilePath(base::ASCIIToUTF16(chrome::kInitialProfile))) {
-    return false;
-  }
-
-  int infobar_shown =
-      profile->GetPrefs()->GetInteger(prefs::kShownAutoLaunchInfobar);
-  const int kMaxTimesToShowInfoBar = 5;
-  if (infobar_shown >= kMaxTimesToShowInfoBar)
-    return false;
-
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (!command_line.HasSwitch(switches::kAutoLaunchAtStartup) &&
-      !first_run::IsChromeFirstRun()) {
-    return false;
-  }
-
-  content::WebContents* web_contents =
-      browser->tab_strip_model()->GetActiveWebContents();
-  AutolaunchInfoBarDelegate::Create(
-      InfoBarService::FromWebContents(web_contents),
-      Profile::FromBrowserContext(web_contents->GetBrowserContext()));
-  return true;
-}
-
-void RegisterAutolaunchUserPrefs(user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterIntegerPref(prefs::kShownAutoLaunchInfobar, 0);
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc b/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
index 379f62ed..1166b2b 100644
--- a/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
+++ b/chrome/browser/ui/startup/obsolete_system_infobar_delegate.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/startup/obsolete_system_infobar_delegate.h"
 
 #include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/chromium_strings.h"
 #include "components/infobars/core/infobar.h"
@@ -12,23 +13,12 @@
 #include "grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_MACOSX)
-#include "chrome/browser/mac/obsolete_system.h"
-#endif
-
 // static
 void ObsoleteSystemInfoBarDelegate::Create(InfoBarService* infobar_service) {
-#if defined(OS_MACOSX)
-  if (!ObsoleteSystemMac::Is32BitObsoleteNowOrSoon() ||
-      !ObsoleteSystemMac::Has32BitOnlyCPU()) {
+  if (!ObsoleteSystem::IsObsoleteNowOrSoon())
     return;
-  }
   infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
       scoped_ptr<ConfirmInfoBarDelegate>(new ObsoleteSystemInfoBarDelegate())));
-#else
-  // No other platforms currently show this infobar.
-  return;
-#endif
 }
 
 ObsoleteSystemInfoBarDelegate::ObsoleteSystemInfoBarDelegate()
@@ -39,11 +29,7 @@
 }
 
 base::string16 ObsoleteSystemInfoBarDelegate::GetMessageText() const {
-#if defined(OS_MACOSX)
-  return ObsoleteSystemMac::LocalizedObsoleteSystemString();
-#else
-  return l10n_util::GetStringUTF16(IDS_SYSTEM_OBSOLETE_MESSAGE);
-#endif
+  return ObsoleteSystem::LocalizedObsoleteString();
 }
 
 int ObsoleteSystemInfoBarDelegate::GetButtons() const {
@@ -55,9 +41,5 @@
 }
 
 GURL ObsoleteSystemInfoBarDelegate::GetLinkURL() const {
-#if defined(OS_MACOSX)
-  return GURL(chrome::kMac32BitDeprecationURL);
-#else
-  return GURL("https://support.google.com/chrome/answer/95411");
-#endif
+  return GURL(ObsoleteSystem::GetLinkURL());
 }
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index d36f584..0eba5e7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -31,7 +31,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
-#include "chrome/browser/auto_launch_trial.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 5467148e..9e5bfe7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -26,7 +26,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/browser/apps/install_chrome_app.h"
-#include "chrome/browser/auto_launch_trial.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
@@ -63,7 +62,6 @@
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/session_crashed_bubble.h"
-#include "chrome/browser/ui/startup/autolaunch_prompt.h"
 #include "chrome/browser/ui/startup/bad_flags_prompt.h"
 #include "chrome/browser/ui/startup/default_browser_prompt.h"
 #include "chrome/browser/ui/startup/google_api_keys_infobar_delegate.h"
@@ -827,10 +825,9 @@
       // Generally, the default browser prompt should not be shown on first
       // run. However, when the set-as-default dialog has been suppressed, we
       // need to allow it.
-      if ((!is_first_run_ ||
-           (browser_creator_ &&
-            browser_creator_->is_default_browser_dialog_suppressed())) &&
-          !chrome::ShowAutolaunchPrompt(browser)) {
+      if (!is_first_run_ ||
+          (browser_creator_ &&
+           browser_creator_->is_default_browser_dialog_suppressed())) {
         chrome::ShowDefaultBrowserPrompt(profile_,
                                          browser->host_desktop_type());
       }
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
index 214f508e..64d7ae5 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.cc
@@ -49,17 +49,13 @@
 
 SaveCardBubbleViews::~SaveCardBubbleViews() {}
 
-void SaveCardBubbleViews::Show() {
-  GetWidget()->Show();
+void SaveCardBubbleViews::Show(DisplayReason reason) {
+  ShowForReason(reason);
 }
 
-void SaveCardBubbleViews::Close() {
-  GetWidget()->Close();
-}
-
-void SaveCardBubbleViews::ControllerGone() {
+void SaveCardBubbleViews::Hide() {
   controller_ = nullptr;
-  GetWidget()->Close();
+  Close();
 }
 
 views::View* SaveCardBubbleViews::GetInitiallyFocusedView() {
@@ -87,7 +83,7 @@
     DCHECK_EQ(sender, cancel_button_);
     controller_->OnCancelButton();
   }
-  GetWidget()->Close();
+  Close();
 }
 
 void SaveCardBubbleViews::LinkClicked(views::Link* source, int event_flags) {
diff --git a/chrome/browser/ui/views/autofill/save_card_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
index eba7e60..6f26339 100644
--- a/chrome/browser/ui/views/autofill/save_card_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/save_card_bubble_views.h
@@ -37,10 +37,10 @@
                       content::WebContents* web_contents,
                       SaveCardBubbleController* controller);
 
+  void Show(DisplayReason reason);
+
   // SaveCardBubbleView
-  void Show() override;
-  void Close() override;
-  void ControllerGone() override;
+  void Hide() override;
 
   // views::WidgetDelegate
   views::View* GetInitiallyFocusedView() override;
diff --git a/chrome/browser/ui/views/autofill/save_card_icon_view.cc b/chrome/browser/ui/views/autofill/save_card_icon_view.cc
index 68b16db2..39d7820 100644
--- a/chrome/browser/ui/views/autofill/save_card_icon_view.cc
+++ b/chrome/browser/ui/views/autofill/save_card_icon_view.cc
@@ -22,15 +22,10 @@
       browser_(browser) {
   set_id(VIEW_ID_SAVE_CREDIT_CARD_BUTTON);
   SetTooltipText(l10n_util::GetStringUTF16(IDS_TOOLTIP_SAVE_CREDIT_CARD));
-  SetToggled(false);
 }
 
 SaveCardIconView::~SaveCardIconView() {}
 
-void SaveCardIconView::SetToggled(bool on) {
-  SetActiveInternal(on);
-}
-
 void SaveCardIconView::OnExecuting(
     BubbleIconView::ExecuteSource execute_source) {}
 
diff --git a/chrome/browser/ui/views/autofill/save_card_icon_view.h b/chrome/browser/ui/views/autofill/save_card_icon_view.h
index 527c0f76..f591420 100644
--- a/chrome/browser/ui/views/autofill/save_card_icon_view.h
+++ b/chrome/browser/ui/views/autofill/save_card_icon_view.h
@@ -21,9 +21,6 @@
   explicit SaveCardIconView(CommandUpdater* command_updater, Browser* browser);
   ~SaveCardIconView() override;
 
-  // Toggles the icon on or off.
-  void SetToggled(bool on);
-
  protected:
   // BubbleIconView:
   void OnExecuting(BubbleIconView::ExecuteSource execute_source) override;
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index 1c309e4..720e006 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 
+#include "base/i18n/case_conversion.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -81,6 +83,75 @@
 ButtonView::~ButtonView() {
 }
 
+// Class containing the exit instruction text. Contains fancy styling on the
+// keyboard key (not just a simple label).
+class InstructionView : public views::View {
+ public:
+  // Creates an InstructionView with specific text. |text| may contain a single
+  // segment delimited by a pair of pipes ('|'); this segment will be displayed
+  // as a keyboard key. e.g., "Press |Esc| to exit" will have "Esc" rendered as
+  // a key.
+  InstructionView(const base::string16& text,
+                  const gfx::FontList& font_list,
+                  SkColor foreground_color,
+                  SkColor background_color);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(InstructionView);
+};
+
+InstructionView::InstructionView(const base::string16& text,
+                                 const gfx::FontList& font_list,
+                                 SkColor foreground_color,
+                                 SkColor background_color) {
+  // Parse |text|, looking for pipe-delimited segment.
+  std::vector<base::string16> segments =
+      base::SplitString(text, base::ASCIIToUTF16("|"), base::TRIM_WHITESPACE,
+                        base::SPLIT_WANT_ALL);
+  // Expect 1 or 3 pieces (either no pipe-delimited segments, or one).
+  DCHECK(segments.size() == 1 || segments.size() == 3);
+
+  // Spacing around the escape key name.
+  const int kKeyNameMarginHorizPx = 7;
+  const int kKeyNameBorderPx = 2;
+  const int kKeyNameCornerRadius = 2;
+  const int kKeyNamePaddingPx = 7;
+
+  // The |between_child_spacing| is the horizontal margin of the key name.
+  views::BoxLayout* layout = new views::BoxLayout(views::BoxLayout::kHorizontal,
+                                                  0, 0, kKeyNameMarginHorizPx);
+  SetLayoutManager(layout);
+
+  views::Label* before_key = new views::Label(segments[0], font_list);
+  before_key->SetEnabledColor(foreground_color);
+  before_key->SetBackgroundColor(background_color);
+  AddChildView(before_key);
+
+  if (segments.size() < 3)
+    return;
+
+  base::string16 key = base::i18n::ToUpper(segments[1]);
+  views::Label* key_name_label = new views::Label(key, font_list);
+  key_name_label->SetEnabledColor(foreground_color);
+  key_name_label->SetBackgroundColor(background_color);
+
+  views::View* key_name = new views::View;
+  views::BoxLayout* key_name_layout = new views::BoxLayout(
+      views::BoxLayout::kHorizontal, kKeyNamePaddingPx, kKeyNamePaddingPx, 0);
+  key_name->SetLayoutManager(key_name_layout);
+  key_name->AddChildView(key_name_label);
+  // The key name has a border around it.
+  scoped_ptr<views::Border> border(views::Border::CreateRoundedRectBorder(
+      kKeyNameBorderPx, kKeyNameCornerRadius, foreground_color));
+  key_name->SetBorder(border.Pass());
+  AddChildView(key_name);
+
+  views::Label* after_key = new views::Label(segments[2], font_list);
+  after_key->SetEnabledColor(foreground_color);
+  after_key->SetBackgroundColor(background_color);
+  AddChildView(after_key);
+}
+
 }  // namespace
 
 class ExclusiveAccessBubbleViews::ExclusiveAccessView
@@ -115,7 +186,7 @@
   ButtonView* button_view_;
   // Instruction for exiting fullscreen / mouse lock. Only present if there is
   // no link or button (always present in simplified mode).
-  views::Label* exit_instruction_;
+  InstructionView* exit_instruction_;
   const base::string16 browser_fullscreen_exit_accelerator_;
 
   DISALLOW_COPY_AND_ASSIGN(ExclusiveAccessView);
@@ -169,9 +240,8 @@
   }
 
   exit_instruction_ =
-      new views::Label(bubble_->GetInstructionText(), medium_font_list);
-  exit_instruction_->SetEnabledColor(foreground_color);
-  exit_instruction_->SetBackgroundColor(background_color);
+      new InstructionView(bubble_->GetInstructionText(), medium_font_list,
+                          foreground_color, background_color);
 
   link_ = new views::Link();
   link_->SetFocusable(false);
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
index 0dac7ae..20d64e9 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.cc
@@ -156,12 +156,9 @@
   DesktopWindowTreeHostWin::HandleCreate();
   browser_window_property_manager_ =
       BrowserWindowPropertyManager::CreateBrowserWindowPropertyManager(
-          browser_view_, GetHWND());
-}
-
-void BrowserDesktopWindowTreeHostWin::HandleDestroying() {
-  browser_window_property_manager_.reset();
-  DesktopWindowTreeHostWin::HandleDestroying();
+          browser_view_);
+  if (browser_window_property_manager_)
+    browser_window_property_manager_->UpdateWindowProperties(GetHWND());
 }
 
 void BrowserDesktopWindowTreeHostWin::HandleFrameChanged() {
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
index 4a4409a..26f20c22 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_win.h
@@ -43,7 +43,6 @@
   int GetInitialShowState() const override;
   bool GetClientAreaInsets(gfx::Insets* insets) const override;
   void HandleCreate() override;
-  void HandleDestroying() override;
   void HandleFrameChanged() override;
   bool PreHandleMSG(UINT message,
                     WPARAM w_param,
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index ec64e54..0c8e4a5 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_test.h"
 #include "chrome/browser/ui/views/profiles/avatar_menu_button.h"
+#include "components/signin/core/account_id/account_id.h"
 #endif  // defined(OS_CHROMEOS)
 
 using views::Widget;
@@ -225,14 +226,14 @@
 
   EXPECT_FALSE(chrome::MultiUserWindowManager::ShouldShowAvatar(window));
 
-  const std::string current_user =
-      multi_user_util::GetUserIDFromProfile(browser()->profile());
+  const AccountId current_account_id =
+      multi_user_util::GetAccountIdFromProfile(browser()->profile());
   TestMultiUserWindowManager* manager =
-      new TestMultiUserWindowManager(browser(), current_user);
+      new TestMultiUserWindowManager(browser(), current_account_id);
 
   // Teleport the window to another desktop.
-  const std::string user2 = "user2";
-  manager->ShowWindowForUser(window, user2);
+  const AccountId account_id2(AccountId::FromUserEmail("user2"));
+  manager->ShowWindowForUser(window, account_id2);
   EXPECT_TRUE(chrome::MultiUserWindowManager::ShouldShowAvatar(window));
 
   // Avatar should show on the top left corner of the teleported browser window.
@@ -253,14 +254,15 @@
                            profiles::kAvatarIconHeight / 2);
   EXPECT_EQ(HTCLIENT, frame_view->NonClientHitTest(avatar_center));
 
-  const std::string current_user =
-      multi_user_util::GetUserIDFromProfile(browser()->profile());
+  const AccountId current_user =
+      multi_user_util::GetAccountIdFromProfile(browser()->profile());
   TestMultiUserWindowManager* manager =
       new TestMultiUserWindowManager(browser(), current_user);
 
   // Teleport the window to another desktop.
-  const std::string user2 = "user2";
-  manager->ShowWindowForUser(browser()->window()->GetNativeWindow(), user2);
+  const AccountId account_id2(AccountId::FromUserEmail("user2"));
+  manager->ShowWindowForUser(browser()->window()->GetNativeWindow(),
+                             account_id2);
   // Clicking on the avatar icon should have same behaviour like clicking on
   // the caption area, i.e., allow the user to drag the browser window around.
   EXPECT_EQ(HTCAPTION, frame_view->NonClientHitTest(avatar_center));
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 2464dad2..5be19270 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -856,7 +856,7 @@
 }
 
 void BrowserView::SetTranslateIconToggled(bool is_lit) {
-  GetLocationBarView()->SetTranslateIconToggled(is_lit);
+  // Translate icon is never active on Views.
 }
 
 void BrowserView::OnActiveTabChanged(content::WebContents* old_contents,
@@ -1281,11 +1281,13 @@
 
 autofill::SaveCardBubbleView* BrowserView::ShowSaveCreditCardBubble(
     content::WebContents* web_contents,
-    autofill::SaveCardBubbleController* controller) {
-  autofill::SaveCardBubbleView* view = new autofill::SaveCardBubbleViews(
+    autofill::SaveCardBubbleController* controller,
+    bool is_user_gesture) {
+  autofill::SaveCardBubbleViews* view = new autofill::SaveCardBubbleViews(
       GetToolbarView()->GetSaveCreditCardBubbleAnchor(), web_contents,
       controller);
-  view->Show();
+  view->Show(is_user_gesture ? autofill::SaveCardBubbleViews::USER_GESTURE
+                             : autofill::SaveCardBubbleViews::AUTOMATIC);
   return view;
 }
 
@@ -1312,7 +1314,8 @@
 
   TranslateBubbleView::ShowBubble(
       GetToolbarView()->GetTranslateBubbleAnchor(), web_contents, step,
-      error_type, is_user_gesture);
+      error_type, is_user_gesture ? TranslateBubbleView::USER_GESTURE
+                                  : TranslateBubbleView::AUTOMATIC);
 }
 
 bool BrowserView::IsProfileResetBubbleSupported() const {
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 41c7c06..e9e1815 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -318,7 +318,8 @@
       const ShowBookmarkAppBubbleCallback& callback) override;
   autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
       content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller) override;
+      autofill::SaveCardBubbleController* controller,
+      bool is_user_gesture) override;
   void ShowTranslateBubble(content::WebContents* contents,
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
index 4c801d9..59996a15 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_win.cc
@@ -24,12 +24,9 @@
 
 using extensions::ExtensionRegistry;
 
-BrowserWindowPropertyManager::BrowserWindowPropertyManager(BrowserView* view,
-                                                           HWND hwnd)
-    : view_(view),
-      hwnd_(hwnd) {
-  // At this point, the HWND is unavailable from BrowserView.
-  DCHECK(hwnd);
+BrowserWindowPropertyManager::BrowserWindowPropertyManager(BrowserView* view)
+    : view_(view) {
+  DCHECK(view_);
   profile_pref_registrar_.Init(view_->browser()->profile()->GetPrefs());
 
   // Monitor the profile icon version on Windows so that we can set the browser
@@ -41,10 +38,10 @@
 }
 
 BrowserWindowPropertyManager::~BrowserWindowPropertyManager() {
-  ui::win::ClearWindowPropertyStore(hwnd_);
 }
 
-void BrowserWindowPropertyManager::UpdateWindowProperties() {
+void BrowserWindowPropertyManager::UpdateWindowProperties(HWND hwnd) {
+  DCHECK(hwnd);
   Browser* browser = view_->browser();
   Profile* profile = browser->profile();
 
@@ -68,8 +65,8 @@
         web_app::GetExtensionIdFromApplicationName(browser->app_name()),
         ExtensionRegistry::EVERYTHING);
     if (extension) {
-      ui::win::SetAppIdForWindow(app_id, hwnd_);
-      web_app::UpdateRelaunchDetailsForApp(profile, extension, hwnd_);
+      ui::win::SetAppIdForWindow(app_id, hwnd);
+      web_app::UpdateRelaunchDetailsForApp(profile, extension, hwnd);
       return;
     }
   }
@@ -95,23 +92,22 @@
       icon_path_string,
       command_line_string,
       pinned_name,
-      hwnd_);
+      hwnd);
 }
 
 // static
 scoped_ptr<BrowserWindowPropertyManager>
     BrowserWindowPropertyManager::CreateBrowserWindowPropertyManager(
-        BrowserView* view, HWND hwnd) {
+        BrowserView* view) {
   if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
-      view->browser()->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH)
+      view->browser()->host_desktop_type() == chrome::HOST_DESKTOP_TYPE_ASH) {
     return scoped_ptr<BrowserWindowPropertyManager>();
+  }
 
-  scoped_ptr<BrowserWindowPropertyManager> browser_window_property_manager(
-      new BrowserWindowPropertyManager(view, hwnd));
-  browser_window_property_manager->UpdateWindowProperties();
-  return browser_window_property_manager.Pass();
+  return scoped_ptr<BrowserWindowPropertyManager>(
+      new BrowserWindowPropertyManager(view));
 }
 
 void BrowserWindowPropertyManager::OnProfileIconVersionChange() {
-  UpdateWindowProperties();
+  UpdateWindowProperties(views::HWNDForNativeWindow(view_->GetNativeWindow()));
 }
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_win.h b/chrome/browser/ui/views/frame/browser_window_property_manager_win.h
index c626ce1..1f08655 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_win.h
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_win.h
@@ -16,18 +16,19 @@
  public:
   virtual ~BrowserWindowPropertyManager();
 
+  void UpdateWindowProperties(HWND hwnd);
+
   static scoped_ptr<BrowserWindowPropertyManager>
-      CreateBrowserWindowPropertyManager(BrowserView* view, HWND hwnd);
+      CreateBrowserWindowPropertyManager(BrowserView* view);
 
  private:
-  BrowserWindowPropertyManager(BrowserView* view, HWND hwnd);
+  explicit BrowserWindowPropertyManager(BrowserView* view);
 
-  void UpdateWindowProperties();
   void OnProfileIconVersionChange();
 
   PrefChangeRegistrar profile_pref_registrar_;
+
   BrowserView* view_;
-  const HWND hwnd_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserWindowPropertyManager);
 };
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
index a1198fe..ea0d1cb 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "components/signin/core/account_id/account_id.h"
 #include "components/user_manager/user_info.h"
 #include "ui/base/l10n/l10n_util.h"
 #endif
@@ -169,10 +170,11 @@
   // is not owned by anyone, we don't show the menu addition.
   chrome::MultiUserWindowManager* manager =
       chrome::MultiUserWindowManager::GetInstance();
-  const std::string user_id =
-      multi_user_util::GetUserIDFromProfile(browser()->profile());
+  const AccountId account_id =
+      multi_user_util::GetAccountIdFromProfile(browser()->profile());
   aura::Window* window = browser()->window()->GetNativeWindow();
-  if (user_id.empty() || !window || manager->GetWindowOwner(window).empty())
+  if (!account_id.is_valid() || !window ||
+      !manager->GetWindowOwner(window).is_valid())
     return;
 
   model->AddSeparator(ui::NORMAL_SEPARATOR);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
index 18f2953..2fa92b5 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.cc
@@ -29,6 +29,15 @@
 
 LocationBarBubbleDelegateView::~LocationBarBubbleDelegateView() {}
 
+void LocationBarBubbleDelegateView::ShowForReason(DisplayReason reason) {
+  if (reason == USER_GESTURE) {
+    SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT);
+    GetWidget()->Show();
+  } else {
+    GetWidget()->ShowInactive();
+  }
+}
+
 void LocationBarBubbleDelegateView::Observe(
     int type,
     const content::NotificationSource& source,
diff --git a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
index 113520a..13c4f7d 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_bubble_delegate_view.h
@@ -22,10 +22,24 @@
 class LocationBarBubbleDelegateView : public views::BubbleDelegateView,
                                       public content::NotificationObserver {
  public:
+  enum DisplayReason {
+    // The bubble appears as a direct result of a user action (clicking on the
+    // location bar icon).
+    USER_GESTURE,
+
+    // The bubble appears spontaneously over the course of the user's
+    // interaction with Chrome (e.g. due to some change in the feature's
+    // status).
+    AUTOMATIC,
+  };
+
   LocationBarBubbleDelegateView(views::View* anchor_view,
                                 content::WebContents* web_contents);
   ~LocationBarBubbleDelegateView() override;
 
+  // Displays the bubble with appearance and behavior tailored for |reason|.
+  void ShowForReason(DisplayReason reason);
+
   // content::NotificationObserver:
   void Observe(int type,
                const content::NotificationSource& source,
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index 5f8e0d2..7d19dea6 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -386,7 +386,7 @@
 
   WebContents* web_contents = GetWebContents();
   if (can_show_bubble && zoom_view_->visible() && web_contents)
-    ZoomBubbleView::ShowBubble(web_contents, true);
+    ZoomBubbleView::ShowBubble(web_contents, ZoomBubbleView::AUTOMATIC);
 }
 
 void LocationBarView::SetPreviewEnabledPageAction(ExtensionAction* page_action,
@@ -426,10 +426,6 @@
     star_view_->SetToggled(on);
 }
 
-void LocationBarView::SetTranslateIconToggled(bool on) {
-  translate_icon_view_->SetToggled(on);
-}
-
 gfx::Point LocationBarView::GetOmniboxViewOrigin() const {
   gfx::Point origin(omnibox_view_->bounds().origin());
   origin.set_x(GetMirroredXInView(origin.x()));
@@ -986,8 +982,6 @@
   command_updater()->UpdateCommandEnabled(IDC_SAVE_CREDIT_CARD_FOR_PAGE,
                                           enabled);
   save_credit_card_icon_view_->SetVisible(enabled);
-  if (enabled)
-    save_credit_card_icon_view_->SetToggled(controller->IsIconToggled());
 
   return was_visible != save_credit_card_icon_view_->visible();
 }
@@ -1001,7 +995,6 @@
   bool enabled = language_state.translate_enabled();
   command_updater()->UpdateCommandEnabled(IDC_TRANSLATE_PAGE, enabled);
   translate_icon_view_->SetVisible(enabled);
-  translate_icon_view_->SetToggled(language_state.IsPageTranslated());
   if (!enabled)
     TranslateBubbleView::CloseBubble();
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index 0b17ae7..b31d937 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -177,9 +177,6 @@
     return save_credit_card_icon_view_;
   }
 
-  // Toggles the translate icon on or off.
-  void SetTranslateIconToggled(bool on);
-
   // The translate icon. It may not be visible.
   TranslateIconView* translate_icon_view() { return translate_icon_view_; }
 
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
index ba46d22..6cc5768 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.cc
@@ -37,7 +37,7 @@
 
 // static
 void ZoomBubbleView::ShowBubble(content::WebContents* web_contents,
-                                bool auto_close) {
+                                DisplayReason reason) {
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   DCHECK(browser && browser->window() &&
          browser->exclusive_access_manager()->fullscreen_controller());
@@ -67,7 +67,7 @@
   // bubble must be closed and a new one created.
   CloseBubble();
 
-  zoom_bubble_ = new ZoomBubbleView(anchor_view, web_contents, auto_close,
+  zoom_bubble_ = new ZoomBubbleView(anchor_view, web_contents, reason,
                                     browser_view->immersive_mode_controller());
 
   // If the zoom change was initiated by an extension, capture the relevent
@@ -88,10 +88,7 @@
   if (is_fullscreen)
     zoom_bubble_->AdjustForFullscreen(browser_view->GetBoundsInScreen());
 
-  if (auto_close)
-    zoom_bubble_->GetWidget()->ShowInactive();
-  else
-    zoom_bubble_->GetWidget()->Show();
+  zoom_bubble_->ShowForReason(reason);
 }
 
 // static
@@ -108,13 +105,13 @@
 ZoomBubbleView::ZoomBubbleView(
     views::View* anchor_view,
     content::WebContents* web_contents,
-    bool auto_close,
+    DisplayReason reason,
     ImmersiveModeController* immersive_mode_controller)
     : LocationBarBubbleDelegateView(anchor_view, web_contents),
       image_button_(NULL),
       label_(NULL),
       web_contents_(web_contents),
-      auto_close_(auto_close),
+      auto_close_(reason == AUTOMATIC),
       immersive_mode_controller_(immersive_mode_controller) {
   // Compensate for built-in vertical padding in the anchor view's image.
   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
@@ -298,19 +295,20 @@
 }
 
 void ZoomBubbleView::StartTimerIfNecessary() {
-  if (auto_close_) {
-    if (timer_.IsRunning()) {
-      timer_.Reset();
-    } else {
-      // The number of milliseconds the bubble should stay on the screen if it
-      // will close automatically.
-      const int kBubbleCloseDelay = 1500;
-      timer_.Start(
-          FROM_HERE,
-          base::TimeDelta::FromMilliseconds(kBubbleCloseDelay),
-          this,
-          &ZoomBubbleView::Close);
-    }
+  if (!auto_close_)
+    return;
+
+  if (timer_.IsRunning()) {
+    timer_.Reset();
+  } else {
+    // The number of milliseconds the bubble should stay on the screen if it
+    // will close automatically.
+    const int kBubbleCloseDelay = 1500;
+    timer_.Start(
+        FROM_HERE,
+        base::TimeDelta::FromMilliseconds(kBubbleCloseDelay),
+        this,
+        &ZoomBubbleView::Close);
   }
 }
 
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view.h b/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
index acf2d34a..3d17991 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view.h
@@ -36,9 +36,9 @@
                        public extensions::IconImage::Observer {
  public:
   // Shows the bubble and automatically closes it after a short time period if
-  // |auto_close| is true.
+  // |reason| is AUTOMATIC.
   static void ShowBubble(content::WebContents* web_contents,
-                         bool auto_close);
+                         DisplayReason reason);
 
   // Closes the showing bubble (if one exists).
   static void CloseBubble();
@@ -71,7 +71,7 @@
 
   ZoomBubbleView(views::View* anchor_view,
                  content::WebContents* web_contents,
-                 bool auto_close,
+                 DisplayReason reason,
                  ImmersiveModeController* immersive_mode_controller);
   ~ZoomBubbleView() override;
 
@@ -115,7 +115,7 @@
   // twice at the same time.
   static ZoomBubbleView* zoom_bubble_;
 
-  // Timer used to close the bubble when |auto_close_| is true.
+  // Timer used to auto close the bubble.
   base::OneShotTimer timer_;
 
   // Image button in the zoom bubble that will show the |extension_icon_| image
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
index db9e61c6..3d54f2f 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -26,7 +26,7 @@
   content::WebContents* web_contents = browser_view->GetActiveWebContents();
 
   // The zoom bubble should be anchored when not in fullscreen.
-  ZoomBubbleView::ShowBubble(web_contents, true);
+  ZoomBubbleView::ShowBubble(web_contents, ZoomBubbleView::AUTOMATIC);
   ASSERT_TRUE(ZoomBubbleView::GetZoomBubble());
   const ZoomBubbleView* zoom_bubble = ZoomBubbleView::GetZoomBubble();
   EXPECT_TRUE(zoom_bubble->GetAnchorView());
@@ -49,7 +49,7 @@
 
   // The bubble should not be anchored when it is shown in non-immersive
   // fullscreen.
-  ZoomBubbleView::ShowBubble(web_contents, true);
+  ZoomBubbleView::ShowBubble(web_contents, ZoomBubbleView::AUTOMATIC);
   ASSERT_TRUE(ZoomBubbleView::GetZoomBubble());
   zoom_bubble = ZoomBubbleView::GetZoomBubble();
   EXPECT_FALSE(zoom_bubble->GetAnchorView());
@@ -87,7 +87,7 @@
 
   // The zoom bubble should not be anchored when it is shown in immersive
   // fullscreen and the top-of-window views are not revealed.
-  ZoomBubbleView::ShowBubble(web_contents, true);
+  ZoomBubbleView::ShowBubble(web_contents, ZoomBubbleView::AUTOMATIC);
   ASSERT_TRUE(ZoomBubbleView::GetZoomBubble());
   const ZoomBubbleView* zoom_bubble = ZoomBubbleView::GetZoomBubble();
   EXPECT_FALSE(zoom_bubble->GetAnchorView());
@@ -101,7 +101,7 @@
 
   // The zoom bubble should be anchored when it is shown in immersive fullscreen
   // and the top-of-window views are revealed.
-  ZoomBubbleView::ShowBubble(web_contents, true);
+  ZoomBubbleView::ShowBubble(web_contents, ZoomBubbleView::AUTOMATIC);
   ASSERT_TRUE(ZoomBubbleView::GetZoomBubble());
   zoom_bubble = ZoomBubbleView::GetZoomBubble();
   EXPECT_TRUE(zoom_bubble->GetAnchorView());
diff --git a/chrome/browser/ui/views/location_bar/zoom_view.cc b/chrome/browser/ui/views/location_bar/zoom_view.cc
index 42cc9b68..fcde261 100644
--- a/chrome/browser/ui/views/location_bar/zoom_view.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_view.cc
@@ -48,7 +48,8 @@
 }
 
 void ZoomView::OnExecuting(BubbleIconView::ExecuteSource source) {
-  ZoomBubbleView::ShowBubble(location_bar_delegate_->GetWebContents(), false);
+  ZoomBubbleView::ShowBubble(location_bar_delegate_->GetWebContents(),
+                             ZoomBubbleView::USER_GESTURE);
 }
 
 void ZoomView::GetAccessibleState(ui::AXViewState* state) {
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
index 7239bc6..8ddf95b 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.cc
@@ -914,7 +914,7 @@
 // static
 void ManagePasswordsBubbleView::ShowBubble(
     content::WebContents* web_contents,
-    ManagePasswordsBubbleModel::DisplayReason reason) {
+    DisplayReason reason) {
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   DCHECK(browser);
   DCHECK(browser->window());
@@ -940,10 +940,8 @@
     manage_passwords_bubble_->AdjustForFullscreen(
         browser_view->GetBoundsInScreen());
   }
-  if (reason == ManagePasswordsBubbleModel::AUTOMATIC)
-    manage_passwords_bubble_->GetWidget()->ShowInactive();
-  else
-    manage_passwords_bubble_->GetWidget()->Show();
+
+  manage_passwords_bubble_->ShowForReason(reason);
 }
 
 // static
@@ -966,11 +964,13 @@
 ManagePasswordsBubbleView::ManagePasswordsBubbleView(
     content::WebContents* web_contents,
     ManagePasswordsIconViews* anchor_view,
-    ManagePasswordsBubbleModel::DisplayReason reason)
+    DisplayReason reason)
     : LocationBarBubbleDelegateView(anchor_view, web_contents),
-      model_(web_contents, reason),
+      model_(web_contents,
+             reason == AUTOMATIC ? ManagePasswordsBubbleModel::AUTOMATIC
+                                 : ManagePasswordsBubbleModel::USER_ACTION),
       anchor_view_(anchor_view),
-      initially_focused_view_(NULL) {
+      initially_focused_view_(nullptr) {
   // Compensate for built-in vertical padding in the anchor view's image.
   set_anchor_view_insets(gfx::Insets(5, 0, 5, 0));
 
@@ -978,8 +978,6 @@
                                                  : views::kPanelVertMargin;
   set_margins(gfx::Insets(top_margin, views::kPanelHorizMargin,
                           views::kPanelVertMargin, views::kPanelHorizMargin));
-  if (anchor_view)
-    anchor_view->SetActive(true);
   mouse_handler_.reset(new WebContentMouseHandler(this));
 }
 
@@ -1004,11 +1002,6 @@
   LocationBarBubbleDelegateView::Close();
 }
 
-void ManagePasswordsBubbleView::OnWidgetClosing(views::Widget* /*widget*/) {
-  if (anchor_view_)
-    anchor_view_->SetActive(false);
-}
-
 bool ManagePasswordsBubbleView::ShouldShowCloseButton() const {
   return model_.state() == password_manager::ui::PENDING_PASSWORD_STATE;
 }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h
index d42063f..4720f06f 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view.h
@@ -26,7 +26,7 @@
  public:
   // Shows the bubble.
   static void ShowBubble(content::WebContents* web_contents,
-                         ManagePasswordsBubbleModel::DisplayReason reason);
+                         DisplayReason reason);
 
   // Closes the existing bubble.
   static void CloseBubble();
@@ -65,7 +65,7 @@
 
   ManagePasswordsBubbleView(content::WebContents* web_contents,
                             ManagePasswordsIconViews* anchor_view,
-                            ManagePasswordsBubbleModel::DisplayReason reason);
+                            DisplayReason reason);
   ~ManagePasswordsBubbleView() override;
 
   // LocationBarBubbleDelegateView:
@@ -73,9 +73,6 @@
   void Init() override;
   void Close() override;
 
-  // WidgetObserver:
-  void OnWidgetClosing(views::Widget* widget) override;
-
   // WidgetDelegate:
   bool ShouldShowCloseButton() const override;
 
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc
index 80f25cf4..e5db354 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_bubble_view_browsertest.cc
@@ -80,7 +80,7 @@
   EXPECT_FALSE(IsBubbleShowing());
   ManagePasswordsBubbleView::ShowBubble(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      ManagePasswordsBubbleModel::USER_ACTION);
+      ManagePasswordsBubbleView::USER_GESTURE);
   EXPECT_TRUE(IsBubbleShowing());
   const ManagePasswordsBubbleView* bubble =
       ManagePasswordsBubbleView::manage_password_bubble();
@@ -93,7 +93,7 @@
   // And, just for grins, ensure that we can re-open the bubble.
   ManagePasswordsBubbleView::ShowBubble(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      ManagePasswordsBubbleModel::USER_ACTION);
+      ManagePasswordsBubbleView::USER_GESTURE);
   EXPECT_TRUE(ManagePasswordsBubbleView::manage_password_bubble()->
       GetFocusManager()->GetFocusedView());
   EXPECT_TRUE(IsBubbleShowing());
@@ -224,7 +224,7 @@
 IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, CloseOnClick) {
   ManagePasswordsBubbleView::ShowBubble(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      ManagePasswordsBubbleModel::AUTOMATIC);
+      ManagePasswordsBubbleView::AUTOMATIC);
   EXPECT_TRUE(IsBubbleShowing());
   EXPECT_FALSE(ManagePasswordsBubbleView::manage_password_bubble()->
       GetFocusManager()->GetFocusedView());
@@ -235,7 +235,7 @@
 IN_PROC_BROWSER_TEST_F(ManagePasswordsBubbleViewTest, CloseOnEsc) {
   ManagePasswordsBubbleView::ShowBubble(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      ManagePasswordsBubbleModel::AUTOMATIC);
+      ManagePasswordsBubbleView::AUTOMATIC);
   EXPECT_TRUE(IsBubbleShowing());
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_ESCAPE,
       false, false, false, false));
@@ -253,7 +253,7 @@
   content::WebContents* web_contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ManagePasswordsBubbleView::ShowBubble(web_contents,
-                                        ManagePasswordsBubbleModel::AUTOMATIC);
+                                        ManagePasswordsBubbleView::AUTOMATIC);
   EXPECT_TRUE(IsBubbleShowing());
   EXPECT_FALSE(ManagePasswordsBubbleView::manage_password_bubble()->
       GetFocusManager()->GetFocusedView());
@@ -282,7 +282,7 @@
   EXPECT_FALSE(IsBubbleShowing());
   ManagePasswordsBubbleView::ShowBubble(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      ManagePasswordsBubbleModel::AUTOMATIC);
+      ManagePasswordsBubbleView::AUTOMATIC);
   EXPECT_TRUE(IsBubbleShowing());
   TabStripModel* tab_model = browser()->tab_strip_model();
   EXPECT_EQ(0, tab_model->active_index());
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc
index 7244c4614..00dcb72 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_browsertest.cc
@@ -31,7 +31,6 @@
   }
 
   password_manager::ui::State ViewState() { return GetView()->state_; }
-  bool ViewIsActive() { return GetView()->active(); }
 
   ManagePasswordsIconViews* GetView() {
     return static_cast<ManagePasswordsIconViews*>(view());
@@ -56,14 +55,9 @@
   SetupPendingPassword();
   EXPECT_EQ(password_manager::ui::PENDING_PASSWORD_STATE, ViewState());
   EXPECT_TRUE(GetView()->visible());
-  EXPECT_TRUE(ViewIsActive());
   // No tooltip because the bubble is showing.
   EXPECT_EQ(base::string16(), GetTooltipText());
   const gfx::ImageSkia active_image = GetView()->GetImage();
-
-  GetView()->SetActive(false);
-  EXPECT_FALSE(active_image.BackedBySameObjectAs(GetView()->GetImage()));
-  EXPECT_FALSE(ViewIsActive());
 }
 
 IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, ManageState) {
@@ -72,28 +66,15 @@
   EXPECT_TRUE(GetView()->visible());
   EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_TOOLTIP_MANAGE),
             GetTooltipText());
-  const gfx::ImageSkia inactive_image = GetView()->GetImage();
-
-  GetView()->SetActive(true);
-  const gfx::ImageSkia active_image = GetView()->GetImage();
-  EXPECT_FALSE(active_image.BackedBySameObjectAs(inactive_image));
-  EXPECT_TRUE(ViewIsActive());
-
-  GetView()->SetActive(false);
-  EXPECT_FALSE(active_image.BackedBySameObjectAs(GetView()->GetImage()));
-  EXPECT_TRUE(inactive_image.BackedBySameObjectAs(GetView()->GetImage()));
-  EXPECT_FALSE(ViewIsActive());
 }
 
 IN_PROC_BROWSER_TEST_F(ManagePasswordsIconViewTest, CloseOnClick) {
   SetupPendingPassword();
   EXPECT_TRUE(GetView()->visible());
-  EXPECT_TRUE(ViewIsActive());
   ui::MouseEvent mouse_down(ui::ET_MOUSE_PRESSED, gfx::Point(10, 10),
                             gfx::Point(900, 60), ui::EventTimeForNow(),
                             ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON);
   GetView()->OnMousePressed(mouse_down);
   // Wait for the command execution to close the bubble.
   content::RunAllPendingInMessageLoop();
-  EXPECT_FALSE(ViewIsActive());
 }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_views.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_views.cc
index aa847db..56e6d94 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_icon_views.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_views.cc
@@ -23,16 +23,11 @@
 
 ManagePasswordsIconViews::~ManagePasswordsIconViews() {}
 
-void ManagePasswordsIconViews::SetActive(bool active) {
-  SetActiveInternal(active);
-}
-
 void ManagePasswordsIconViews::SetState(password_manager::ui::State state) {
   if (state_ == state)
     return;
   // If there is an opened bubble for the current icon it should go away.
-  if (active())
-    ManagePasswordsBubbleView::CloseBubble();
+  ManagePasswordsBubbleView::CloseBubble();
   state_ = state;
   UpdateUiForState();
 }
@@ -61,8 +56,7 @@
 
 bool ManagePasswordsIconViews::OnMousePressed(const ui::MouseEvent& event) {
   bool result = BubbleIconView::OnMousePressed(event);
-  if (IsBubbleShowing())
-    ManagePasswordsBubbleView::CloseBubble();
+  ManagePasswordsBubbleView::CloseBubble();
   return result;
 }
 
@@ -72,8 +66,8 @@
   // button.
   if (event.key_code() == ui::VKEY_SPACE)
     return true;
-  if (event.key_code() == ui::VKEY_RETURN && active()) {
-    // If the icon is active, it should transfer its focus to the bubble.
+  if (event.key_code() == ui::VKEY_RETURN && IsBubbleShowing()) {
+    // If the bubble's open, the icon should transfer its focus to the bubble.
     // If it still somehow got this key event, the bubble shouldn't be reopened.
     return true;
   }
@@ -90,6 +84,6 @@
 
 void ManagePasswordsIconViews::AboutToRequestFocusFromTabTraversal(
     bool reverse) {
-  if (active())
+  if (IsBubbleShowing())
     ManagePasswordsBubbleView::ActivateBubble();
 }
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_views.h b/chrome/browser/ui/views/passwords/manage_passwords_icon_views.h
index 2d5db46..b0a1094 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_icon_views.h
+++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_views.h
@@ -23,7 +23,6 @@
 
   // ManagePasswordsIconView:
   void SetState(password_manager::ui::State state) override;
-  void SetActive(bool active) override;
 
   // BubbleIconView:
   void OnExecuting(BubbleIconView::ExecuteSource source) override;
diff --git a/chrome/browser/ui/views/tab_dialogs_views.cc b/chrome/browser/ui/views/tab_dialogs_views.cc
index d739fb0..d829ee5 100644
--- a/chrome/browser/ui/views/tab_dialogs_views.cc
+++ b/chrome/browser/ui/views/tab_dialogs_views.cc
@@ -60,8 +60,8 @@
     ManagePasswordsBubbleView::CloseBubble();
   }
   ManagePasswordsBubbleView::ShowBubble(
-      web_contents_, user_action ? ManagePasswordsBubbleModel::USER_ACTION
-                                 : ManagePasswordsBubbleModel::AUTOMATIC);
+      web_contents_, user_action ? ManagePasswordsBubbleView::USER_GESTURE
+                                 : ManagePasswordsBubbleView::AUTOMATIC);
 }
 
 void TabDialogsViews::HideManagePasswordsBubble() {
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.cc b/chrome/browser/ui/views/translate/translate_bubble_view.cc
index 3069475..c8689b171 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.cc
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.cc
@@ -78,7 +78,7 @@
     content::WebContents* web_contents,
     translate::TranslateStep step,
     translate::TranslateErrors::Type error_type,
-    bool is_user_gesture) {
+    DisplayReason reason) {
   if (translate_bubble_view_) {
     // When the user reads the advanced setting panel, the bubble should not be
     // changed because they are focusing on the bubble.
@@ -97,7 +97,7 @@
     return;
   } else {
     if (step == translate::TRANSLATE_STEP_AFTER_TRANSLATE &&
-        !is_user_gesture) {
+        reason == AUTOMATIC) {
       return;
     }
   }
@@ -119,10 +119,8 @@
                                                       model.Pass(),
                                                       error_type,
                                                       web_contents);
-  if (is_user_gesture)
-    views::BubbleDelegateView::CreateBubble(view)->Show();
-  else
-    views::BubbleDelegateView::CreateBubble(view)->ShowInactive();
+  views::BubbleDelegateView::CreateBubble(view);
+  view->ShowForReason(reason);
 }
 
 // static
diff --git a/chrome/browser/ui/views/translate/translate_bubble_view.h b/chrome/browser/ui/views/translate/translate_bubble_view.h
index 25516c5..c42430b 100644
--- a/chrome/browser/ui/views/translate/translate_bubble_view.h
+++ b/chrome/browser/ui/views/translate/translate_bubble_view.h
@@ -61,7 +61,7 @@
                          content::WebContents* web_contents,
                          translate::TranslateStep step,
                          translate::TranslateErrors::Type error_type,
-                         bool is_user_gesture);
+                         DisplayReason reason);
 
   // Closes the current bubble if existing.
   static void CloseBubble();
diff --git a/chrome/browser/ui/views/translate/translate_icon_view.cc b/chrome/browser/ui/views/translate/translate_icon_view.cc
index c4acdca..b406154 100644
--- a/chrome/browser/ui/views/translate/translate_icon_view.cc
+++ b/chrome/browser/ui/views/translate/translate_icon_view.cc
@@ -23,10 +23,6 @@
 
 TranslateIconView::~TranslateIconView() {}
 
-void TranslateIconView::SetToggled(bool on) {
-  SetActiveInternal(on);
-}
-
 void TranslateIconView::OnExecuting(
     BubbleIconView::ExecuteSource execute_source) {}
 
diff --git a/chrome/browser/ui/views/translate/translate_icon_view.h b/chrome/browser/ui/views/translate/translate_icon_view.h
index f981c4a..764fdf2 100644
--- a/chrome/browser/ui/views/translate/translate_icon_view.h
+++ b/chrome/browser/ui/views/translate/translate_icon_view.h
@@ -17,9 +17,6 @@
   explicit TranslateIconView(CommandUpdater* command_updater);
   ~TranslateIconView() override;
 
-  // Toggles the icon on or off.
-  void SetToggled(bool on);
-
  protected:
   // BubbleIconView:
   void OnExecuting(BubbleIconView::ExecuteSource execute_source) override;
diff --git a/chrome/browser/ui/webui/help/help_handler.cc b/chrome/browser/ui/webui/help/help_handler.cc
index 8499e6c..6199d3c 100644
--- a/chrome/browser/ui/webui/help/help_handler.cc
+++ b/chrome/browser/ui/webui/help/help_handler.cc
@@ -21,6 +21,7 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -44,10 +45,6 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "v8/include/v8.h"
 
-#if defined(OS_MACOSX)
-#include "chrome/browser/mac/obsolete_system.h"
-#endif
-
 #if defined(OS_CHROMEOS)
 #include "base/files/file_util_proxy.h"
 #include "base/i18n/time_formatting.h"
@@ -291,14 +288,12 @@
                                  l10n_util::GetStringUTF16(resources[i].ids));
   }
 
-#if defined(OS_MACOSX)
-  localized_strings->SetString(
-      "updateObsoleteSystem",
-      ObsoleteSystemMac::LocalizedObsoleteSystemString());
-  localized_strings->SetString(
-      "updateObsoleteSystemURL",
-      chrome::kMac32BitDeprecationURL);
-#endif
+  if (ObsoleteSystem::IsObsoleteNowOrSoon()) {
+    localized_strings->SetString("updateObsoleteSystem",
+                                 ObsoleteSystem::LocalizedObsoleteString());
+    localized_strings->SetString("updateObsoleteSystemURL",
+                                 ObsoleteSystem::GetLinkURL());
+  }
 
   localized_strings->SetString(
       "browserVersion",
@@ -453,16 +448,12 @@
   RequestUpdate(NULL);
 #endif
 
-#if defined(OS_MACOSX)
   web_ui()->CallJavascriptFunction(
       "help.HelpPage.setObsoleteSystem",
-      base::FundamentalValue(ObsoleteSystemMac::Is32BitObsoleteNowOrSoon() &&
-                             ObsoleteSystemMac::Has32BitOnlyCPU()));
+      base::FundamentalValue(ObsoleteSystem::IsObsoleteNowOrSoon()));
   web_ui()->CallJavascriptFunction(
       "help.HelpPage.setObsoleteSystemEndOfTheLine",
-      base::FundamentalValue(ObsoleteSystemMac::Is32BitObsoleteNowOrSoon() &&
-                             ObsoleteSystemMac::Is32BitEndOfTheLine()));
-#endif
+      base::FundamentalValue(ObsoleteSystem::IsObsoleteNowOrSoon()));
 
 #if defined(OS_CHROMEOS)
   web_ui()->CallJavascriptFunction(
diff --git a/chrome/browser/ui/webui/help/version_updater_mac.mm b/chrome/browser/ui/webui/help/version_updater_mac.mm
index ea76b22..be9c08f 100644
--- a/chrome/browser/ui/webui/help/version_updater_mac.mm
+++ b/chrome/browser/ui/webui/help/version_updater_mac.mm
@@ -8,7 +8,7 @@
 #include "base/bind_helpers.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #import "chrome/browser/mac/keystone_glue.h"
-#include "chrome/browser/mac/obsolete_system.h"
+#include "chrome/browser/obsolete_system/obsolete_system.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -224,8 +224,7 @@
 }
 
 void VersionUpdaterMac::UpdateShowPromoteButton() {
-  if (ObsoleteSystemMac::Has32BitOnlyCPU() &&
-      ObsoleteSystemMac::Is32BitEndOfTheLine()) {
+  if (ObsoleteSystem::IsObsoleteNowOrSoon()) {
     // Promotion is moot upon reaching the end of the line.
     show_promote_button_ = false;
     return;
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index fa815e1..bd52e04 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -246,9 +246,7 @@
   query_result_manager_->GetSupportedCastModes(&cast_modes_);
   if (ui_initialized_) {
     handler_->UpdateCastModes(
-        cast_modes_, presentation_request_
-                         ? GetHostFromURL(presentation_request_->frame_url())
-                         : std::string());
+        cast_modes_, GetHostFromURL(GetFrameURL()));
   }
 }
 
@@ -401,7 +399,8 @@
   requesting_route_for_default_source_ = false;
   current_route_request_id_ = -1;
 
-  base::string16 host = base::UTF8ToUTF16(GetTruncatedHostFromURL(frame_url_));
+  base::string16 host = base::UTF8ToUTF16(GetTruncatedHostFromURL(
+      GetFrameURL()));
 
   // TODO(apacible): Update error messages based on current cast mode
   // (e.g. desktop).
@@ -419,8 +418,13 @@
   handler_->NotifyRouteCreationTimeout();
 }
 
+GURL MediaRouterUI::GetFrameURL() const {
+  return presentation_request_ ? presentation_request_->frame_url() :
+      GURL();
+}
+
 std::string MediaRouterUI::GetFrameURLHost() const {
-  return GetHostFromURL(frame_url_);
+  return GetHostFromURL(GetFrameURL());
 }
 
 const std::string& MediaRouterUI::GetRouteProviderExtensionId() const {
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index 4c8ef33..f18ce31 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -108,7 +108,6 @@
   bool HasPendingRouteRequest() const {
     return current_route_request_id_ != -1;
   }
-  const GURL& frame_url() const { return frame_url_; }
   const std::vector<MediaSinkWithCastModes>& sinks() const { return sinks_; }
   const std::vector<MediaRoute>& routes() const { return routes_; }
   const std::set<MediaCastMode>& cast_modes() const { return cast_modes_; }
@@ -175,6 +174,10 @@
   // |handler_|.
   void UpdateCastModes();
 
+  // Returns the default presentation request's frame URL if there is one.
+  // Otherwise returns an empty GURL.
+  GURL GetFrameURL() const;
+
   // Owned by the |web_ui| passed in the ctor, and guaranteed to be deleted
   // only after it has deleted |this|.
   MediaRouterWebUIMessageHandler* handler_;
@@ -199,7 +202,6 @@
   std::vector<MediaSinkWithCastModes> sinks_;
   std::vector<MediaRoute> routes_;
   CastModeSet cast_modes_;
-  GURL frame_url_;
 
   scoped_ptr<QueryResultManager> query_result_manager_;
 
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 199a534..095cb14 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -22,7 +22,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/value_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/auto_launch_trial.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/custom_home_pages_table_model.h"
@@ -134,7 +133,6 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/extensions/settings_api_helpers.h"
-#include "chrome/installer/util/auto_launch_util.h"
 #include "content/public/browser/browser_url_handler.h"
 #endif  // defined(OS_WIN)
 
@@ -176,6 +174,9 @@
     : page_initialized_(false),
       template_url_service_(NULL),
       cloud_print_mdns_ui_enabled_(false),
+#if defined(OS_CHROMEOS)
+      enable_factory_reset_(false),
+#endif  // defined(OS_CHROMEOS)
       signin_observer_(this),
       weak_ptr_factory_(this) {
   default_browser_worker_ = new ShellIntegration::DefaultBrowserWorker(this);
@@ -229,7 +230,6 @@
     { "advancedSectionTitlePrivacy",
       IDS_OPTIONS_ADVANCED_SECTION_TITLE_PRIVACY },
     { "advancedSectionTitleSystem", IDS_OPTIONS_ADVANCED_SECTION_TITLE_SYSTEM },
-    { "autoLaunchText", IDS_AUTOLAUNCH_TEXT },
     { "autoOpenFileTypesInfo", IDS_OPTIONS_OPEN_FILE_TYPES_AUTOMATICALLY },
     { "autoOpenFileTypesResetToDefault",
       IDS_OPTIONS_AUTOOPENFILETYPES_RESETTODEFAULT },
@@ -912,15 +912,6 @@
 
 #if defined(OS_WIN)
   ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->AddObserver(this);
-
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-  if (!command_line.HasSwitch(switches::kUserDataDir)) {
-    BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
-        base::Bind(&BrowserOptionsHandler::CheckAutoLaunch,
-                   weak_ptr_factory_.GetWeakPtr(),
-                   profile->GetPath()));
-  }
 #endif
 
   // No preferences below this point may be modified by guest profiles.
@@ -1020,9 +1011,10 @@
   SetupAccessibilityFeatures();
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
-  if (!connector->IsEnterpriseManaged() &&
+  enable_factory_reset_ = !connector->IsEnterpriseManaged() &&
       !user_manager::UserManager::Get()->IsLoggedInAsGuest() &&
-      !user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) {
+      !user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser();
+  if (enable_factory_reset_) {
     web_ui()->CallJavascriptFunction(
         "BrowserOptions.enableFactoryResetSection");
   }
@@ -1049,50 +1041,6 @@
 #endif
 }
 
-// static
-void BrowserOptionsHandler::CheckAutoLaunch(
-    base::WeakPtr<BrowserOptionsHandler> weak_this,
-    const base::FilePath& profile_path) {
-#if defined(OS_WIN)
-  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
-
-  // Auto-launch is not supported for secondary profiles yet.
-  if (profile_path.BaseName().value() !=
-          base::ASCIIToUTF16(chrome::kInitialProfile)) {
-    return;
-  }
-
-  // Pass in weak pointer to this to avoid race if BrowserOptionsHandler is
-  // deleted.
-  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
-      base::Bind(&BrowserOptionsHandler::CheckAutoLaunchCallback,
-                 weak_this,
-                 auto_launch_trial::IsInAutoLaunchGroup(),
-                 auto_launch_util::AutoStartRequested(
-                     profile_path.BaseName().value(),
-                     true,  // Window requested.
-                     base::FilePath())));
-#endif
-}
-
-void BrowserOptionsHandler::CheckAutoLaunchCallback(
-    bool is_in_auto_launch_group,
-    bool will_launch_at_login) {
-#if defined(OS_WIN)
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  if (is_in_auto_launch_group) {
-    web_ui()->RegisterMessageCallback("toggleAutoLaunch",
-        base::Bind(&BrowserOptionsHandler::ToggleAutoLaunch,
-        base::Unretained(this)));
-
-    base::FundamentalValue enabled(will_launch_at_login);
-    web_ui()->CallJavascriptFunction("BrowserOptions.updateAutoLaunchState",
-                                     enabled);
-  }
-#endif
-}
-
 bool BrowserOptionsHandler::ShouldShowSetDefaultBrowser() {
 #if defined(OS_CHROMEOS)
   // We're always the default browser on ChromeOS.
@@ -1329,26 +1277,6 @@
   SendProfilesInfo();
 }
 
-void BrowserOptionsHandler::ToggleAutoLaunch(const base::ListValue* args) {
-#if defined(OS_WIN)
-  if (!auto_launch_trial::IsInAutoLaunchGroup())
-    return;
-
-  bool enable;
-  CHECK_EQ(args->GetSize(), 1U);
-  CHECK(args->GetBoolean(0, &enable));
-
-  Profile* profile = Profile::FromWebUI(web_ui());
-  content::BrowserThread::PostTask(
-      content::BrowserThread::FILE, FROM_HERE,
-      enable ?
-          base::Bind(&auto_launch_util::EnableForegroundStartAtLogin,
-                     profile->GetPath().BaseName().value(), base::FilePath()) :
-          base::Bind(&auto_launch_util::DisableForegroundStartAtLogin,
-                      profile->GetPath().BaseName().value()));
-#endif  // OS_WIN
-}
-
 scoped_ptr<base::ListValue> BrowserOptionsHandler::GetProfilesInfoList() {
   ProfileInfoCache& cache =
       g_browser_process->profile_manager()->GetProfileInfoCache();
@@ -1911,9 +1839,7 @@
 
 void BrowserOptionsHandler::PerformFactoryResetRestart(
     const base::ListValue* args) {
-  policy::BrowserPolicyConnectorChromeOS* connector =
-      g_browser_process->platform_part()->browser_policy_connector_chromeos();
-  if (connector->IsEnterpriseManaged())
+  if (!enable_factory_reset_)
     return;
 
   PrefService* prefs = g_browser_process->local_state();
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.h b/chrome/browser/ui/webui/options/browser_options_handler.h
index 4acd11f..2c02bc47 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.h
+++ b/chrome/browser/ui/webui/options/browser_options_handler.h
@@ -164,23 +164,6 @@
   // Sets the search engine at the given index to be default. Called from WebUI.
   void SetDefaultSearchEngine(const base::ListValue* args);
 
-  // Enables/disables auto-launching of Chrome on computer startup.
-  void ToggleAutoLaunch(const base::ListValue* args);
-
-  // Checks (on the file thread) whether the user is in the auto-launch trial
-  // and whether Chrome is set to auto-launch at login. Gets a reply on the UI
-  // thread (see CheckAutoLaunchCallback). A weak pointer to this is passed in
-  // as a parameter to avoid the need to lock between this function and the
-  // destructor. |profile_path| is the full path to the current profile.
-  static void CheckAutoLaunch(base::WeakPtr<BrowserOptionsHandler> weak_this,
-                              const base::FilePath& profile_path);
-
-  // Sets up (on the UI thread) the necessary bindings for toggling auto-launch
-  // (if the user is part of the auto-launch and makes sure the HTML UI knows
-  // whether Chrome will auto-launch at login.
-  void CheckAutoLaunchCallback(bool is_in_auto_launch_group,
-                               bool will_launch_at_login);
-
   // Returns the string ID for the given default browser state.
   int StatusStringIdForState(ShellIntegration::DefaultWebClientState state);
 
@@ -411,6 +394,9 @@
   PrefChangeRegistrar profile_pref_registrar_;
 #if defined(OS_CHROMEOS)
   scoped_ptr<policy::PolicyChangeRegistrar> policy_registrar_;
+
+  // Whether factory reset can be performed.
+  bool enable_factory_reset_;
 #endif
 
   ScopedObserver<SigninManagerBase, SigninManagerBase::Observer>
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 314abd0f..4072783 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -603,8 +603,6 @@
       'browser/mac/mac_startup_profiler.h',
       'browser/mac/master_prefs.h',
       'browser/mac/master_prefs.mm',
-      'browser/mac/obsolete_system.cc',
-      'browser/mac/obsolete_system.h',
       'browser/mac/relauncher.cc',
       'browser/mac/relauncher.h',
       'browser/mac/security_wrappers.cc',
@@ -1031,8 +1029,6 @@
     'chrome_browser_non_mobile_sources': [
       'browser/accessibility/invert_bubble_prefs.cc',
       'browser/accessibility/invert_bubble_prefs.h',
-      'browser/auto_launch_trial.cc',
-      'browser/auto_launch_trial.h',
       'browser/background/background_contents.cc',
       'browser/background/background_contents.h',
       'browser/banners/app_banner_data_fetcher_desktop.cc',
@@ -1240,6 +1236,10 @@
       'browser/net/firefox_proxy_settings.h',
       'browser/net/utility_process_mojo_proxy_resolver_factory.cc',
       'browser/net/utility_process_mojo_proxy_resolver_factory.h',
+      'browser/obsolete_system/obsolete_system.h',
+      'browser/obsolete_system/obsolete_system_linux.cc',
+      'browser/obsolete_system/obsolete_system_mac.cc',
+      'browser/obsolete_system/obsolete_system_win.cc',
       'browser/pdf/pdf_extension_util.cc',
       'browser/pdf/pdf_extension_util.h',
       'browser/permissions/permission_bubble_request_impl.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 749880e7..d804fe16 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -1342,7 +1342,6 @@
     'chrome_browser_ui_linux_sources': [
       'browser/ui/certificate_dialogs.cc',
       'browser/ui/certificate_dialogs.h',
-      'browser/ui/startup/autolaunch_prompt.cc',
       'browser/ui/views/apps/chrome_app_window_client_views.cc',
       'browser/ui/webui/certificate_viewer_ui.cc',
       'browser/ui/webui/certificate_viewer_ui.h',
@@ -1444,7 +1443,6 @@
       # manage_passwords_decoration.mm
       'browser/ui/passwords/manage_passwords_icon.cc',
       'browser/ui/passwords/manage_passwords_icon.h',
-      'browser/ui/startup/autolaunch_prompt.cc',
       'browser/ui/web_contents_sizer.mm',
     ],
     'chrome_browser_ui_media_router_sources': [
@@ -1664,8 +1662,6 @@
       'browser/ui/settings_window_manager_observer.h',
       'browser/ui/singleton_tabs.cc',
       'browser/ui/singleton_tabs.h',
-      'browser/ui/startup/autolaunch_prompt.h',
-      'browser/ui/startup/autolaunch_prompt_win.cc',
       'browser/ui/startup/bad_flags_prompt.cc',
       'browser/ui/startup/bad_flags_prompt.h',
       'browser/ui/startup/google_api_keys_infobar_delegate.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 1fdfe380..6d49d900 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1302,11 +1302,6 @@
 const char kWindows8Search[]                = "windows8-search";
 #endif  // defined(OS_WIN)
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
-// Enable tab discarding when system is under memory pressure.
-const char kEnableTabDiscarding[] = "enable-tab-discarding";
-#endif  // defined(OS_WIN) || defined(OS_MACOSX)
-
 #if defined(ENABLE_IPC_FUZZER)
 // Specifies the testcase used by the IPC fuzzer.
 const char kIpcFuzzerTestcase[]             = "ipc-fuzzer-testcase";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 461eb33..1813c9a 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -370,10 +370,6 @@
 extern const char kWindows8Search[];
 #endif  // defined(OS_WIN)
 
-#if defined(OS_WIN) || defined(OS_MACOSX)
-extern const char kEnableTabDiscarding[];
-#endif  // defined(OS_WIN) || defined(OS_MACOSX)
-
 #if defined(ENABLE_IPC_FUZZER)
 extern const char kIpcFuzzerTestcase[];
 #endif
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 7e325e8..94952ba 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1601,10 +1601,6 @@
 // The "major.minor" OS version for which the welcome page was last shown.
 const char kLastWelcomedOSVersion[] = "browser.last_welcomed_os_version";
 
-// An int that stores how often we've shown the "Chrome is configured to
-// auto-launch" infobar.
-const char kShownAutoLaunchInfobar[] = "browser.shown_autolaunch_infobar";
-
 // Boolean that specifies whether or not showing the welcome page following an
 // OS upgrade is enabled. True by default. May be set by master_preferences or
 // overridden by the WelcomePageOnOSUpgradeEnabled policy setting.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 0b43272..7c200ed 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -653,7 +653,6 @@
 
 #if defined(OS_WIN)
 extern const char kLastWelcomedOSVersion[];
-extern const char kShownAutoLaunchInfobar[];
 extern const char kWelcomePageOnOSUpgradeEnabled[];
 #endif
 
diff --git a/chrome/common/safe_browsing/download_protection_util.cc b/chrome/common/safe_browsing/download_protection_util.cc
index 9fa1e4d2..12fce462 100644
--- a/chrome/common/safe_browsing/download_protection_util.cc
+++ b/chrome/common/safe_browsing/download_protection_util.cc
@@ -191,6 +191,76 @@
   EXTENSION_U3P,
   EXTENSION_VBSCRIPT,
   EXTENSION_WORKFLOW,
+  EXTENSION_001,
+  EXTENSION_ACE,
+  EXTENSION_ARC,
+  EXTENSION_B64,
+  EXTENSION_BALZ,
+  EXTENSION_BHX,
+  EXTENSION_BZ,
+  EXTENSION_FAT,
+  EXTENSION_HFS,
+  EXTENSION_HQX,
+  EXTENSION_ISO,
+  EXTENSION_LPAQ1,
+  EXTENSION_LPAQ5,
+  EXTENSION_LPAQ8,
+  EXTENSION_MIM,
+  EXTENSION_NTFS,
+  EXTENSION_PAQ8F,
+  EXTENSION_PAQ8JD,
+  EXTENSION_PAQ8L,
+  EXTENSION_PAQ8O,
+  EXTENSION_PEA,
+  EXTENSION_PET,
+  EXTENSION_PUP,
+  EXTENSION_QUAD,
+  EXTENSION_R00,
+  EXTENSION_R01,
+  EXTENSION_R02,
+  EXTENSION_R03,
+  EXTENSION_R04,
+  EXTENSION_R05,
+  EXTENSION_R06,
+  EXTENSION_R07,
+  EXTENSION_R08,
+  EXTENSION_R09,
+  EXTENSION_R10,
+  EXTENSION_R11,
+  EXTENSION_R12,
+  EXTENSION_R13,
+  EXTENSION_R14,
+  EXTENSION_R15,
+  EXTENSION_R16,
+  EXTENSION_R17,
+  EXTENSION_R18,
+  EXTENSION_R19,
+  EXTENSION_R20,
+  EXTENSION_R21,
+  EXTENSION_R22,
+  EXTENSION_R23,
+  EXTENSION_R24,
+  EXTENSION_R25,
+  EXTENSION_R26,
+  EXTENSION_R27,
+  EXTENSION_R28,
+  EXTENSION_R29,
+  EXTENSION_SLP,
+  EXTENSION_SQUASHFS,
+  EXTENSION_SWM,
+  EXTENSION_TPZ,
+  EXTENSION_TXZ,
+  EXTENSION_TZ,
+  EXTENSION_UDF,
+  EXTENSION_UU,
+  EXTENSION_UUE,
+  EXTENSION_VHD,
+  EXTENSION_VMDK,
+  EXTENSION_WRC,
+  EXTENSION_XAR,
+  EXTENSION_XXE,
+  EXTENSION_ZIPX,
+  EXTENSION_ZPAQ,
 
   // New values go above this one.
   EXTENSION_MAX
@@ -205,7 +275,9 @@
 
 const SafeBrowsingFiletype kSafeBrowsingFileTypes[] = {
     // KEEP THIS LIST SORTED!
+    {FILE_PATH_LITERAL(".001"), EXTENSION_001, true, true},
     {FILE_PATH_LITERAL(".7z"), EXTENSION_7Z, true, true},
+    {FILE_PATH_LITERAL(".ace"), EXTENSION_ACE, true, true},
     {FILE_PATH_LITERAL(".action"), EXTENSION_ACTION, false, false},  // UMA.
     {FILE_PATH_LITERAL(".ade"), EXTENSION_ADE, true, false},
     {FILE_PATH_LITERAL(".adp"), EXTENSION_ADP, true, false},
@@ -213,13 +285,18 @@
     {FILE_PATH_LITERAL(".app"), EXTENSION_APP, true, false},
     {FILE_PATH_LITERAL(".application"), EXTENSION_APPLICATION, true, false},
     {FILE_PATH_LITERAL(".appref-ms"), EXTENSION_APPREF_MS, true, false},
+    {FILE_PATH_LITERAL(".arc"), EXTENSION_ARC, true, true},
     {FILE_PATH_LITERAL(".arj"), EXTENSION_ARJ, true, true},
     {FILE_PATH_LITERAL(".asp"), EXTENSION_ASP, true, false},
     {FILE_PATH_LITERAL(".asx"), EXTENSION_ASX, true, false},
+    {FILE_PATH_LITERAL(".b64"), EXTENSION_B64, true, true},
+    {FILE_PATH_LITERAL(".balz"), EXTENSION_BALZ, true, true},
     {FILE_PATH_LITERAL(".bas"), EXTENSION_BAS, true, false},
     {FILE_PATH_LITERAL(".bash"), EXTENSION_BASH, true, false},
     {FILE_PATH_LITERAL(".bat"), EXTENSION_BAT, true, false},
+    {FILE_PATH_LITERAL(".bhx"), EXTENSION_BHX, true, true},
     {FILE_PATH_LITERAL(".bin"), EXTENSION_BIN, false, false},  // UMA only.
+    {FILE_PATH_LITERAL(".bz"), EXTENSION_BZ, true, true},
     {FILE_PATH_LITERAL(".bz2"), EXTENSION_BZ2, true, true},
     {FILE_PATH_LITERAL(".bzip2"), EXTENSION_BZIP2, true, true},
     {FILE_PATH_LITERAL(".cab"), EXTENSION_CAB, true, true},
@@ -242,13 +319,16 @@
     {FILE_PATH_LITERAL(".drv"), EXTENSION_DRV, true, false},
     {FILE_PATH_LITERAL(".efi"), EXTENSION_EFI, true, false},
     {FILE_PATH_LITERAL(".exe"), EXTENSION_EXE, true, false},
+    {FILE_PATH_LITERAL(".fat"), EXTENSION_FAT, true, true},
     {FILE_PATH_LITERAL(".fon"), EXTENSION_FON, true, false},
     {FILE_PATH_LITERAL(".fxp"), EXTENSION_FXP, true, false},
     {FILE_PATH_LITERAL(".gadget"), EXTENSION_GADGET, true, false},
     {FILE_PATH_LITERAL(".grp"), EXTENSION_GRP, true, false},
     {FILE_PATH_LITERAL(".gz"), EXTENSION_GZ, true, true},
     {FILE_PATH_LITERAL(".gzip"), EXTENSION_GZIP, true, true},
+    {FILE_PATH_LITERAL(".hfs"), EXTENSION_HFS, true, true},
     {FILE_PATH_LITERAL(".hlp"), EXTENSION_HLP, true, false},
+    {FILE_PATH_LITERAL(".hqx"), EXTENSION_HQX, true, true},
     {FILE_PATH_LITERAL(".hta"), EXTENSION_HTA, true, false},
     {FILE_PATH_LITERAL(".htt"), EXTENSION_HTT, true, false},
     {FILE_PATH_LITERAL(".inf"), EXTENSION_INF, true, false},
@@ -256,6 +336,7 @@
     {FILE_PATH_LITERAL(".ins"), EXTENSION_INS, true, false},
     {FILE_PATH_LITERAL(".inx"), EXTENSION_INX, false, false},  // UMA only.
     {FILE_PATH_LITERAL(".ipa"), EXTENSION_IPA, false, false},  // UMA only.
+    {FILE_PATH_LITERAL(".iso"), EXTENSION_ISO, true, true},
     {FILE_PATH_LITERAL(".isp"), EXTENSION_ISP, true, false},
     {FILE_PATH_LITERAL(".isu"), EXTENSION_ISU, false, false},  // UMA only.
     {FILE_PATH_LITERAL(".jar"), EXTENSION_JAR, true, false},
@@ -267,6 +348,9 @@
     {FILE_PATH_LITERAL(".lha"), EXTENSION_LHA, true, true},
     {FILE_PATH_LITERAL(".lnk"), EXTENSION_LNK, true, false},
     {FILE_PATH_LITERAL(".local"), EXTENSION_LOCAL, true, false},
+    {FILE_PATH_LITERAL(".lpaq1"), EXTENSION_LPAQ1, true, true},
+    {FILE_PATH_LITERAL(".lpaq5"), EXTENSION_LPAQ5, true, true},
+    {FILE_PATH_LITERAL(".lpaq8"), EXTENSION_LPAQ8, true, true},
     {FILE_PATH_LITERAL(".lzh"), EXTENSION_LZH, true, true},
     {FILE_PATH_LITERAL(".lzma"), EXTENSION_LZMA, true, true},
     {FILE_PATH_LITERAL(".mad"), EXTENSION_MAD, true, false},
@@ -289,6 +373,7 @@
     {FILE_PATH_LITERAL(".mdz"), EXTENSION_MDZ, true, false},
     {FILE_PATH_LITERAL(".mht"), EXTENSION_MHT, true, false},
     {FILE_PATH_LITERAL(".mhtml"), EXTENSION_MHTML, true, false},
+    {FILE_PATH_LITERAL(".mim"), EXTENSION_MIM, true, true},
     {FILE_PATH_LITERAL(".mmc"), EXTENSION_MMC, true, false},
     {FILE_PATH_LITERAL(".mof"), EXTENSION_MOF, true, false},
     {FILE_PATH_LITERAL(".msc"), EXTENSION_MSC, true, false},
@@ -301,14 +386,21 @@
     {FILE_PATH_LITERAL(".msi"), EXTENSION_MSI, true, false},
     {FILE_PATH_LITERAL(".msp"), EXTENSION_MSP, true, false},
     {FILE_PATH_LITERAL(".mst"), EXTENSION_MST, true, false},
+    {FILE_PATH_LITERAL(".ntfs"), EXTENSION_NTFS, true, true},
     {FILE_PATH_LITERAL(".ocx"), EXTENSION_OCX, true, false},
     {FILE_PATH_LITERAL(".ops"), EXTENSION_OPS, true, false},
     {FILE_PATH_LITERAL(".osx"), EXTENSION_OSX, true, false},
     {FILE_PATH_LITERAL(".out"), EXTENSION_OUT, false, false},  // UMA only.
     {FILE_PATH_LITERAL(".pad"), EXTENSION_PAD, false, false},  // UMA only.
     {FILE_PATH_LITERAL(".paf"), EXTENSION_PAF, false, false},  // UMA only.
+    {FILE_PATH_LITERAL(".paq8f"), EXTENSION_PAQ8F, true, true},
+    {FILE_PATH_LITERAL(".paq8jd"), EXTENSION_PAQ8JD, true, true},
+    {FILE_PATH_LITERAL(".paq8l"), EXTENSION_PAQ8L, true, true},
+    {FILE_PATH_LITERAL(".paq8o"), EXTENSION_PAQ8O, true, true},
     {FILE_PATH_LITERAL(".partial"), EXTENSION_PARTIAL, true, false},
     {FILE_PATH_LITERAL(".pcd"), EXTENSION_PCD, true, false},
+    {FILE_PATH_LITERAL(".pea"), EXTENSION_PEA, true, true},
+    {FILE_PATH_LITERAL(".pet"), EXTENSION_PET, true, true},
     {FILE_PATH_LITERAL(".pif"), EXTENSION_PIF, true, false},
     {FILE_PATH_LITERAL(".pkg"), EXTENSION_PKG, true, false},
     {FILE_PATH_LITERAL(".pl"), EXTENSION_PL, true, false},
@@ -322,9 +414,41 @@
     {FILE_PATH_LITERAL(".psc1"), EXTENSION_PSC1, true, false},
     {FILE_PATH_LITERAL(".psc2"), EXTENSION_PSC2, true, false},
     {FILE_PATH_LITERAL(".pst"), EXTENSION_PST, true, false},
+    {FILE_PATH_LITERAL(".pup"), EXTENSION_PUP, true, true},
     {FILE_PATH_LITERAL(".py"), EXTENSION_PY, true, false},
     {FILE_PATH_LITERAL(".pyc"), EXTENSION_PYC, true, false},
     {FILE_PATH_LITERAL(".pyw"), EXTENSION_PYW, true, false},
+    {FILE_PATH_LITERAL(".quad"), EXTENSION_QUAD, true, true},
+    {FILE_PATH_LITERAL(".r00"), EXTENSION_R00, true, true},
+    {FILE_PATH_LITERAL(".r01"), EXTENSION_R01, true, true},
+    {FILE_PATH_LITERAL(".r02"), EXTENSION_R02, true, true},
+    {FILE_PATH_LITERAL(".r03"), EXTENSION_R03, true, true},
+    {FILE_PATH_LITERAL(".r04"), EXTENSION_R04, true, true},
+    {FILE_PATH_LITERAL(".r05"), EXTENSION_R05, true, true},
+    {FILE_PATH_LITERAL(".r06"), EXTENSION_R06, true, true},
+    {FILE_PATH_LITERAL(".r07"), EXTENSION_R07, true, true},
+    {FILE_PATH_LITERAL(".r08"), EXTENSION_R08, true, true},
+    {FILE_PATH_LITERAL(".r09"), EXTENSION_R09, true, true},
+    {FILE_PATH_LITERAL(".r10"), EXTENSION_R10, true, true},
+    {FILE_PATH_LITERAL(".r11"), EXTENSION_R11, true, true},
+    {FILE_PATH_LITERAL(".r12"), EXTENSION_R12, true, true},
+    {FILE_PATH_LITERAL(".r13"), EXTENSION_R13, true, true},
+    {FILE_PATH_LITERAL(".r14"), EXTENSION_R14, true, true},
+    {FILE_PATH_LITERAL(".r15"), EXTENSION_R15, true, true},
+    {FILE_PATH_LITERAL(".r16"), EXTENSION_R16, true, true},
+    {FILE_PATH_LITERAL(".r17"), EXTENSION_R17, true, true},
+    {FILE_PATH_LITERAL(".r18"), EXTENSION_R18, true, true},
+    {FILE_PATH_LITERAL(".r19"), EXTENSION_R19, true, true},
+    {FILE_PATH_LITERAL(".r20"), EXTENSION_R20, true, true},
+    {FILE_PATH_LITERAL(".r21"), EXTENSION_R21, true, true},
+    {FILE_PATH_LITERAL(".r22"), EXTENSION_R22, true, true},
+    {FILE_PATH_LITERAL(".r23"), EXTENSION_R23, true, true},
+    {FILE_PATH_LITERAL(".r24"), EXTENSION_R24, true, true},
+    {FILE_PATH_LITERAL(".r25"), EXTENSION_R25, true, true},
+    {FILE_PATH_LITERAL(".r26"), EXTENSION_R26, true, true},
+    {FILE_PATH_LITERAL(".r27"), EXTENSION_R27, true, true},
+    {FILE_PATH_LITERAL(".r28"), EXTENSION_R28, true, true},
+    {FILE_PATH_LITERAL(".r29"), EXTENSION_R29, true, true},
     {FILE_PATH_LITERAL(".rar"), EXTENSION_RAR, true, true},
     {FILE_PATH_LITERAL(".rb"), EXTENSION_RB, true, false},
     {FILE_PATH_LITERAL(".reg"), EXTENSION_REG, true, false},
@@ -337,9 +461,12 @@
     {FILE_PATH_LITERAL(".shar"), EXTENSION_SHAR, true, false},
     {FILE_PATH_LITERAL(".shb"), EXTENSION_SHB, true, false},
     {FILE_PATH_LITERAL(".shs"), EXTENSION_SHS, true, false},
+    {FILE_PATH_LITERAL(".slp"), EXTENSION_SLP, true, true},
     {FILE_PATH_LITERAL(".spl"), EXTENSION_SPL, true, false},
+    {FILE_PATH_LITERAL(".squashfs"), EXTENSION_SQUASHFS, true, true},
     {FILE_PATH_LITERAL(".svg"), EXTENSION_SVG, true, false},
     {FILE_PATH_LITERAL(".swf"), EXTENSION_SWF, true, false},
+    {FILE_PATH_LITERAL(".swm"), EXTENSION_SWM, true, true},
     {FILE_PATH_LITERAL(".sys"), EXTENSION_SYS, true, false},
     {FILE_PATH_LITERAL(".tar"), EXTENSION_TAR, true, true},
     {FILE_PATH_LITERAL(".taz"), EXTENSION_TAZ, true, true},
@@ -348,12 +475,20 @@
     {FILE_PATH_LITERAL(".tcsh"), EXTENSION_TCSH, true, false},
     {FILE_PATH_LITERAL(".tgz"), EXTENSION_TGZ, true, true},
     {FILE_PATH_LITERAL(".torrent"), EXTENSION_TORRENT, true, false},
+    {FILE_PATH_LITERAL(".tpz"), EXTENSION_TPZ, true, true},
+    {FILE_PATH_LITERAL(".txz"), EXTENSION_TXZ, true, true},
+    {FILE_PATH_LITERAL(".tz"), EXTENSION_TZ, true, true},
     {FILE_PATH_LITERAL(".u3p"), EXTENSION_U3P, false, false},  // UMA only.
+    {FILE_PATH_LITERAL(".udf"), EXTENSION_UDF, true, true},
     {FILE_PATH_LITERAL(".url"), EXTENSION_URL, true, false},
+    {FILE_PATH_LITERAL(".uu"), EXTENSION_UU, true, true},
+    {FILE_PATH_LITERAL(".uue"), EXTENSION_UUE, true, true},
     {FILE_PATH_LITERAL(".vb"), EXTENSION_VB, true, false},
     {FILE_PATH_LITERAL(".vbe"), EXTENSION_VBE, true, false},
     {FILE_PATH_LITERAL(".vbs"), EXTENSION_VBS, true, false},
     {FILE_PATH_LITERAL(".vbscript"), EXTENSION_VBSCRIPT, false, false},  // UMA.
+    {FILE_PATH_LITERAL(".vhd"), EXTENSION_VHD, true, true},
+    {FILE_PATH_LITERAL(".vmdk"), EXTENSION_VMDK, true, true},
     {FILE_PATH_LITERAL(".vsd"), EXTENSION_VSD, true, false},
     {FILE_PATH_LITERAL(".vsmacros"), EXTENSION_VSMACROS, true, false},
     {FILE_PATH_LITERAL(".vss"), EXTENSION_VSS, true, false},
@@ -362,18 +497,23 @@
     {FILE_PATH_LITERAL(".website"), EXTENSION_WEBSITE, true, false},
     {FILE_PATH_LITERAL(".wim"), EXTENSION_WIM, true, true},
     {FILE_PATH_LITERAL(".workflow"), EXTENSION_WORKFLOW, false, false},  // UMA.
+    {FILE_PATH_LITERAL(".wrc"), EXTENSION_WRC, true, true},
     {FILE_PATH_LITERAL(".ws"), EXTENSION_WS, true, false},
     {FILE_PATH_LITERAL(".wsc"), EXTENSION_WSC, true, false},
     {FILE_PATH_LITERAL(".wsf"), EXTENSION_WSF, true, false},
     {FILE_PATH_LITERAL(".wsh"), EXTENSION_WSH, true, false},
+    {FILE_PATH_LITERAL(".xar"), EXTENSION_XAR, true, true},
     {FILE_PATH_LITERAL(".xbap"), EXTENSION_XBAP, true, false},
     {FILE_PATH_LITERAL(".xml"), EXTENSION_XML, true, false},
     {FILE_PATH_LITERAL(".xnk"), EXTENSION_XNK, true, false},
     {FILE_PATH_LITERAL(".xrm-ms"), EXTENSION_XRM_MS, true, false},
     {FILE_PATH_LITERAL(".xsl"), EXTENSION_XSL, true, false},
+    {FILE_PATH_LITERAL(".xxe"), EXTENSION_XXE, true, true},
     {FILE_PATH_LITERAL(".xz"), EXTENSION_XZ, true, true},
     {FILE_PATH_LITERAL(".z"), EXTENSION_Z, true, true},
     {FILE_PATH_LITERAL(".zip"), EXTENSION_ZIP, true, true},
+    {FILE_PATH_LITERAL(".zipx"), EXTENSION_ZIPX, true, true},
+    {FILE_PATH_LITERAL(".zpaq"), EXTENSION_ZPAQ, true, true},
 };
 
 const SafeBrowsingFiletype& GetFileType(const base::FilePath& file) {
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 8e7f455..4ade73b 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -733,6 +733,9 @@
 const char kChromeSearchMostVisitedHost[] = "most-visited";
 const char kChromeSearchMostVisitedUrl[] = "chrome-search://most-visited/";
 
+const char kEasyUnlockLearnMoreUrl[] =
+    "https://support.google.com/chromebook/?p=smart_lock";
+
 // Google SafeSearch query parameters.
 const char kSafeSearchSafeParameter[] = "safe=active";
 const char kSafeSearchSsuiParameter[] = "ssui=on";
@@ -756,7 +759,9 @@
 #endif
 #endif
 
-const char kEasyUnlockLearnMoreUrl[] =
-    "https://support.google.com/chromebook/?p=smart_lock";
+#if defined(OS_WIN)
+const char kWindowsXPVistaDeprecationURL[] =
+    "https://support.google.com/chrome/answer/95346";
+#endif
 
 }  // namespace chrome
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index b3444f99..d77529c9 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -530,6 +530,11 @@
 extern const char kChromeSearchMostVisitedHost[];
 extern const char kChromeSearchMostVisitedUrl[];
 
+#if defined(OS_WIN) || defined(OS_CHROMEOS)
+extern const char kChromeUIDiscardsHost[];
+extern const char kChromeUIDiscardsURL[];
+#endif
+
 #if defined(OS_CHROMEOS)
 extern const char kCrosScheme[];
 #endif
@@ -540,6 +545,9 @@
 // "Learn more" URL for the Cloud Print Preview No Destinations Promotion.
 extern const char kCloudPrintNoDestinationsLearnMoreURL[];
 
+// The URL for the "Learn more" link the the Easy Unlock settings.
+extern const char kEasyUnlockLearnMoreUrl[];
+
 // Parameters that get appended to force SafeSearch.
 extern const char kSafeSearchSafeParameter[];
 extern const char kSafeSearchSsuiParameter[];
@@ -551,16 +559,13 @@
 extern const char kLanguageSettingsLearnMoreUrl[];
 
 #if defined(OS_MACOSX)
-// The URL for the 32-bit Mac deprecation help center article
+// The URL for the 32-bit Mac deprecation help center article.
 extern const char kMac32BitDeprecationURL[];
 #endif
 
-// The URL for the "Learn more" link the the Easy Unlock settings.
-extern const char kEasyUnlockLearnMoreUrl[];
-
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
-extern const char kChromeUIDiscardsHost[];
-extern const char kChromeUIDiscardsURL[];
+#if defined(OS_WIN)
+// The URL for the Windows XP/Vista deprecation help center article.
+extern const char kWindowsXPVistaDeprecationURL[];
 #endif
 
 }  // namespace chrome
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index f42e11b..58703eb 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -166,7 +166,8 @@
 
 autofill::SaveCardBubbleView* TestBrowserWindow::ShowSaveCreditCardBubble(
     content::WebContents* contents,
-    autofill::SaveCardBubbleController* controller) {
+    autofill::SaveCardBubbleController* controller,
+    bool user_gesture) {
   return nullptr;
 }
 
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index b29bd4b..a9e0f247 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -111,7 +111,8 @@
       const ShowBookmarkAppBubbleCallback& callback) override {}
   autofill::SaveCardBubbleView* ShowSaveCreditCardBubble(
       content::WebContents* contents,
-      autofill::SaveCardBubbleController* controller) override;
+      autofill::SaveCardBubbleController* controller,
+      bool user_gesture) override;
   void ShowTranslateBubble(content::WebContents* contents,
                            translate::TranslateStep step,
                            translate::TranslateErrors::Type error_type,
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 9d0fe0f..f6d85d7 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7630.0.0
\ No newline at end of file
+7633.0.0
\ No newline at end of file
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index d7471e8c..7a5c5dd 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -595,6 +595,7 @@
 
 bool CrashDone(const MinidumpDescriptor& minidump,
                const bool upload,
+               const bool should_finalize,
                const bool succeeded) {
   // WARNING: this code runs in a compromised context. It may not call into
   // libc nor allocate memory normally.
@@ -629,17 +630,27 @@
   info.crash_keys = g_crash_keys;
   HandleCrashDump(info);
 #if defined(OS_ANDROID)
-  return FinalizeCrashDoneAndroid(true /* is_browser_process */);
+  return !should_finalize ||
+         FinalizeCrashDoneAndroid(true /* is_browser_process */);
 #else
   return true;
 #endif
 }
 
+#if defined(OS_ANDROID)
+// Wrapper function, do not add more code here.
+bool MinidumpGenerated(const MinidumpDescriptor& minidump,
+                       void* context,
+                       bool succeeded) {
+  return CrashDone(minidump, false, false, succeeded);
+}
+#endif
+
 // Wrapper function, do not add more code here.
 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
                        void* context,
                        bool succeeded) {
-  return CrashDone(minidump, false, succeeded);
+  return CrashDone(minidump, false, true, succeeded);
 }
 
 #if !defined(OS_ANDROID)
@@ -647,7 +658,7 @@
 bool CrashDoneUpload(const MinidumpDescriptor& minidump,
                      void* context,
                      bool succeeded) {
-  return CrashDone(minidump, true, succeeded);
+  return CrashDone(minidump, true, true, succeeded);
 }
 #endif
 
@@ -814,13 +825,11 @@
 }
 
 void GenerateMinidumpOnDemandForAndroid() {
-  // TODO(tobiasjs) this still calls FinalizeCrashDoneAndroid, which
-  // generates logspam. Consider refactoring.
   int dump_fd = GetCrashReporterClient()->GetAndroidMinidumpDescriptor();
   if (dump_fd >= 0) {
     MinidumpDescriptor minidump_descriptor(dump_fd);
     minidump_descriptor.set_size_limit(-1);
-    ExceptionHandler(minidump_descriptor, nullptr, CrashDoneNoUpload, nullptr,
+    ExceptionHandler(minidump_descriptor, nullptr, MinidumpGenerated, nullptr,
                      false, -1)
         .WriteMinidump();
   }
diff --git a/components/html_viewer/devtools_agent_impl.cc b/components/html_viewer/devtools_agent_impl.cc
index a547062..bc4c871 100644
--- a/components/html_viewer/devtools_agent_impl.cc
+++ b/components/html_viewer/devtools_agent_impl.cc
@@ -21,7 +21,7 @@
 
   if (state) {
     cache_until_client_ready_ = true;
-    frame_->devToolsAgent()->reattach(blink::WebString::fromUTF8(id_), 0,
+    frame_->devToolsAgent()->reattach(blink::WebString::fromUTF8(id_),
                                       blink::WebString::fromUTF8(*state));
   }
 }
@@ -52,17 +52,16 @@
                                        message.state);
     cached_client_messages_.clear();
   } else {
-    frame_->devToolsAgent()->attach(blink::WebString::fromUTF8(id_), 0);
+    frame_->devToolsAgent()->attach(blink::WebString::fromUTF8(id_));
   }
 }
 
 void DevToolsAgentImpl::DispatchProtocolMessage(const mojo::String& message) {
   frame_->devToolsAgent()->dispatchOnInspectorBackend(
-      0, blink::WebString::fromUTF8(message));
+      blink::WebString::fromUTF8(message));
 }
 
-void DevToolsAgentImpl::sendProtocolMessage(int session_id,
-                                            int call_id,
+void DevToolsAgentImpl::sendProtocolMessage(int call_id,
                                             const blink::WebString& response,
                                             const blink::WebString& state) {
   DCHECK(!response.isNull());
diff --git a/components/html_viewer/devtools_agent_impl.h b/components/html_viewer/devtools_agent_impl.h
index 17ff601d..f062b31d 100644
--- a/components/html_viewer/devtools_agent_impl.h
+++ b/components/html_viewer/devtools_agent_impl.h
@@ -38,8 +38,7 @@
   void DispatchProtocolMessage(const mojo::String& message) override;
 
   // blink::WebDevToolsAgentClient implementation.
-  void sendProtocolMessage(int session_id,
-                           int call_id,
+  void sendProtocolMessage(int call_id,
                            const blink::WebString& response,
                            const blink::WebString& state);
 
diff --git a/components/mus/example/window_type_launcher/main.cc b/components/mus/example/window_type_launcher/main.cc
index f0bd9c093..9cecc39c 100644
--- a/components/mus/example/window_type_launcher/main.cc
+++ b/components/mus/example/window_type_launcher/main.cc
@@ -57,7 +57,6 @@
     CHECK(io_thread.StartWithOptions(io_thread_options));
 
     mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE,
-                                   io_thread.task_runner().get(),
                                    &process_delegate,
                                    io_thread.task_runner().get(),
                                    mojo::embedder::ScopedPlatformHandle());
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index 26ef227..acbe3ce 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -49,6 +49,7 @@
     "//cc",
     "//cc/surfaces",
     "//cc/surfaces:surface_id",
+    "//components/mus/common",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/converters/geometry",
diff --git a/components/mus/public/cpp/lib/in_flight_change.h b/components/mus/public/cpp/lib/in_flight_change.h
index a627760..b963282 100644
--- a/components/mus/public/cpp/lib/in_flight_change.h
+++ b/components/mus/public/cpp/lib/in_flight_change.h
@@ -14,8 +14,10 @@
 class WindowTreeConnection;
 
 enum class ChangeType {
+  ADD_TRANSIENT_WINDOW,
   BOUNDS,
   NEW_WINDOW,
+  REMOVE_TRANSIENT_WINDOW_FROM_PARENT
 };
 
 // InFlightChange is used to track function calls to the server and take the
diff --git a/components/mus/public/cpp/lib/window.cc b/components/mus/public/cpp/lib/window.cc
index ded9b52..6fc0570 100644
--- a/components/mus/public/cpp/lib/window.cc
+++ b/components/mus/public/cpp/lib/window.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/bind.h"
+#include "components/mus/common/transient_window_utils.h"
 #include "components/mus/public/cpp/lib/window_private.h"
 #include "components/mus/public/cpp/lib/window_tree_client_impl.h"
 #include "components/mus/public/cpp/window_observer.h"
@@ -86,19 +87,24 @@
   }
 }
 
-class ScopedOrderChangedNotifier {
+class OrderChangedNotifier {
  public:
-  ScopedOrderChangedNotifier(Window* window,
-                             Window* relative_window,
-                             mojom::OrderDirection direction)
+  OrderChangedNotifier(Window* window,
+                       Window* relative_window,
+                       mojom::OrderDirection direction)
       : window_(window),
         relative_window_(relative_window),
-        direction_(direction) {
+        direction_(direction) {}
+
+  ~OrderChangedNotifier() {}
+
+  void NotifyWindowReordering() {
     FOR_EACH_OBSERVER(
         WindowObserver, *WindowPrivate(window_).observers(),
         OnWindowReordering(window_, relative_window_, direction_));
   }
-  ~ScopedOrderChangedNotifier() {
+
+  void NotifyWindowReordered() {
     FOR_EACH_OBSERVER(WindowObserver, *WindowPrivate(window_).observers(),
                       OnWindowReordered(window_, relative_window_, direction_));
   }
@@ -108,39 +114,9 @@
   Window* relative_window_;
   mojom::OrderDirection direction_;
 
-  MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedOrderChangedNotifier);
+  MOJO_DISALLOW_COPY_AND_ASSIGN(OrderChangedNotifier);
 };
 
-// Returns true if the order actually changed.
-bool ReorderImpl(Window::Children* children,
-                 Window* window,
-                 Window* relative,
-                 mojom::OrderDirection direction) {
-  DCHECK(relative);
-  DCHECK_NE(window, relative);
-  DCHECK_EQ(window->parent(), relative->parent());
-
-  const size_t child_i =
-      std::find(children->begin(), children->end(), window) - children->begin();
-  const size_t target_i =
-      std::find(children->begin(), children->end(), relative) -
-      children->begin();
-  if ((direction == mojom::ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
-      (direction == mojom::ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
-    return false;
-  }
-
-  ScopedOrderChangedNotifier notifier(window, relative, direction);
-
-  const size_t dest_i = direction == mojom::ORDER_DIRECTION_ABOVE
-                            ? (child_i < target_i ? target_i : target_i + 1)
-                            : (child_i < target_i ? target_i - 1 : target_i);
-  children->erase(children->begin() + child_i);
-  children->insert(children->begin() + dest_i, window);
-
-  return true;
-}
-
 class ScopedSetBoundsNotifier {
  public:
   ScopedSetBoundsNotifier(Window* window,
@@ -299,6 +275,25 @@
   }
 }
 
+void Window::AddTransientWindow(Window* transient_window) {
+  if (connection_)
+    CHECK_EQ(transient_window->connection(), connection_);
+  LocalAddTransientWindow(transient_window);
+  if (connection_)
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->AddTransientWindow(id_, transient_window->id());
+}
+
+void Window::RemoveTransientWindow(Window* transient_window) {
+  if (connection_)
+    CHECK_EQ(transient_window->connection(), connection_);
+  LocalRemoveTransientWindow(transient_window);
+  if (connection_) {
+    static_cast<WindowTreeClientImpl*>(connection_)
+        ->RemoveTransientWindow(transient_window->id(), id_);
+  }
+}
+
 void Window::MoveToFront() {
   if (!parent_ || parent_->children_.back() == this)
     return;
@@ -345,7 +340,7 @@
     if (window)
       return window;
   }
-  return NULL;
+  return nullptr;
 }
 
 void Window::SetTextInputState(mojo::TextInputStatePtr state) {
@@ -423,15 +418,31 @@
 }  // namespace
 
 Window::Window()
-    : connection_(NULL),
+    : connection_(nullptr),
       id_(static_cast<Id>(-1)),
-      parent_(NULL),
+      parent_(nullptr),
+      stacking_target_(nullptr),
+      transient_parent_(nullptr),
       viewport_metrics_(CreateEmptyViewportMetrics()),
       visible_(true),
       drawn_(false) {}
 
 Window::~Window() {
   FOR_EACH_OBSERVER(WindowObserver, observers_, OnWindowDestroying(this));
+
+  // Remove from transient parent.
+  if (transient_parent_)
+    transient_parent_->LocalRemoveTransientWindow(this);
+
+  // Remove transient children.
+  while (!transient_children_.empty()) {
+    Window* transient_child = transient_children_.front();
+    LocalRemoveTransientWindow(transient_child);
+    transient_child->LocalDestroy();
+    DCHECK(transient_children_.empty() ||
+           transient_children_.front() != transient_child);
+  }
+
   if (parent_)
     parent_->LocalRemoveChild(this);
 
@@ -468,6 +479,8 @@
     : connection_(connection),
       id_(id),
       parent_(nullptr),
+      stacking_target_(nullptr),
+      transient_parent_(nullptr),
       viewport_metrics_(CreateEmptyViewportMetrics()),
       visible_(false),
       drawn_(false) {}
@@ -530,12 +543,34 @@
 
 void Window::LocalRemoveChild(Window* child) {
   DCHECK_EQ(this, child->parent());
-  ScopedTreeNotifier notifier(child, this, NULL);
+  ScopedTreeNotifier notifier(child, this, nullptr);
   RemoveChildImpl(child, &children_);
 }
 
+void Window::LocalAddTransientWindow(Window* transient_window) {
+  if (transient_window->transient_parent())
+    RemoveTransientWindowImpl(transient_window);
+  transient_children_.push_back(transient_window);
+  transient_window->transient_parent_ = this;
+
+  // Restack |transient_window| properly above its transient parent, if they
+  // share the same parent.
+  if (transient_window->parent() == parent())
+    RestackTransientDescendants(this, &GetStackingTarget,
+                                &ReorderWithoutNotification);
+
+  // TODO(fsamuel): We might want a notification here.
+}
+
+void Window::LocalRemoveTransientWindow(Window* transient_window) {
+  DCHECK_EQ(this, transient_window->transient_parent());
+  RemoveTransientWindowImpl(transient_window);
+  // TODO(fsamuel): We might want a notification here.
+}
+
 bool Window::LocalReorder(Window* relative, mojom::OrderDirection direction) {
-  return ReorderImpl(&parent_->children_, this, relative, direction);
+  OrderChangedNotifier notifier(this, relative, direction);
+  return ReorderImpl(this, relative, direction, &notifier);
 }
 
 void Window::LocalSetBounds(const gfx::Rect& old_bounds,
@@ -601,8 +636,8 @@
     if (value && old_value == *value)
       return;
   } else if (!value) {
-    // This property isn't set in |properties_| and |value| is NULL, so there's
-    // no change.
+    // This property isn't set in |properties_| and |value| is nullptr, so
+    // there's no change.
     return;
   }
 
@@ -617,6 +652,19 @@
       OnWindowSharedPropertyChanged(this, name, old_value_ptr, value));
 }
 
+void Window::NotifyWindowStackingChanged() {
+  if (stacking_target_) {
+    Children::const_iterator window_i = std::find(
+        parent()->children().begin(), parent()->children().end(), this);
+    DCHECK(window_i != parent()->children().end());
+    if (window_i != parent()->children().begin() &&
+        (*(window_i - 1) == stacking_target_))
+      return;
+  }
+  RestackTransientDescendants(this, &GetStackingTarget,
+                              &ReorderWithoutNotification);
+}
+
 void Window::NotifyWindowVisibilityChanged(Window* target) {
   if (!NotifyWindowVisibilityChangedDown(target)) {
     return;  // |this| has been deleted.
@@ -677,4 +725,77 @@
   return true;
 }
 
+void Window::RemoveTransientWindowImpl(Window* transient_window) {
+  Window::Children::iterator it = std::find(
+      transient_children_.begin(), transient_children_.end(), transient_window);
+  if (it != transient_children_.end()) {
+    transient_children_.erase(it);
+    transient_window->transient_parent_ = nullptr;
+  }
+  // If |transient_window| and its former transient parent share the same
+  // parent, |transient_window| should be restacked properly so it is not among
+  // transient children of its former parent, anymore.
+  if (parent() == transient_window->parent())
+    RestackTransientDescendants(this, &GetStackingTarget,
+                                &ReorderWithoutNotification);
+
+  // TOOD(fsamuel): We might want to notify observers here.
+}
+
+// static
+void Window::ReorderWithoutNotification(Window* window,
+                                        Window* relative,
+                                        mojom::OrderDirection direction) {
+  ReorderImpl(window, relative, direction, nullptr);
+}
+
+// static
+// Returns true if the order actually changed.
+bool Window::ReorderImpl(Window* window,
+                         Window* relative,
+                         mojom::OrderDirection direction,
+                         OrderChangedNotifier* notifier) {
+  DCHECK(relative);
+  DCHECK_NE(window, relative);
+  DCHECK_EQ(window->parent(), relative->parent());
+
+  if (!AdjustStackingForTransientWindows(&window, &relative, &direction,
+                                         window->stacking_target_))
+    return false;
+
+  const size_t child_i = std::find(window->parent_->children_.begin(),
+                                   window->parent_->children_.end(), window) -
+                         window->parent_->children_.begin();
+  const size_t target_i =
+      std::find(window->parent_->children_.begin(),
+                window->parent_->children_.end(), relative) -
+      window->parent_->children_.begin();
+  if ((direction == mojom::ORDER_DIRECTION_ABOVE && child_i == target_i + 1) ||
+      (direction == mojom::ORDER_DIRECTION_BELOW && child_i + 1 == target_i)) {
+    return false;
+  }
+
+  if (notifier)
+    notifier->NotifyWindowReordering();
+
+  const size_t dest_i = direction == mojom::ORDER_DIRECTION_ABOVE
+                            ? (child_i < target_i ? target_i : target_i + 1)
+                            : (child_i < target_i ? target_i - 1 : target_i);
+  window->parent_->children_.erase(window->parent_->children_.begin() +
+                                   child_i);
+  window->parent_->children_.insert(window->parent_->children_.begin() + dest_i,
+                                    window);
+
+  window->NotifyWindowStackingChanged();
+
+  if (notifier)
+    notifier->NotifyWindowReordered();
+
+  return true;
+}
+
+// static
+Window** Window::GetStackingTarget(Window* window) {
+  return &window->stacking_target_;
+}
 }  // namespace mus
diff --git a/components/mus/public/cpp/lib/window_private.h b/components/mus/public/cpp/lib/window_private.h
index d566a60..fe1622f 100644
--- a/components/mus/public/cpp/lib/window_private.h
+++ b/components/mus/public/cpp/lib/window_private.h
@@ -23,7 +23,9 @@
     return &window_->observers_;
   }
 
-  void ClearParent() { window_->parent_ = NULL; }
+  void ClearParent() { window_->parent_ = nullptr; }
+
+  void ClearTransientParent() { window_->transient_parent_ = nullptr; }
 
   void set_visible(bool visible) { window_->visible_ = visible; }
 
@@ -47,6 +49,12 @@
   void LocalDestroy() { window_->LocalDestroy(); }
   void LocalAddChild(Window* child) { window_->LocalAddChild(child); }
   void LocalRemoveChild(Window* child) { window_->LocalRemoveChild(child); }
+  void LocalAddTransientWindow(Window* child) {
+    window_->LocalAddTransientWindow(child);
+  }
+  void LocalRemoveTransientWindow(Window* child) {
+    window_->LocalRemoveTransientWindow(child);
+  }
   void LocalReorder(Window* relative, mojom::OrderDirection direction) {
     window_->LocalReorder(relative, direction);
   }
@@ -63,6 +71,7 @@
                               const std::vector<uint8_t>* data){
     window_->LocalSetSharedProperty(name, data);
   }
+  void NotifyWindowStackingChanged() { window_->NotifyWindowStackingChanged(); }
 
  private:
   Window* window_;
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index 3c5e329..9fd65b5 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -170,6 +170,24 @@
   tree_->RemoveWindowFromParent(child_id, ActionCompletedCallback());
 }
 
+void WindowTreeClientImpl::AddTransientWindow(Id window_id,
+                                              Id transient_window_id) {
+  DCHECK(tree_);
+  const uint32_t change_id = ScheduleInFlightChange(make_scoped_ptr(
+      new CrashInFlightChange(window_id, ChangeType::ADD_TRANSIENT_WINDOW)));
+  tree_->AddTransientWindow(change_id, window_id, transient_window_id);
+}
+
+void WindowTreeClientImpl::RemoveTransientWindow(Id transient_window_id,
+                                                 Id transient_parent_id) {
+  DCHECK(tree_);
+  const uint32_t change_id =
+      ScheduleInFlightChange(make_scoped_ptr(new CrashInFlightChange(
+          transient_window_id,
+          ChangeType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)));
+  tree_->RemoveTransientWindowFromParent(change_id, transient_window_id);
+}
+
 void WindowTreeClientImpl::Reorder(Id window_id,
                                    Id relative_window_id,
                                    mojom::OrderDirection direction) {
@@ -432,6 +450,28 @@
     WindowPrivate(window).LocalSetClientArea(new_client_area.To<gfx::Insets>());
 }
 
+void WindowTreeClientImpl::OnTransientWindowAdded(
+    uint32_t window_id,
+    uint32_t transient_window_id) {
+  Window* window = GetWindowById(window_id);
+  Window* transient_window = GetWindowById(transient_window_id);
+  // window or transient_window or both may be null if a local delete occurs
+  // with an in flight add from the server.
+  if (window && transient_window)
+    WindowPrivate(window).LocalAddTransientWindow(transient_window);
+}
+
+void WindowTreeClientImpl::OnTransientWindowRemoved(
+    uint32_t window_id,
+    uint32_t transient_window_id) {
+  Window* window = GetWindowById(window_id);
+  Window* transient_window = GetWindowById(transient_window_id);
+  // window or transient_window or both may be null if a local delete occurs
+  // with an in flight delete from the server.
+  if (window && transient_window)
+    WindowPrivate(window).LocalRemoveTransientWindow(transient_window);
+}
+
 namespace {
 
 void SetViewportMetricsOnDecendants(Window* root,
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
index 04fe215..512f8a1 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -50,6 +50,9 @@
   void AddChild(Id child_id, Id parent_id);
   void RemoveChild(Id child_id, Id parent_id);
 
+  void AddTransientWindow(Id window_id, Id transient_window_id);
+  void RemoveTransientWindow(Id transient_window_id, Id transient_parent_id);
+
   void Reorder(Id window_id,
                Id relative_window_id,
                mojom::OrderDirection direction);
@@ -146,6 +149,10 @@
   void OnClientAreaChanged(uint32_t window_id,
                            mojo::InsetsPtr old_client_area,
                            mojo::InsetsPtr new_client_area) override;
+  void OnTransientWindowAdded(uint32_t window_id,
+                              uint32_t transient_window_id) override;
+  void OnTransientWindowRemoved(uint32_t window_id,
+                                uint32_t transient_window_id) override;
   void OnWindowViewportMetricsChanged(
       mojom::ViewportMetricsPtr old_metrics,
       mojom::ViewportMetricsPtr new_metrics) override;
diff --git a/components/mus/public/cpp/tests/test_window.h b/components/mus/public/cpp/tests/test_window.h
index a7b458d..47557ce 100644
--- a/components/mus/public/cpp/tests/test_window.h
+++ b/components/mus/public/cpp/tests/test_window.h
@@ -15,6 +15,7 @@
 class TestWindow : public Window {
  public:
   TestWindow() { WindowPrivate(this).set_id(1); }
+  explicit TestWindow(Id window_id) { WindowPrivate(this).set_id(window_id); }
   ~TestWindow() {}
 
  private:
diff --git a/components/mus/public/cpp/tests/test_window_tree.cc b/components/mus/public/cpp/tests/test_window_tree.cc
index 15efbf76..f2a9a51 100644
--- a/components/mus/public/cpp/tests/test_window_tree.cc
+++ b/components/mus/public/cpp/tests/test_window_tree.cc
@@ -60,6 +60,14 @@
     uint32_t window_id,
     const RemoveWindowFromParentCallback& callback) {}
 
+void TestWindowTree::AddTransientWindow(uint32_t change_id,
+                                        uint32_t window_id,
+                                        uint32_t transient_window_id) {}
+
+void TestWindowTree::RemoveTransientWindowFromParent(
+    uint32_t change_id,
+    uint32_t transient_window_id) {}
+
 void TestWindowTree::ReorderWindow(uint32_t window_id,
                                    uint32_t relative_window_id,
                                    mojom::OrderDirection direction,
diff --git a/components/mus/public/cpp/tests/test_window_tree.h b/components/mus/public/cpp/tests/test_window_tree.h
index 57e60cd1..fc242f4 100644
--- a/components/mus/public/cpp/tests/test_window_tree.h
+++ b/components/mus/public/cpp/tests/test_window_tree.h
@@ -48,6 +48,11 @@
   void RemoveWindowFromParent(
       uint32_t window_id,
       const RemoveWindowFromParentCallback& callback) override;
+  void AddTransientWindow(uint32_t change_id,
+                          uint32_t window_id,
+                          uint32_t transient_window_id) override;
+  void RemoveTransientWindowFromParent(uint32_t change_id,
+                                       uint32_t window_id) override;
   void ReorderWindow(uint32_t window_id,
                      uint32_t relative_window_id,
                      mojom::OrderDirection direction,
diff --git a/components/mus/public/cpp/tests/window_unittest.cc b/components/mus/public/cpp/tests/window_unittest.cc
index 04f907a..f0386c9 100644
--- a/components/mus/public/cpp/tests/window_unittest.cc
+++ b/components/mus/public/cpp/tests/window_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/mus/public/cpp/window.h"
 
 #include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "components/mus/public/cpp/lib/window_private.h"
 #include "components/mus/public/cpp/property_type_converters.h"
@@ -17,6 +18,33 @@
 
 namespace mus {
 
+namespace {
+
+TestWindow* CreateTestWindow(TestWindow* parent) {
+  TestWindow* window = new TestWindow;
+  if (parent)
+    parent->AddChild(window);
+  return window;
+}
+
+TestWindow* CreateTestWindow(Id id, TestWindow* parent) {
+  TestWindow* window = new TestWindow(id);
+  if (parent)
+    parent->AddChild(window);
+  return window;
+}
+
+std::string ChildWindowIDsAsString(TestWindow* parent) {
+  std::string result;
+  for (Window* child : parent->children()) {
+    if (!result.empty())
+      result += " ";
+    result += base::IntToString(child->id());
+  }
+  return result;
+}
+
+}  // namespace
 // Window ---------------------------------------------------------------------
 
 using WindowTest = testing::Test;
@@ -870,4 +898,225 @@
             o.PropertyChangeInfoAndClear());
 }
 
+TEST_F(WindowTest, RemoveTransientWindow) {
+  scoped_ptr<TestWindow> w1(CreateTestWindow(nullptr));
+  scoped_ptr<TestWindow> w11(CreateTestWindow(w1.get()));
+  TestWindow* w12 = CreateTestWindow(w1.get());
+  EXPECT_EQ(2u, w1->children().size());
+  // w12's lifetime is now tied to w11.
+  w11->AddTransientWindow(w12);
+  w11.reset();
+  EXPECT_EQ(0u, w1->children().size());
+}
+
+TEST_F(WindowTest, TransientWindow) {
+  scoped_ptr<TestWindow> parent(CreateTestWindow(nullptr));
+  scoped_ptr<TestWindow> w1(CreateTestWindow(parent.get()));
+  scoped_ptr<TestWindow> w3(CreateTestWindow(parent.get()));
+
+  Window* w2 = CreateTestWindow(parent.get());
+  EXPECT_EQ(w2, parent->children().back());
+  ASSERT_EQ(3u, parent->children().size());
+
+  w1->AddTransientWindow(w2);
+  // Stack w1 at the top (end). This should force w2 to be last (on top of w1).
+  w1->MoveToFront();
+  ASSERT_EQ(3u, parent->children().size());
+  EXPECT_EQ(w2, parent->children().back());
+
+  // Destroy w1, which should also destroy w3 (since it's a transient child).A
+  w1.reset();
+  w2 = nullptr;
+  ASSERT_EQ(1u, parent->children().size());
+  EXPECT_EQ(w3.get(), parent->children()[0]);
+}
+
+// Tests that transient windows are stacked as a unit when using order above.
+TEST_F(WindowTest, TransientWindowsGroupAbove) {
+  scoped_ptr<TestWindow> parent(CreateTestWindow(0, nullptr));
+  scoped_ptr<TestWindow> w1(CreateTestWindow(1, parent.get()));
+
+  TestWindow* w11 = CreateTestWindow(11, parent.get());
+  scoped_ptr<TestWindow> w2(CreateTestWindow(2, parent.get()));
+
+  TestWindow* w21 = CreateTestWindow(21, parent.get());
+  TestWindow* w211 = CreateTestWindow(211, parent.get());
+  TestWindow* w212 = CreateTestWindow(212, parent.get());
+  TestWindow* w213 = CreateTestWindow(213, parent.get());
+  TestWindow* w22 = CreateTestWindow(22, parent.get());
+  ASSERT_EQ(8u, parent->children().size());
+
+  // w11 is now owned by w1.
+  w1->AddTransientWindow(w11);
+  // w21 is now owned by w2.
+  w2->AddTransientWindow(w21);
+  // w22 is now owned by w2.
+  w2->AddTransientWindow(w22);
+  // w211 is now owned by w21.
+  w21->AddTransientWindow(w211);
+  // w212 is now owned by w21.
+  w21->AddTransientWindow(w212);
+  // w213 is now owned by w21.
+  w21->AddTransientWindow(w213);
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  // Stack w1 at the top (end), this should force w11 to be last (on top of w1).
+  w1->MoveToFront();
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+  // This tests that the order in children_ array rather than in
+  // transient_children_ array is used when reinserting transient children.
+  // If transient_children_ array was used '22' would be following '21'.
+  w2->MoveToFront();
+  EXPECT_EQ(w22, parent->children().back());
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  w11->Reorder(w2.get(), mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w21->Reorder(w1.get(), mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w22, parent->children().back());
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  w21->Reorder(w22, mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w213, parent->children().back());
+  EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+  w11->Reorder(w21, mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w213->Reorder(w21, mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+  // No change when stacking a transient parent above its transient child.
+  w21->Reorder(w211, mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+  // This tests that the order in children_ array rather than in
+  // transient_children_ array is used when reinserting transient children.
+  // If transient_children_ array was used '22' would be following '21'.
+  w2->Reorder(w1.get(), mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w212, parent->children().back());
+  EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+  w11->Reorder(w213, mojom::ORDER_DIRECTION_ABOVE);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient children are stacked as a unit when using order below.
+TEST_F(WindowTest, TransientWindowsGroupBelow) {
+  scoped_ptr<TestWindow> parent(CreateTestWindow(0, nullptr));
+  scoped_ptr<TestWindow> w1(CreateTestWindow(1, parent.get()));
+
+  TestWindow* w11 = CreateTestWindow(11, parent.get());
+  scoped_ptr<TestWindow> w2(CreateTestWindow(2, parent.get()));
+
+  TestWindow* w21 = CreateTestWindow(21, parent.get());
+  TestWindow* w211 = CreateTestWindow(211, parent.get());
+  TestWindow* w212 = CreateTestWindow(212, parent.get());
+  TestWindow* w213 = CreateTestWindow(213, parent.get());
+  TestWindow* w22 = CreateTestWindow(22, parent.get());
+  ASSERT_EQ(8u, parent->children().size());
+
+  // w11 is now owned by w1.
+  w1->AddTransientWindow(w11);
+  // w21 is now owned by w2.
+  w2->AddTransientWindow(w21);
+  // w22 is now owned by w2.
+  w2->AddTransientWindow(w22);
+  // w211 is now owned by w21.
+  w21->AddTransientWindow(w211);
+  // w212 is now owned by w21.
+  w21->AddTransientWindow(w212);
+  // w213 is now owned by w21.
+  w21->AddTransientWindow(w213);
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  // Stack w2 at the bottom, this should force w11 to be last (on top of w1).
+  // This also tests that the order in children_ array rather than in
+  // transient_children_ array is used when reinserting transient children.
+  // If transient_children_ array was used '22' would be following '21'.
+  w2->MoveToBack();
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w1->MoveToBack();
+  EXPECT_EQ(w22, parent->children().back());
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  w21->Reorder(w1.get(), mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 21 211 212 213 22 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w11->Reorder(w2.get(), mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w22, parent->children().back());
+  EXPECT_EQ("1 11 2 21 211 212 213 22", ChildWindowIDsAsString(parent.get()));
+
+  w22->Reorder(w21, mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w213, parent->children().back());
+  EXPECT_EQ("1 11 2 22 21 211 212 213", ChildWindowIDsAsString(parent.get()));
+
+  w21->Reorder(w11, mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 211 212 213 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w213->Reorder(w211, mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+  // No change when stacking a transient parent below its transient child.
+  w21->Reorder(w211, mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+
+  w1->Reorder(w2.get(), mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w212, parent->children().back());
+  EXPECT_EQ("1 11 2 22 21 213 211 212", ChildWindowIDsAsString(parent.get()));
+
+  w213->Reorder(w11, mojom::ORDER_DIRECTION_BELOW);
+  EXPECT_EQ(w11, parent->children().back());
+  EXPECT_EQ("2 22 21 213 211 212 1 11", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that windows are restacked properly after a call to
+// AddTransientWindow() or RemoveTransientWindow).
+TEST_F(WindowTest, RestackUponAddOrRemoveTransientWindow) {
+  scoped_ptr<TestWindow> parent(CreateTestWindow(0, nullptr));
+  scoped_ptr<TestWindow> windows[4];
+  for (int i = 0; i < 4; i++)
+    windows[i].reset(CreateTestWindow(i, parent.get()));
+
+  EXPECT_EQ("0 1 2 3", ChildWindowIDsAsString(parent.get()));
+
+  windows[0]->AddTransientWindow(windows[2].get());
+  EXPECT_EQ("0 2 1 3", ChildWindowIDsAsString(parent.get()));
+
+  windows[0]->AddTransientWindow(windows[3].get());
+  EXPECT_EQ("0 2 3 1", ChildWindowIDsAsString(parent.get()));
+
+  windows[0]->RemoveTransientWindow(windows[2].get());
+  EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get()));
+
+  windows[0]->RemoveTransientWindow(windows[3].get());
+  EXPECT_EQ("0 3 2 1", ChildWindowIDsAsString(parent.get()));
+}
+
+// Tests that transient windows are stacked properly when created.
+TEST_F(WindowTest, StackUponCreation) {
+  scoped_ptr<TestWindow> parent(CreateTestWindow(0, nullptr));
+  scoped_ptr<TestWindow> window0(CreateTestWindow(1, parent.get()));
+  scoped_ptr<TestWindow> window1(CreateTestWindow(2, parent.get()));
+
+  TestWindow* window2 = CreateTestWindow(3, parent.get());
+
+  window0->AddTransientWindow(window2);
+  EXPECT_EQ("1 3 2", ChildWindowIDsAsString(parent.get()));
+}
+
 }  // namespace mus
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h
index b7eb8b2..a58e07ad 100644
--- a/components/mus/public/cpp/window.h
+++ b/components/mus/public/cpp/window.h
@@ -31,6 +31,10 @@
 class WindowSurface;
 class WindowTreeConnection;
 
+namespace {
+class OrderChangedNotifier;
+}
+
 // Defined in window_property.h (which we do not include)
 template <typename T>
 struct WindowProperty;
@@ -133,6 +137,14 @@
   Window* parent() { return parent_; }
   const Window* parent() const { return parent_; }
   const Children& children() const { return children_; }
+
+  // TODO(fsamuel): Figure out if we want to refactor transient window
+  // management into a separate class.
+  // Transient tree.
+  Window* transient_parent() { return transient_parent_; }
+  const Window* transient_parent() const { return transient_parent_; }
+  const Children& transient_children() const { return transient_children_; }
+
   Window* GetRoot() {
     return const_cast<Window*>(const_cast<const Window*>(this)->GetRoot());
   }
@@ -141,6 +153,9 @@
   void AddChild(Window* child);
   void RemoveChild(Window* child);
 
+  void AddTransientWindow(Window* transient_window);
+  void RemoveTransientWindow(Window* transient_window);
+
   void Reorder(Window* relative, mojom::OrderDirection direction);
   void MoveToFront();
   void MoveToBack();
@@ -198,6 +213,8 @@
   void LocalDestroy();
   void LocalAddChild(Window* child);
   void LocalRemoveChild(Window* child);
+  void LocalAddTransientWindow(Window* transient_window);
+  void LocalRemoveTransientWindow(Window* transient_window);
   // Returns true if the order actually changed.
   bool LocalReorder(Window* relative, mojom::OrderDirection direction);
   void LocalSetBounds(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds);
@@ -209,6 +226,8 @@
   void LocalSetSharedProperty(const std::string& name,
                               const std::vector<uint8_t>* data);
 
+  // Notifies this winodw that its stacking position has changed.
+  void NotifyWindowStackingChanged();
   // Methods implementing visibility change notifications. See WindowObserver
   // for more details.
   void NotifyWindowVisibilityChanged(Window* target);
@@ -225,11 +244,28 @@
   // the children are removed.
   bool PrepareForEmbed();
 
+  void RemoveTransientWindowImpl(Window* child);
+  static void ReorderWithoutNotification(Window* window,
+                                         Window* relative,
+                                         mojom::OrderDirection direction);
+  static bool ReorderImpl(Window* window,
+                          Window* relative,
+                          mojom::OrderDirection direction,
+                          OrderChangedNotifier* notifier);
+
+  // Returns a pointer to the stacking target that can be used by
+  // RestackTransientDescendants.
+  static Window** GetStackingTarget(Window* window);
+
   WindowTreeConnection* connection_;
   Id id_;
   Window* parent_;
   Children children_;
 
+  Window* stacking_target_;
+  Window* transient_parent_;
+  Children transient_children_;
+
   base::ObserverList<WindowObserver> observers_;
 
   gfx::Rect bounds_;
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 37b29e6..f8a840d6 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -139,6 +139,19 @@
   // visible to connection B.
   RemoveWindowFromParent(uint32 window_id) => (bool success);
 
+  // Ties the lifetime of |child| to the lifetime of |parent|. This also
+  // places |child| always on top of |parent|.
+  // This fails for any of the following reasons:
+  // . |window_id| or |transient_window_id| does not identify a valid window.
+  // . |transient_window_id| is an ancestor of |window_id|.
+  AddTransientWindow(uint32 change_id,
+                     uint32 window_id,
+                     uint32 transient_window_id);
+
+  // Decouples the lifetime of |transient_window_id| from its transient parent.
+  // This does not change transient window's position in the window hierarchy.
+  RemoveTransientWindowFromParent(uint32 change_id, uint32 transient_window_id);
+
   // Reorders a window in its parent, relative to |relative_window_id| according
   // to |direction|. Only the connection that created the window's parent can
   // reorder its children.
@@ -249,6 +262,12 @@
                       mojo.Insets old_client_area,
                       mojo.Insets new_client_area);
 
+  OnTransientWindowAdded(uint32 window_id,
+                         uint32 transient_window_id);
+
+  OnTransientWindowRemoved(uint32 window_id,
+                           uint32 transient_window_id);
+
   // Invoked when the viewport metrics for the window have changed.
   // Clients are expected to propagate this to the window tree.
   OnWindowViewportMetricsChanged(ViewportMetrics old_metrics,
diff --git a/components/mus/surfaces/surfaces_scheduler.cc b/components/mus/surfaces/surfaces_scheduler.cc
index c02a8d7..1f25df2 100644
--- a/components/mus/surfaces/surfaces_scheduler.cc
+++ b/components/mus/surfaces/surfaces_scheduler.cc
@@ -59,7 +59,8 @@
 
 void SurfacesScheduler::DidFinishImplFrame() {}
 
-void SurfacesScheduler::ScheduledActionSendBeginMainFrame() {
+void SurfacesScheduler::ScheduledActionSendBeginMainFrame(
+    const cc::BeginFrameArgs& args) {
   scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
 }
diff --git a/components/mus/surfaces/surfaces_scheduler.h b/components/mus/surfaces/surfaces_scheduler.h
index bffd9ddb..24ceac5 100644
--- a/components/mus/surfaces/surfaces_scheduler.h
+++ b/components/mus/surfaces/surfaces_scheduler.h
@@ -33,7 +33,8 @@
  private:
   void WillBeginImplFrame(const cc::BeginFrameArgs& args) override;
   void DidFinishImplFrame() override;
-  void ScheduledActionSendBeginMainFrame() override;
+  void ScheduledActionSendBeginMainFrame(
+      const cc::BeginFrameArgs& args) override;
   cc::DrawResult ScheduledActionDrawAndSwapIfPossible() override;
   cc::DrawResult ScheduledActionDrawAndSwapForced() override;
   void ScheduledActionAnimate() override;
diff --git a/components/mus/ws/access_policy.h b/components/mus/ws/access_policy.h
index e1065e7..9b382fe 100644
--- a/components/mus/ws/access_policy.h
+++ b/components/mus/ws/access_policy.h
@@ -27,6 +27,10 @@
   virtual bool CanRemoveWindowFromParent(const ServerWindow* window) const = 0;
   virtual bool CanAddWindow(const ServerWindow* parent,
                             const ServerWindow* child) const = 0;
+  virtual bool CanAddTransientWindow(const ServerWindow* parent,
+                                     const ServerWindow* child) const = 0;
+  virtual bool CanRemoveTransientWindowFromParent(
+      const ServerWindow* window) const = 0;
   virtual bool CanReorderWindow(const ServerWindow* window,
                                 const ServerWindow* relative_window,
                                 mojom::OrderDirection direction) const = 0;
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc
index ce627549..5f320d90 100644
--- a/components/mus/ws/connection_manager.cc
+++ b/components/mus/ws/connection_manager.cc
@@ -310,6 +310,12 @@
     const ServerWindow* window,
     const ServerWindow* relative_window,
     const mojom::OrderDirection direction) {
+  // We'll probably do a bit of reshuffling when we add a transient window.
+  if ((current_operation_type() == OperationType::ADD_TRANSIENT_WINDOW) ||
+      (current_operation_type() ==
+       OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT)) {
+    return;
+  }
   for (auto& pair : connection_map_) {
     pair.second->service()->ProcessWindowReorder(
         window, relative_window, direction, IsOperationSource(pair.first));
@@ -460,6 +466,26 @@
   host->UpdateTextInputState(window, state);
 }
 
+void ConnectionManager::OnTransientWindowAdded(ServerWindow* window,
+                                               ServerWindow* transient_child) {
+  for (auto& pair : connection_map_) {
+    pair.second->service()->ProcessTransientWindowAdded(
+        window, transient_child, IsOperationSource(pair.first));
+  }
+}
+
+void ConnectionManager::OnTransientWindowRemoved(
+    ServerWindow* window,
+    ServerWindow* transient_child) {
+  // If we're deleting a window, then this is a superfluous message.
+  if (current_operation_type() == OperationType::DELETE_WINDOW)
+    return;
+  for (auto& pair : connection_map_) {
+    pair.second->service()->ProcessTransientWindowRemoved(
+        window, transient_child, IsOperationSource(pair.first));
+  }
+}
+
 }  // namespace ws
 
 }  // namespace mus
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h
index b56156d..3236568 100644
--- a/components/mus/ws/connection_manager.h
+++ b/components/mus/ws/connection_manager.h
@@ -219,6 +219,10 @@
       const std::vector<uint8_t>* new_data) override;
   void OnWindowTextInputStateChanged(ServerWindow* window,
                                      const ui::TextInputState& state) override;
+  void OnTransientWindowAdded(ServerWindow* window,
+                              ServerWindow* transient_child) override;
+  void OnTransientWindowRemoved(ServerWindow* window,
+                                ServerWindow* transient_child) override;
 
   ConnectionManagerDelegate* delegate_;
 
diff --git a/components/mus/ws/default_access_policy.cc b/components/mus/ws/default_access_policy.cc
index b6d7494..0a9cb241 100644
--- a/components/mus/ws/default_access_policy.cc
+++ b/components/mus/ws/default_access_policy.cc
@@ -34,6 +34,23 @@
            !delegate_->IsWindowRootOfAnotherConnectionForAccessPolicy(parent)));
 }
 
+bool DefaultAccessPolicy::CanAddTransientWindow(
+    const ServerWindow* parent,
+    const ServerWindow* child) const {
+  return WasCreatedByThisConnection(child) &&
+         (delegate_->IsRootForAccessPolicy(parent->id()) ||
+          WasCreatedByThisConnection(parent));
+}
+
+bool DefaultAccessPolicy::CanRemoveTransientWindowFromParent(
+    const ServerWindow* window) const {
+  if (!WasCreatedByThisConnection(window))
+    return false;  // Can only unparent windows we created.
+
+  return delegate_->IsRootForAccessPolicy(window->transient_parent()->id()) ||
+         WasCreatedByThisConnection(window->transient_parent());
+}
+
 bool DefaultAccessPolicy::CanReorderWindow(
     const ServerWindow* window,
     const ServerWindow* relative_window,
diff --git a/components/mus/ws/default_access_policy.h b/components/mus/ws/default_access_policy.h
index c1af8f2..f5b766d 100644
--- a/components/mus/ws/default_access_policy.h
+++ b/components/mus/ws/default_access_policy.h
@@ -25,6 +25,10 @@
   bool CanRemoveWindowFromParent(const ServerWindow* window) const override;
   bool CanAddWindow(const ServerWindow* parent,
                     const ServerWindow* child) const override;
+  bool CanAddTransientWindow(const ServerWindow* parent,
+                             const ServerWindow* child) const override;
+  bool CanRemoveTransientWindowFromParent(
+      const ServerWindow* window) const override;
   bool CanReorderWindow(const ServerWindow* window,
                         const ServerWindow* relative_window,
                         mojom::OrderDirection direction) const override;
diff --git a/components/mus/ws/operation.h b/components/mus/ws/operation.h
index 615287e..b1dcc53a 100644
--- a/components/mus/ws/operation.h
+++ b/components/mus/ws/operation.h
@@ -18,9 +18,11 @@
 
 enum class OperationType {
   NONE,
+  ADD_TRANSIENT_WINDOW,
   ADD_WINDOW,
   DELETE_WINDOW,
   EMBED,
+  REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
   REMOVE_WINDOW_FROM_PARENT,
   REORDER_WINDOW,
   SET_FOCUS,
diff --git a/components/mus/ws/test_change_tracker.cc b/components/mus/ws/test_change_tracker.cc
index ac673ec..5f1e686 100644
--- a/components/mus/ws/test_change_tracker.cc
+++ b/components/mus/ws/test_change_tracker.cc
@@ -44,6 +44,11 @@
     case CHANGE_TYPE_UNEMBED:
       return "OnUnembed";
 
+    case CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW:
+      return base::StringPrintf("AddTransientWindow parent = %s child = %s",
+                                WindowIdToString(change.window_id).c_str(),
+                                WindowIdToString(change.window_id2).c_str());
+
     case CHANGE_TYPE_NODE_BOUNDS_CHANGED:
       return base::StringPrintf(
           "BoundsChanged window=%s old_bounds=%s new_bounds=%s",
@@ -62,6 +67,12 @@
           WindowIdToString(change.window_id2).c_str(),
           WindowIdToString(change.window_id3).c_str());
 
+    case CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT:
+      return base::StringPrintf(
+          "RemoveTransientWindowFromParent parent = %s child = %s",
+          WindowIdToString(change.window_id).c_str(),
+          WindowIdToString(change.window_id2).c_str());
+
     case CHANGE_TYPE_NODE_REORDERED:
       return base::StringPrintf("Reordered window=%s relative=%s direction=%s",
                                 WindowIdToString(change.window_id).c_str(),
@@ -211,6 +222,24 @@
   AddChange(change);
 }
 
+void TestChangeTracker::OnTransientWindowAdded(Id window_id,
+                                               Id transient_window_id) {
+  Change change;
+  change.type = CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW;
+  change.window_id = window_id;
+  change.window_id2 = transient_window_id;
+  AddChange(change);
+}
+
+void TestChangeTracker::OnTransientWindowRemoved(Id window_id,
+                                                 Id transient_window_id) {
+  Change change;
+  change.type = CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT;
+  change.window_id = window_id;
+  change.window_id2 = transient_window_id;
+  AddChange(change);
+}
+
 void TestChangeTracker::OnWindowViewportMetricsChanged(
     mojom::ViewportMetricsPtr old_metrics,
     mojom::ViewportMetricsPtr new_metrics) {
diff --git a/components/mus/ws/test_change_tracker.h b/components/mus/ws/test_change_tracker.h
index 5946a18f..ef833ae 100644
--- a/components/mus/ws/test_change_tracker.h
+++ b/components/mus/ws/test_change_tracker.h
@@ -23,9 +23,11 @@
   CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED,
   CHANGE_TYPE_UNEMBED,
   // TODO(sky): nuke NODE.
+  CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW,
   CHANGE_TYPE_NODE_BOUNDS_CHANGED,
   CHANGE_TYPE_NODE_VIEWPORT_METRICS_CHANGED,
   CHANGE_TYPE_NODE_HIERARCHY_CHANGED,
+  CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
   CHANGE_TYPE_NODE_REORDERED,
   CHANGE_TYPE_NODE_VISIBILITY_CHANGED,
   CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED,
@@ -122,6 +124,8 @@
   void OnEmbed(ConnectionSpecificId connection_id, mojom::WindowDataPtr root);
   void OnEmbeddedAppDisconnected(Id window_id);
   void OnUnembed();
+  void OnTransientWindowAdded(Id window_id, Id transient_window_id);
+  void OnTransientWindowRemoved(Id window_id, Id transient_window_id);
   void OnWindowBoundsChanged(Id window_id,
                              mojo::RectPtr old_bounds,
                              mojo::RectPtr new_bounds);
diff --git a/components/mus/ws/window_manager_access_policy.cc b/components/mus/ws/window_manager_access_policy.cc
index ce5b600..69c17f1e 100644
--- a/components/mus/ws/window_manager_access_policy.cc
+++ b/components/mus/ws/window_manager_access_policy.cc
@@ -31,6 +31,17 @@
   return true;
 }
 
+bool WindowManagerAccessPolicy::CanAddTransientWindow(
+    const ServerWindow* parent,
+    const ServerWindow* child) const {
+  return true;
+}
+
+bool WindowManagerAccessPolicy::CanRemoveTransientWindowFromParent(
+    const ServerWindow* window) const {
+  return true;
+}
+
 bool WindowManagerAccessPolicy::CanReorderWindow(
     const ServerWindow* window,
     const ServerWindow* relative_window,
diff --git a/components/mus/ws/window_manager_access_policy.h b/components/mus/ws/window_manager_access_policy.h
index ddeccdd..ba1c6b4 100644
--- a/components/mus/ws/window_manager_access_policy.h
+++ b/components/mus/ws/window_manager_access_policy.h
@@ -24,6 +24,10 @@
   bool CanRemoveWindowFromParent(const ServerWindow* window) const override;
   bool CanAddWindow(const ServerWindow* parent,
                     const ServerWindow* child) const override;
+  bool CanAddTransientWindow(const ServerWindow* parent,
+                             const ServerWindow* child) const override;
+  bool CanRemoveTransientWindowFromParent(
+      const ServerWindow* window) const override;
   bool CanReorderWindow(const ServerWindow* window,
                         const ServerWindow* relative_window,
                         mojom::OrderDirection direction) const override;
diff --git a/components/mus/ws/window_tree_apptest.cc b/components/mus/ws/window_tree_apptest.cc
index 0edf629..f6e0401 100644
--- a/components/mus/ws/window_tree_apptest.cc
+++ b/components/mus/ws/window_tree_apptest.cc
@@ -316,6 +316,14 @@
   void OnClientAreaChanged(uint32_t window_id,
                            mojo::InsetsPtr old_client_area,
                            mojo::InsetsPtr new_client_area) override {}
+  void OnTransientWindowAdded(uint32_t window_id,
+                              uint32_t transient_window_id) override {
+    tracker()->OnTransientWindowAdded(window_id, transient_window_id);
+  }
+  void OnTransientWindowRemoved(uint32_t window_id,
+                                uint32_t transient_window_id) override {
+    tracker()->OnTransientWindowRemoved(window_id, transient_window_id);
+  }
   void OnWindowViewportMetricsChanged(ViewportMetricsPtr old_metrics,
                                       ViewportMetricsPtr new_metrics) override {
     // Don't track the metrics as they are available at an indeterministic time
@@ -1709,6 +1717,52 @@
                         window_1_2));
 }
 
+// Verifies that a transient window tracks its parent's lifetime.
+TEST_F(WindowTreeAppTest, TransientWindowTracksTransientParentLifetime) {
+  ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true));
+  Id window_1_1 = BuildWindowId(connection_id_1(), 1);
+
+  Id window_2_1 = ws_client2()->NewWindow(1);
+  Id window_2_2 = ws_client2()->NewWindow(2);
+  Id window_2_3 = ws_client2()->NewWindow(3);
+  ASSERT_TRUE(window_2_1);
+
+  // root -> window_1_1 -> window_2_1
+  // root -> window_1_1 -> window_2_2
+  // root -> window_1_1 -> window_2_3
+  ASSERT_TRUE(AddWindow(ws1(), root_window_id(), window_1_1));
+  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_1));
+  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_2));
+  ASSERT_TRUE(AddWindow(ws2(), window_1_1, window_2_3));
+
+  // window_2_2 and window_2_3 now track the lifetime of window_2_1.
+  changes1()->clear();
+  ws2()->AddTransientWindow(10, window_2_1, window_2_2);
+  ws2()->AddTransientWindow(11, window_2_1, window_2_3);
+  ws_client1()->WaitForChangeCount(2);
+  EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
+                " child = " + IdToString(window_2_2),
+            ChangesToDescription1(*changes1())[0]);
+  EXPECT_EQ("AddTransientWindow parent = " + IdToString(window_2_1) +
+                " child = " + IdToString(window_2_3),
+            ChangesToDescription1(*changes1())[1]);
+
+  changes1()->clear();
+  ws2()->RemoveTransientWindowFromParent(12, window_2_3);
+  ws_client1()->WaitForChangeCount(1);
+  EXPECT_EQ("RemoveTransientWindowFromParent parent = " +
+                IdToString(window_2_1) + " child = " + IdToString(window_2_3),
+            SingleChangeToDescription(*changes1()));
+
+  changes1()->clear();
+  ASSERT_TRUE(DeleteWindow(ws2(), window_2_1));
+  ws_client1()->WaitForChangeCount(2);
+  EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_2),
+            ChangesToDescription1(*changes1())[0]);
+  EXPECT_EQ("WindowDeleted window=" + IdToString(window_2_1),
+            ChangesToDescription1(*changes1())[1]);
+}
+
 // TODO(sky): need to better track changes to initial connection. For example,
 // that SetBounsdWindows/AddWindow and the like don't result in messages to the
 // originating connection.
diff --git a/components/mus/ws/window_tree_impl.cc b/components/mus/ws/window_tree_impl.cc
index a16188c..6b594f7 100644
--- a/components/mus/ws/window_tree_impl.cc
+++ b/components/mus/ws/window_tree_impl.cc
@@ -143,6 +143,20 @@
   return false;
 }
 
+bool WindowTreeImpl::AddTransientWindow(const WindowId& window_id,
+                                        const WindowId& transient_window_id) {
+  ServerWindow* window = GetWindow(window_id);
+  ServerWindow* transient_window = GetWindow(transient_window_id);
+  if (window && transient_window && !transient_window->Contains(window) &&
+      access_policy_->CanAddTransientWindow(window, transient_window)) {
+    Operation op(this, connection_manager_,
+                 OperationType::ADD_TRANSIENT_WINDOW);
+    window->AddTransientWindow(transient_window);
+    return true;
+  }
+  return false;
+}
+
 std::vector<const ServerWindow*> WindowTreeImpl::GetWindowTree(
     const WindowId& window_id) const {
   const ServerWindow* window = GetWindow(window_id);
@@ -282,12 +296,14 @@
                                           mojom::OrderDirection direction,
                                           bool originated_change) {
   if (originated_change || !IsWindowKnown(window) ||
-      !IsWindowKnown(relative_window))
+      !IsWindowKnown(relative_window) ||
+      connection_manager_->DidConnectionMessageClient(id_))
     return;
 
   client()->OnWindowReordered(WindowIdToTransportId(window->id()),
                               WindowIdToTransportId(relative_window->id()),
                               direction);
+  connection_manager_->OnConnectionMessagedClient(id_);
 }
 
 void WindowTreeImpl::ProcessWindowDeleted(const WindowId& window,
@@ -344,6 +360,28 @@
                                    : WindowIdToTransportId(WindowId()));
 }
 
+void WindowTreeImpl::ProcessTransientWindowAdded(
+    const ServerWindow* window,
+    const ServerWindow* transient_window,
+    bool originated_change) {
+  if (originated_change)
+    return;
+  client()->OnTransientWindowAdded(
+      WindowIdToTransportId(window->id()),
+      WindowIdToTransportId(transient_window->id()));
+}
+
+void WindowTreeImpl::ProcessTransientWindowRemoved(
+    const ServerWindow* window,
+    const ServerWindow* transient_window,
+    bool originated_change) {
+  if (originated_change)
+    return;
+  client()->OnTransientWindowRemoved(
+      WindowIdToTransportId(window->id()),
+      WindowIdToTransportId(transient_window->id()));
+}
+
 bool WindowTreeImpl::ShouldRouteToWindowManager(
     const ServerWindow* window) const {
   // If the client created this window, then do not route it through the WM.
@@ -516,15 +554,23 @@
 }
 
 void WindowTreeImpl::DestroyWindows() {
-  if (!window_map_.empty()) {
-    Operation op(this, connection_manager_, OperationType::DELETE_WINDOW);
-    // If we get here from the destructor we're not going to get
-    // ProcessWindowDeleted(). Copy the map and delete from the copy so that we
-    // don't have to worry about whether |window_map_| changes or not.
-    WindowMap window_map_copy;
-    window_map_.swap(window_map_copy);
-    STLDeleteValues(&window_map_copy);
+  if (window_map_.empty())
+    return;
+
+  Operation op(this, connection_manager_, OperationType::DELETE_WINDOW);
+  // If we get here from the destructor we're not going to get
+  // ProcessWindowDeleted(). Copy the map and delete from the copy so that we
+  // don't have to worry about whether |window_map_| changes or not.
+  WindowMap window_map_copy;
+  window_map_.swap(window_map_copy);
+  // A sibling can be a transient parent of another window so we detach windows
+  // from their transient parents to avoid double deletes.
+  for (auto& pair : window_map_copy) {
+    ServerWindow* transient_parent = pair.second->transient_parent();
+    if (transient_parent)
+      transient_parent->RemoveTransientWindow(pair.second);
   }
+  STLDeleteValues(&window_map_copy);
 }
 
 bool WindowTreeImpl::CanEmbed(const WindowId& window_id,
@@ -601,6 +647,30 @@
   callback.Run(success);
 }
 
+void WindowTreeImpl::AddTransientWindow(uint32_t change_id,
+                                        Id window,
+                                        Id transient_window) {
+  client_->OnChangeCompleted(
+      change_id, AddTransientWindow(WindowIdFromTransportId(window),
+                                    WindowIdFromTransportId(transient_window)));
+}
+
+void WindowTreeImpl::RemoveTransientWindowFromParent(uint32_t change_id,
+                                                     Id transient_window_id) {
+  bool success = false;
+  ServerWindow* transient_window =
+      GetWindow(WindowIdFromTransportId(transient_window_id));
+  if (transient_window->transient_parent() &&
+      access_policy_->CanRemoveTransientWindowFromParent(transient_window)) {
+    success = true;
+    Operation op(this, connection_manager_,
+                 OperationType::REMOVE_TRANSIENT_WINDOW_FROM_PARENT);
+    transient_window->transient_parent()->RemoveTransientWindow(
+        transient_window);
+  }
+  client_->OnChangeCompleted(change_id, success);
+}
+
 void WindowTreeImpl::ReorderWindow(Id window_id,
                                    Id relative_window_id,
                                    mojom::OrderDirection direction,
@@ -664,7 +734,6 @@
   const bool success = window && access_policy_->CanSetWindowProperties(window);
   if (success) {
     Operation op(this, connection_manager_, OperationType::SET_WINDOW_PROPERTY);
-
     if (value.is_null()) {
       window->SetProperty(name, nullptr);
     } else {
diff --git a/components/mus/ws/window_tree_impl.h b/components/mus/ws/window_tree_impl.h
index 92717ed1..6574ac9 100644
--- a/components/mus/ws/window_tree_impl.h
+++ b/components/mus/ws/window_tree_impl.h
@@ -76,6 +76,8 @@
   // WindowTree implementations all call into these. See the mojom for details.
   bool NewWindow(const WindowId& window_id);
   bool AddWindow(const WindowId& parent_id, const WindowId& child_id);
+  bool AddTransientWindow(const WindowId& window_id,
+                          const WindowId& transient_window_id);
   std::vector<const ServerWindow*> GetWindowTree(
       const WindowId& window_id) const;
   bool SetWindowVisibility(const WindowId& window_id, bool visible);
@@ -119,6 +121,12 @@
                                          bool originated_change);
   void ProcessFocusChanged(const ServerWindow* old_focused_window,
                            const ServerWindow* new_focused_window);
+  void ProcessTransientWindowAdded(const ServerWindow* window,
+                                   const ServerWindow* transient_window,
+                                   bool originated_change);
+  void ProcessTransientWindowRemoved(const ServerWindow* window,
+                                     const ServerWindow* transient_window,
+                                     bool originated_change);
 
  private:
   using WindowIdSet = base::hash_set<Id>;
@@ -191,6 +199,11 @@
   void RemoveWindowFromParent(
       Id window_id,
       const mojo::Callback<void(bool)>& callback) override;
+  void AddTransientWindow(uint32_t change_id,
+                          Id window_id,
+                          Id transient_window_id) override;
+  void RemoveTransientWindowFromParent(uint32_t change_id,
+                                       Id transient_window_id) override;
   void ReorderWindow(Id window_id,
                      Id relative_window_id,
                      mojom::OrderDirection direction,
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index c2c9482..bf3fccd0 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -79,6 +79,10 @@
   void OnClientAreaChanged(uint32_t window_id,
                            mojo::InsetsPtr old_client_area,
                            mojo::InsetsPtr new_client_area) override {}
+  void OnTransientWindowAdded(uint32_t window_id,
+                              uint32_t transient_window_id) override {}
+  void OnTransientWindowRemoved(uint32_t window_id,
+                                uint32_t transient_window_id) override {}
   void OnWindowViewportMetricsChanged(
       mojom::ViewportMetricsPtr old_metrics,
       mojom::ViewportMetricsPtr new_metrics) override {
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index e5a507f..d70572d 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -349,6 +349,19 @@
         base::Bind(&CloseFile, base::Passed(file.Pass())));
   }
 #endif
+  base::File files_to_close[] = {
+      nexe_file_.Pass(),
+      socket_for_renderer_.Pass(),
+      socket_for_sel_ldr_.Pass(),
+  };
+  // Open files need to be closed on the blocking pool.
+  for (auto& file : files_to_close) {
+    if (file.IsValid()) {
+      content::BrowserThread::GetBlockingPool()->PostTask(
+          FROM_HERE,
+          base::Bind(&CloseFile, base::Passed(file.Pass())));
+    }
+  }
 
   if (reply_msg_) {
     // The process failed to launch for some reason.
diff --git a/components/nacl/renderer/plugin/pnacl_coordinator.cc b/components/nacl/renderer/plugin/pnacl_coordinator.cc
index 3270d07..052f289 100644
--- a/components/nacl/renderer/plugin/pnacl_coordinator.cc
+++ b/components/nacl/renderer/plugin/pnacl_coordinator.cc
@@ -289,7 +289,8 @@
   // The component updater's resource throttles + OnDemand update/install
   // should block the URL request until the compiler is present. Now we
   // can load the resources (e.g. llc and ld nexes).
-  resources_.reset(new PnaclResources(plugin_, pnacl_options_.use_subzero));
+  resources_.reset(new PnaclResources(plugin_,
+                                      PP_ToBool(pnacl_options_.use_subzero)));
   CHECK(resources_ != NULL);
 
   // The first step of loading resources: read the resource info file.
diff --git a/components/nacl/renderer/plugin/pnacl_translate_thread.cc b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
index 6e4d45d..8b26a11 100644
--- a/components/nacl/renderer/plugin/pnacl_translate_thread.cc
+++ b/components/nacl/renderer/plugin/pnacl_translate_thread.cc
@@ -223,10 +223,12 @@
   std::vector<char> split_args;
   if (pnacl_options_->use_subzero) {
     GetSubzeroCommandLine(&split_args, pnacl_options_->opt_level,
-                          pnacl_options_->is_debug, architecture_attributes_);
+                          PP_ToBool(pnacl_options_->is_debug),
+                          architecture_attributes_);
   } else {
     GetLlcCommandLine(&split_args, obj_files_->size(),
-                      pnacl_options_->opt_level, pnacl_options_->is_debug,
+                      pnacl_options_->opt_level,
+                      PP_ToBool(pnacl_options_->is_debug),
                       architecture_attributes_);
   }
 
diff --git a/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc b/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
index 07ae6c8..ece90f0 100644
--- a/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
+++ b/components/nacl/renderer/plugin/sel_ldr_launcher_chrome.cc
@@ -10,7 +10,9 @@
 
 bool SelLdrLauncherChrome::Start(const char* url) {
   NACL_NOTREACHED();
-  return false;
+  /*
+   * No return here because MSVC warns about it as unreached code.
+   */
 }
 
 void SelLdrLauncherChrome::set_channel(NaClHandle channel) {
diff --git a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc b/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
index 939579b..7052a6f 100644
--- a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/password_manager/content/common/credential_manager_messages.h"
 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
 #include "components/password_manager/core/browser/mock_affiliated_match_helper.h"
+#include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/password_manager/core/browser/test_password_store.h"
@@ -139,6 +140,11 @@
   return driver_;
 }
 
+class MockPasswordManagerDriver : public StubPasswordManagerDriver {
+ public:
+  MOCK_METHOD0(GetPasswordManager, PasswordManager*());
+};
+
 void RunAllPendingTasks() {
   base::RunLoop run_loop;
   base::MessageLoop::current()->PostTask(
@@ -157,8 +163,11 @@
     content::RenderViewHostTestHarness::SetUp();
     store_ = new TestPasswordStore;
     client_.reset(new MockPasswordManagerClient(store_.get()));
+    password_manager_.reset(new PasswordManager(client_.get()));
+    ON_CALL(mock_driver_, GetPasswordManager())
+        .WillByDefault(testing::Return(password_manager_.get()));
     dispatcher_.reset(new TestCredentialManagerDispatcher(
-        web_contents(), client_.get(), &stub_driver_));
+        web_contents(), client_.get(), &mock_driver_));
     ON_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
         .WillByDefault(testing::Return(true));
     ON_CALL(*client_, IsOffTheRecord()).WillByDefault(testing::Return(false));
@@ -267,8 +276,9 @@
   autofill::PasswordForm cross_origin_form_;
   scoped_refptr<TestPasswordStore> store_;
   scoped_ptr<MockPasswordManagerClient> client_;
-  StubPasswordManagerDriver stub_driver_;
+  MockPasswordManagerDriver mock_driver_;
   scoped_ptr<CredentialManagerDispatcher> dispatcher_;
+  scoped_ptr<PasswordManager> password_manager_;
 };
 
 TEST_F(CredentialManagerDispatcherTest, CredentialManagerOnStore) {
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index a12b8e3..4869159d 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -38,6 +38,8 @@
                PasswordStoreChangeList(base::Time, base::Time));
   MOCK_METHOD2(RemoveLoginsSyncedBetweenImpl,
                PasswordStoreChangeList(base::Time, base::Time));
+  MOCK_METHOD2(RemoveStatisticsCreatedBetweenImpl,
+               bool(base::Time, base::Time));
   ScopedVector<autofill::PasswordForm> FillMatchingLogins(
       const autofill::PasswordForm& form,
       PasswordStore::AuthorizationPromptPolicy prompt_policy) override {
diff --git a/components/password_manager/core/browser/password_manager_client.cc b/components/password_manager/core/browser/password_manager_client.cc
index 7b1e0ef..3bf6c76 100644
--- a/components/password_manager/core/browser/password_manager_client.cc
+++ b/components/password_manager/core/browser/password_manager_client.cc
@@ -69,10 +69,15 @@
   return false;
 }
 
-PasswordManager* PasswordManagerClient::GetPasswordManager() {
+const PasswordManager* PasswordManagerClient::GetPasswordManager() const {
   return nullptr;
 }
 
+PasswordManager* PasswordManagerClient::GetPasswordManager() {
+  return const_cast<PasswordManager*>(
+      static_cast<const PasswordManagerClient*>(this)->GetPasswordManager());
+}
+
 autofill::AutofillManager*
 PasswordManagerClient::GetAutofillManagerForMainFrame() {
   return nullptr;
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 406052e..b2af53f 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -154,8 +154,10 @@
   // If this browsing session should not be persisted.
   virtual bool IsOffTheRecord() const;
 
-  // Returns the PasswordManager associated with this client.
-  virtual PasswordManager* GetPasswordManager();
+  // Returns the PasswordManager associated with this client. The non-const
+  // version calls the const one.
+  PasswordManager* GetPasswordManager();
+  virtual const PasswordManager* GetPasswordManager() const;
 
   // Returns the AutofillManager for the main frame.
   virtual autofill::AutofillManager* GetAutofillManagerForMainFrame();
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index b6c291c..560a2928 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -134,6 +134,15 @@
                           this, delete_begin, delete_end));
 }
 
+void PasswordStore::RemoveStatisticsCreatedBetween(
+    base::Time delete_begin,
+    base::Time delete_end,
+    const base::Closure& completion) {
+  ScheduleTask(
+      base::Bind(&PasswordStore::RemoveStatisticsCreatedBetweenInternal, this,
+                 delete_begin, delete_end, completion));
+}
+
 void PasswordStore::TrimAffiliationCache() {
   if (affiliated_match_helper_)
     affiliated_match_helper_->TrimAffiliationCache();
@@ -374,6 +383,15 @@
   NotifyLoginsChanged(changes);
 }
 
+void PasswordStore::RemoveStatisticsCreatedBetweenInternal(
+    base::Time delete_begin,
+    base::Time delete_end,
+    const base::Closure& completion) {
+  RemoveStatisticsCreatedBetweenImpl(delete_begin, delete_end);
+  if (!completion.is_null())
+    main_thread_runner_->PostTask(FROM_HERE, completion);
+}
+
 void PasswordStore::GetAutofillableLoginsImpl(
     scoped_ptr<GetLoginsRequest> request) {
   ScopedVector<PasswordForm> obtained_forms;
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 785efc1..6b2f352 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -111,21 +111,29 @@
   // in the given date range. |completion| will be posted to the
   // |main_thread_runner_| after deletions have been completed and notification
   // have been sent out.
-  virtual void RemoveLoginsByOriginAndTime(const url::Origin& origin,
-                                           base::Time delete_begin,
-                                           base::Time delete_end,
-                                           const base::Closure& completion);
+  void RemoveLoginsByOriginAndTime(const url::Origin& origin,
+                                   base::Time delete_begin,
+                                   base::Time delete_end,
+                                   const base::Closure& completion);
 
   // Removes all logins created in the given date range. If |completion| is not
   // null, it will be posted to the |main_thread_runner_| after deletions have
   // be completed and notification have been sent out.
-  virtual void RemoveLoginsCreatedBetween(base::Time delete_begin,
-                                          base::Time delete_end,
-                                          const base::Closure& completion);
+  void RemoveLoginsCreatedBetween(base::Time delete_begin,
+                                  base::Time delete_end,
+                                  const base::Closure& completion);
 
   // Removes all logins synced in the given date range.
-  virtual void RemoveLoginsSyncedBetween(base::Time delete_begin,
-                                         base::Time delete_end);
+  void RemoveLoginsSyncedBetween(base::Time delete_begin,
+                                 base::Time delete_end);
+
+  // Removes all the stats created in the given date range. If |completion| is
+  // not null, it will be posted to the |main_thread_runner_| after deletions
+  // have been completed.
+  // Should be called on the UI thread.
+  void RemoveStatisticsCreatedBetween(base::Time delete_begin,
+                                      base::Time delete_end,
+                                      const base::Closure& completion);
 
   // Removes cached affiliation data that is no longer needed; provided that
   // affiliation-based matching is enabled.
@@ -249,6 +257,10 @@
       base::Time delete_begin,
       base::Time delete_end) = 0;
 
+  // Synchronous implementation to remove the statistics.
+  virtual bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
+                                                  base::Time delete_end) = 0;
+
   // Finds all PasswordForms with a signon_realm that is equal to, or is a
   // PSL-match to that of |form|, and takes care of notifying the consumer with
   // the results when done.
@@ -347,6 +359,9 @@
                                           const base::Closure& completion);
   void RemoveLoginsSyncedBetweenInternal(base::Time delete_begin,
                                          base::Time delete_end);
+  void RemoveStatisticsCreatedBetweenInternal(base::Time delete_begin,
+                                              base::Time delete_end,
+                                              const base::Closure& completion);
 
   // Finds all non-blacklist PasswordForms, and notifies the consumer.
   void GetAutofillableLoginsImpl(scoped_ptr<GetLoginsRequest> request);
diff --git a/components/password_manager/core/browser/password_store_default.cc b/components/password_manager/core/browser/password_store_default.cc
index 89ca082..ad65039 100644
--- a/components/password_manager/core/browser/password_store_default.cc
+++ b/components/password_manager/core/browser/password_store_default.cc
@@ -137,6 +137,13 @@
   return changes;
 }
 
+bool PasswordStoreDefault::RemoveStatisticsCreatedBetweenImpl(
+    base::Time delete_begin,
+    base::Time delete_end) {
+  return login_db_ &&
+         login_db_->stats_table().RemoveStatsBetween(delete_begin, delete_end);
+}
+
 ScopedVector<autofill::PasswordForm> PasswordStoreDefault::FillMatchingLogins(
     const autofill::PasswordForm& form,
     AuthorizationPromptPolicy prompt_policy) {
diff --git a/components/password_manager/core/browser/password_store_default.h b/components/password_manager/core/browser/password_store_default.h
index b43c20e..7a251a1 100644
--- a/components/password_manager/core/browser/password_store_default.h
+++ b/components/password_manager/core/browser/password_store_default.h
@@ -56,6 +56,8 @@
   PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
       base::Time delete_begin,
       base::Time delete_end) override;
+  bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
+                                          base::Time delete_end) override;
   ScopedVector<autofill::PasswordForm> FillMatchingLogins(
       const autofill::PasswordForm& form,
       AuthorizationPromptPolicy prompt_policy) override;
diff --git a/components/password_manager/core/browser/test_password_store.cc b/components/password_manager/core/browser/test_password_store.cc
index bb81d46c..1daef7c5 100644
--- a/components/password_manager/core/browser/test_password_store.cc
+++ b/components/password_manager/core/browser/test_password_store.cc
@@ -108,6 +108,12 @@
   return changes;
 }
 
+bool TestPasswordStore::RemoveStatisticsCreatedBetweenImpl(
+    base::Time delete_begin,
+    base::Time delete_end) {
+  return false;
+}
+
 bool TestPasswordStore::FillAutofillableLogins(
     ScopedVector<autofill::PasswordForm>* forms) {
   for (const auto& forms_for_realm : stored_passwords_) {
diff --git a/components/password_manager/core/browser/test_password_store.h b/components/password_manager/core/browser/test_password_store.h
index 826ed0e..661d761 100644
--- a/components/password_manager/core/browser/test_password_store.h
+++ b/components/password_manager/core/browser/test_password_store.h
@@ -56,6 +56,8 @@
   PasswordStoreChangeList RemoveLoginsSyncedBetweenImpl(
       base::Time delete_begin,
       base::Time delete_end) override;
+  bool RemoveStatisticsCreatedBetweenImpl(base::Time delete_begin,
+                                          base::Time delete_end) override;
   bool FillAutofillableLogins(
       ScopedVector<autofill::PasswordForm>* forms) override;
   bool FillBlacklistLogins(
diff --git a/components/test_runner/test_common.cc b/components/test_runner/test_common.cc
index ad06d5233..8a096d6 100644
--- a/components/test_runner/test_common.cc
+++ b/components/test_runner/test_common.cc
@@ -6,6 +6,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "base/rand_util.h"
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 
@@ -30,7 +31,10 @@
   }
   ~MockBlinkPlatform() override {}
   void cryptographicallyRandomValues(unsigned char* buffer,
-                                     size_t length) override {}
+                                     size_t length) override {
+    base::RandBytes(buffer, length);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MockBlinkPlatform);
 };
diff --git a/components/visitedlink/test/visitedlink_unittest.cc b/components/visitedlink/test/visitedlink_unittest.cc
index f663f83..3fc25ce 100644
--- a/components/visitedlink/test/visitedlink_unittest.cc
+++ b/components/visitedlink/test/visitedlink_unittest.cc
@@ -593,6 +593,16 @@
     content::RenderViewHostTestHarness::SetUp();
   }
 
+  void TearDown() override {
+    // Explicitly destroy the master before proceeding with the rest
+    // of teardown because it posts a task to close a file handle, and
+    // we need to make sure we've finished all file related work
+    // before our superclass sets about destroying the scoped temp
+    // directory.
+    master_.reset();
+    RenderViewHostTestHarness::TearDown();
+  }
+
   content::BrowserContext* CreateBrowserContext() override {
     VisitCountingContext* context = new VisitCountingContext();
     master_.reset(new VisitedLinkMaster(context, &delegate_, true));
@@ -608,7 +618,7 @@
     return master_.get();
   }
 
-  void WaitForCoalescense() {
+  void WaitForCoalescence() {
     // Let the timer fire.
     //
     // TODO(ajwong): This is horrid! What is the right synchronization method?
@@ -627,7 +637,7 @@
   scoped_ptr<VisitedLinkMaster> master_;
 };
 
-TEST_F(VisitedLinkEventsTest, Coalescense) {
+TEST_F(VisitedLinkEventsTest, Coalescence) {
   // add some URLs to master.
   // Add a few URLs.
   master()->AddURL(GURL("http://acidtests.org/"));
@@ -641,7 +651,7 @@
   EXPECT_EQ(0, context()->add_count());
   EXPECT_EQ(0, context()->add_event_count());
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We now should have 3 entries added in 1 event.
   EXPECT_EQ(3, context()->add_count());
@@ -652,7 +662,7 @@
   master()->AddURL(GURL("http://webkit.org/"));
   master()->AddURL(GURL("http://acid3.acidtests.org/"));
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We should have 6 entries added in 2 events.
   EXPECT_EQ(6, context()->add_count());
@@ -661,7 +671,7 @@
   // Test whether duplicate entries produce add events.
   master()->AddURL(GURL("http://acidtests.org/"));
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We should have no change in results.
   EXPECT_EQ(6, context()->add_count());
@@ -671,7 +681,7 @@
   master()->AddURL(GURL("http://build.chromium.org/"));
   master()->DeleteAllURLs();
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We should have no change in results except for one new reset event.
   EXPECT_EQ(6, context()->add_count());
@@ -688,7 +698,7 @@
   master()->AddURL(GURL("http://google.com/"));
   master()->AddURL(GURL("http://chromium.org/"));
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We now should have 1 add event.
   EXPECT_EQ(1, context()->add_event_count());
@@ -696,7 +706,7 @@
 
   master()->DeleteAllURLs();
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We should have no change in add results, plus one new reset event.
   EXPECT_EQ(1, context()->add_event_count());
@@ -715,7 +725,7 @@
   master()->AddURL(GURL("http://google.com/"));
   master()->AddURL(GURL("http://chromium.org/"));
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // We shouldn't have any events.
   EXPECT_EQ(0, context()->add_event_count());
@@ -735,7 +745,7 @@
   for (int i = 0; i < 100; i++)
     master()->AddURL(TestURL(i));
 
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   // Again, no change in events until tab is active.
   EXPECT_EQ(1, context()->add_event_count());
@@ -759,7 +769,7 @@
       content::NOTIFICATION_RENDERER_PROCESS_CREATED,
       content::Source<content::RenderProcessHost>(&different_process_host),
       content::NotificationService::NoDetails());
-  WaitForCoalescense();
+  WaitForCoalescence();
 
   EXPECT_EQ(0, different_context.new_table_count());
 }
diff --git a/content/browser/device_sensors/data_fetcher_shared_memory_android.cc b/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
index d2eebb4..d746b4d32 100644
--- a/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
+++ b/content/browser/device_sensors/data_fetcher_shared_memory_android.cc
@@ -23,20 +23,22 @@
 
   switch (consumer_type) {
     case CONSUMER_TYPE_MOTION:
-      return SensorManagerAndroid::GetInstance()->
-          StartFetchingDeviceMotionData(
-              static_cast<DeviceMotionHardwareBuffer*>(buffer));
+      SensorManagerAndroid::GetInstance()->StartFetchingDeviceMotionData(
+          static_cast<DeviceMotionHardwareBuffer*>(buffer));
+      return true;
     case CONSUMER_TYPE_ORIENTATION:
-      return SensorManagerAndroid::GetInstance()->
-          StartFetchingDeviceOrientationData(
-              static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+      SensorManagerAndroid::GetInstance()->StartFetchingDeviceOrientationData(
+          static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+      return true;
     case CONSUMER_TYPE_ORIENTATION_ABSOLUTE:
-      return SensorManagerAndroid::GetInstance()->
+      SensorManagerAndroid::GetInstance()->
           StartFetchingDeviceOrientationAbsoluteData(
               static_cast<DeviceOrientationHardwareBuffer*>(buffer));
+      return true;
     case CONSUMER_TYPE_LIGHT:
-      return SensorManagerAndroid::GetInstance()->StartFetchingDeviceLightData(
+      SensorManagerAndroid::GetInstance()->StartFetchingDeviceLightData(
           static_cast<DeviceLightHardwareBuffer*>(buffer));
+      return true;
     default:
       NOTREACHED();
   }
diff --git a/content/browser/device_sensors/sensor_manager_android.cc b/content/browser/device_sensors/sensor_manager_android.cc
index 148ad7b..a108666 100644
--- a/content/browser/device_sensors/sensor_manager_android.cc
+++ b/content/browser/device_sensors/sensor_manager_android.cc
@@ -23,6 +23,28 @@
       type, content::SensorManagerAndroid::ORIENTATION_SENSOR_MAX);
 }
 
+void SetOrientation(content::DeviceOrientationHardwareBuffer* buffer,
+    double alpha, double beta, double gamma) {
+  buffer->seqlock.WriteBegin();
+  buffer->data.alpha = alpha;
+  buffer->data.hasAlpha = true;
+  buffer->data.beta = beta;
+  buffer->data.hasBeta = true;
+  buffer->data.gamma = gamma;
+  buffer->data.hasGamma = true;
+  buffer->seqlock.WriteEnd();
+}
+
+void SetOrientationBufferStatus(
+    content::DeviceOrientationHardwareBuffer* buffer,
+    bool ready, bool absolute) {
+  buffer->seqlock.WriteBegin();
+  buffer->data.absolute = absolute;
+  buffer->data.hasAbsolute = ready;
+  buffer->data.allAvailableSensorsAreActive = ready;
+  buffer->seqlock.WriteEnd();
+}
+
 }  // namespace
 
 namespace content {
@@ -60,23 +82,35 @@
   if (!device_orientation_buffer_)
     return;
 
-  device_orientation_buffer_->seqlock.WriteBegin();
-  device_orientation_buffer_->data.alpha = alpha;
-  device_orientation_buffer_->data.hasAlpha = true;
-  device_orientation_buffer_->data.beta = beta;
-  device_orientation_buffer_->data.hasBeta = true;
-  device_orientation_buffer_->data.gamma = gamma;
-  device_orientation_buffer_->data.hasGamma = true;
-  device_orientation_buffer_->seqlock.WriteEnd();
+  SetOrientation(device_orientation_buffer_, alpha, beta, gamma);
 
   if (!orientation_buffer_initialized_) {
     OrientationSensorType type =
         static_cast<OrientationSensorType>(GetOrientationSensorTypeUsed());
-    SetOrientationBufferStatus(true, type != GAME_ROTATION_VECTOR);
+    SetOrientationBufferStatus(device_orientation_buffer_, true,
+        type != GAME_ROTATION_VECTOR);
+    orientation_buffer_initialized_ = true;
     UpdateDeviceOrientationHistogram(type);
   }
 }
 
+void SensorManagerAndroid::GotOrientationAbsolute(
+    JNIEnv*, jobject, double alpha, double beta, double gamma) {
+  base::AutoLock autolock(orientation_absolute_buffer_lock_);
+
+  if (!device_orientation_absolute_buffer_)
+    return;
+
+  SetOrientation(device_orientation_absolute_buffer_, alpha, beta, gamma);
+
+  if (!orientation_absolute_buffer_initialized_) {
+    SetOrientationBufferStatus(device_orientation_absolute_buffer_, true, true);
+    orientation_absolute_buffer_initialized_ = true;
+    // TODO(timvolodine): Add UMA.
+  }
+}
+
+
 void SensorManagerAndroid::GotAcceleration(
     JNIEnv*, jobject, double x, double y, double z) {
   base::AutoLock autolock(motion_buffer_lock_);
@@ -154,23 +188,23 @@
   device_light_buffer_->seqlock.WriteEnd();
 }
 
-bool SensorManagerAndroid::Start(ConsumerType event_type) {
+bool SensorManagerAndroid::Start(ConsumerType consumer_type) {
   DCHECK(!device_sensors_.is_null());
-  int rate_in_microseconds = (event_type == CONSUMER_TYPE_LIGHT)
+  int rate_in_microseconds = (consumer_type == CONSUMER_TYPE_LIGHT)
                                  ? kLightSensorIntervalMicroseconds
                                  : kInertialSensorIntervalMicroseconds;
   return Java_DeviceSensors_start(AttachCurrentThread(),
                                   device_sensors_.obj(),
                                   reinterpret_cast<intptr_t>(this),
-                                  static_cast<jint>(event_type),
+                                  static_cast<jint>(consumer_type),
                                   rate_in_microseconds);
 }
 
-void SensorManagerAndroid::Stop(ConsumerType event_type) {
+void SensorManagerAndroid::Stop(ConsumerType consumer_type) {
   DCHECK(!device_sensors_.is_null());
   Java_DeviceSensors_stop(AttachCurrentThread(),
                           device_sensors_.obj(),
-                          static_cast<jint>(event_type));
+                          static_cast<jint>(consumer_type));
 }
 
 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
@@ -179,17 +213,19 @@
       AttachCurrentThread(), device_sensors_.obj());
 }
 
-int SensorManagerAndroid::GetOrientationSensorTypeUsed() {
+SensorManagerAndroid::OrientationSensorType
+SensorManagerAndroid::GetOrientationSensorTypeUsed() {
   DCHECK(!device_sensors_.is_null());
-  return Java_DeviceSensors_getOrientationSensorTypeUsed(
-      AttachCurrentThread(), device_sensors_.obj());
+  return static_cast<SensorManagerAndroid::OrientationSensorType>(
+      Java_DeviceSensors_getOrientationSensorTypeUsed(
+          AttachCurrentThread(), device_sensors_.obj()));
 }
 
 // ----- Shared memory API methods
 
 // --- Device Light
 
-bool SensorManagerAndroid::StartFetchingDeviceLightData(
+void SensorManagerAndroid::StartFetchingDeviceLightData(
     DeviceLightHardwareBuffer* buffer) {
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     StartFetchingLightDataOnUI(buffer);
@@ -200,7 +236,6 @@
                    base::Unretained(this),
                    buffer));
   }
-  return true;
 }
 
 void SensorManagerAndroid::StartFetchingLightDataOnUI(
@@ -257,7 +292,7 @@
 
 // --- Device Motion
 
-bool SensorManagerAndroid::StartFetchingDeviceMotionData(
+void SensorManagerAndroid::StartFetchingDeviceMotionData(
     DeviceMotionHardwareBuffer* buffer) {
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     StartFetchingMotionDataOnUI(buffer);
@@ -268,7 +303,6 @@
                    base::Unretained(this),
                    buffer));
   }
-  return true;
 }
 
 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
@@ -359,17 +393,7 @@
 
 // --- Device Orientation
 
-void SensorManagerAndroid::SetOrientationBufferStatus(bool ready,
-    bool absolute) {
-  device_orientation_buffer_->seqlock.WriteBegin();
-  device_orientation_buffer_->data.absolute = absolute;
-  device_orientation_buffer_->data.hasAbsolute = ready;
-  device_orientation_buffer_->data.allAvailableSensorsAreActive = ready;
-  device_orientation_buffer_->seqlock.WriteEnd();
-  orientation_buffer_initialized_ = ready;
-}
-
-bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
+void SensorManagerAndroid::StartFetchingDeviceOrientationData(
     DeviceOrientationHardwareBuffer* buffer) {
   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     StartFetchingOrientationDataOnUI(buffer);
@@ -380,7 +404,6 @@
                    base::Unretained(this),
                    buffer));
   }
-  return true;
 }
 
 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
@@ -400,7 +423,9 @@
     base::AutoLock autolock(orientation_buffer_lock_);
     // If Start() was unsuccessful then set the buffer ready flag to true
     // to start firing all-null events.
-    SetOrientationBufferStatus(!success /* ready */, false /* absolute */);
+    SetOrientationBufferStatus(buffer, !success /* ready */,
+        false /* absolute */);
+    orientation_buffer_initialized_ = !success;
   }
 
   if (!success)
@@ -428,20 +453,77 @@
   {
     base::AutoLock autolock(orientation_buffer_lock_);
     if (device_orientation_buffer_) {
-      SetOrientationBufferStatus(false, false);
+      SetOrientationBufferStatus(device_orientation_buffer_, false, false);
+      orientation_buffer_initialized_ = false;
       device_orientation_buffer_ = nullptr;
     }
   }
 }
 
-bool SensorManagerAndroid::StartFetchingDeviceOrientationAbsoluteData(
+void SensorManagerAndroid::StartFetchingDeviceOrientationAbsoluteData(
     DeviceOrientationHardwareBuffer* buffer) {
-  NOTIMPLEMENTED();
-  return false;
+  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    StartFetchingOrientationAbsoluteDataOnUI(buffer);
+  } else {
+    BrowserThread::PostTask(
+        BrowserThread::UI, FROM_HERE,
+        base::Bind(
+            &SensorManagerAndroid::StartFetchingOrientationAbsoluteDataOnUI,
+            base::Unretained(this),
+            buffer));
+  }
 }
 
 void SensorManagerAndroid::StopFetchingDeviceOrientationAbsoluteData() {
-  NOTIMPLEMENTED();
+  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
+    StopFetchingOrientationAbsoluteDataOnUI();
+    return;
+  }
+
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&SensorManagerAndroid::StopFetchingOrientationAbsoluteDataOnUI,
+                 base::Unretained(this)));
+}
+
+void SensorManagerAndroid::StartFetchingOrientationAbsoluteDataOnUI(
+    DeviceOrientationHardwareBuffer* buffer) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  DCHECK(buffer);
+  if (is_shutdown_)
+    return;
+
+  {
+    base::AutoLock autolock(orientation_absolute_buffer_lock_);
+    device_orientation_absolute_buffer_ = buffer;
+  }
+  bool success = Start(CONSUMER_TYPE_ORIENTATION_ABSOLUTE);
+
+  {
+    base::AutoLock autolock(orientation_absolute_buffer_lock_);
+    // If Start() was unsuccessful then set the buffer ready flag to true
+    // to start firing all-null events.
+    SetOrientationBufferStatus(buffer, !success /* ready */,
+        false /* absolute */);
+    orientation_absolute_buffer_initialized_ = !success;
+  }
+}
+
+void SensorManagerAndroid::StopFetchingOrientationAbsoluteDataOnUI() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  if (is_shutdown_)
+    return;
+
+  Stop(CONSUMER_TYPE_ORIENTATION_ABSOLUTE);
+  {
+    base::AutoLock autolock(orientation_absolute_buffer_lock_);
+    if (device_orientation_absolute_buffer_) {
+      SetOrientationBufferStatus(device_orientation_absolute_buffer_, false,
+          false);
+      orientation_absolute_buffer_initialized_ = false;
+      device_orientation_absolute_buffer_ = nullptr;
+    }
+  }
 }
 
 void SensorManagerAndroid::Shutdown() {
diff --git a/content/browser/device_sensors/sensor_manager_android.h b/content/browser/device_sensors/sensor_manager_android.h
index e147f79..44595563 100644
--- a/content/browser/device_sensors/sensor_manager_android.h
+++ b/content/browser/device_sensors/sensor_manager_android.h
@@ -38,6 +38,8 @@
   void GotLight(JNIEnv*, jobject, double value);
   void GotOrientation(JNIEnv*, jobject,
                       double alpha, double beta, double gamma);
+  void GotOrientationAbsolute(JNIEnv*, jobject,
+                      double alpha, double beta, double gamma);
   void GotAcceleration(JNIEnv*, jobject,
                        double x, double y, double z);
   void GotAccelerationIncludingGravity(JNIEnv*, jobject,
@@ -46,17 +48,17 @@
                        double alpha, double beta, double gamma);
 
   // Shared memory related methods.
-  bool StartFetchingDeviceLightData(DeviceLightHardwareBuffer* buffer);
+  void StartFetchingDeviceLightData(DeviceLightHardwareBuffer* buffer);
   void StopFetchingDeviceLightData();
 
-  bool StartFetchingDeviceMotionData(DeviceMotionHardwareBuffer* buffer);
+  void StartFetchingDeviceMotionData(DeviceMotionHardwareBuffer* buffer);
   void StopFetchingDeviceMotionData();
 
-  bool StartFetchingDeviceOrientationData(
+  void StartFetchingDeviceOrientationData(
       DeviceOrientationHardwareBuffer* buffer);
   void StopFetchingDeviceOrientationData();
 
-  bool StartFetchingDeviceOrientationAbsoluteData(
+  void StartFetchingDeviceOrientationAbsoluteData(
       DeviceOrientationHardwareBuffer* buffer);
   void StopFetchingDeviceOrientationAbsoluteData();
 
@@ -77,9 +79,15 @@
   SensorManagerAndroid();
   virtual ~SensorManagerAndroid();
 
-  virtual bool Start(ConsumerType event_type);
-  virtual void Stop(ConsumerType event_type);
-  virtual int GetOrientationSensorTypeUsed();
+  // Starts listening to the sensors corresponding to the consumer_type.
+  // Returns true if the registration with sensors was successful.
+  virtual bool Start(ConsumerType consumer_type);
+  // Stops listening to the sensors corresponding to the consumer_type.
+  virtual void Stop(ConsumerType consumer_type);
+  // Returns currently used sensor type for device orientation.
+  virtual OrientationSensorType GetOrientationSensorTypeUsed();
+  // Returns the number of active sensors corresponding to
+  // ConsumerType.DEVICE_MOTION.
   virtual int GetNumberActiveDeviceMotionSensors();
 
   void StartFetchingLightDataOnUI(DeviceLightHardwareBuffer* buffer);
@@ -92,6 +100,10 @@
       DeviceOrientationHardwareBuffer* buffer);
   void StopFetchingOrientationDataOnUI();
 
+  void StartFetchingOrientationAbsoluteDataOnUI(
+      DeviceOrientationHardwareBuffer* buffer);
+  void StopFetchingOrientationAbsoluteDataOnUI();
+
  private:
   friend struct base::DefaultSingletonTraits<SensorManagerAndroid>;
 
@@ -108,22 +120,25 @@
   void SetMotionBufferReadyStatus(bool ready);
   void ClearInternalMotionBuffers();
 
-  void SetOrientationBufferStatus(bool ready, bool absolute);
-
   // The Java provider of sensors info.
   base::android::ScopedJavaGlobalRef<jobject> device_sensors_;
   int number_active_device_motion_sensors_;
   int received_motion_data_[RECEIVED_MOTION_DATA_MAX];
+
+  // Cached pointers to buffers, owned by DataFetcherSharedMemoryBase.
   DeviceLightHardwareBuffer* device_light_buffer_;
   DeviceMotionHardwareBuffer* device_motion_buffer_;
   DeviceOrientationHardwareBuffer* device_orientation_buffer_;
+  DeviceOrientationHardwareBuffer* device_orientation_absolute_buffer_;
 
   bool motion_buffer_initialized_;
   bool orientation_buffer_initialized_;
+  bool orientation_absolute_buffer_initialized_;
 
   base::Lock light_buffer_lock_;
   base::Lock motion_buffer_lock_;
   base::Lock orientation_buffer_lock_;
+  base::Lock orientation_absolute_buffer_lock_;
 
   bool is_shutdown_;
 
diff --git a/content/browser/device_sensors/sensor_manager_android_unittest.cc b/content/browser/device_sensors/sensor_manager_android_unittest.cc
index 84ee9cb..133b1b5 100644
--- a/content/browser/device_sensors/sensor_manager_android_unittest.cc
+++ b/content/browser/device_sensors/sensor_manager_android_unittest.cc
@@ -20,7 +20,7 @@
   FakeSensorManagerAndroid() {}
   ~FakeSensorManagerAndroid() override {}
 
-  int GetOrientationSensorTypeUsed() override {
+  OrientationSensorType GetOrientationSensorTypeUsed() override {
     return SensorManagerAndroid::ROTATION_VECTOR;
   }
 
@@ -46,11 +46,25 @@
     light_buffer_.reset(new DeviceLightHardwareBuffer);
     motion_buffer_.reset(new DeviceMotionHardwareBuffer);
     orientation_buffer_.reset(new DeviceOrientationHardwareBuffer);
+    orientation_absolute_buffer_.reset(new DeviceOrientationHardwareBuffer);
+  }
+
+  void VerifyOrientationBufferValues(
+      const DeviceOrientationHardwareBuffer* buffer,
+      double alpha, double beta, double gamma) {
+    ASSERT_TRUE(buffer->data.allAvailableSensorsAreActive);
+    ASSERT_EQ(alpha, buffer->data.alpha);
+    ASSERT_TRUE(buffer->data.hasAlpha);
+    ASSERT_EQ(beta, buffer->data.beta);
+    ASSERT_TRUE(buffer->data.hasBeta);
+    ASSERT_EQ(gamma, buffer->data.gamma);
+    ASSERT_TRUE(buffer->data.hasGamma);
   }
 
   scoped_ptr<DeviceLightHardwareBuffer> light_buffer_;
   scoped_ptr<DeviceMotionHardwareBuffer> motion_buffer_;
   scoped_ptr<DeviceOrientationHardwareBuffer> orientation_buffer_;
+  scoped_ptr<DeviceOrientationHardwareBuffer> orientation_absolute_buffer_;
   content::TestBrowserThreadBundle thread_bundle_;
 };
 
@@ -62,7 +76,7 @@
   sensorManager.StartFetchingDeviceMotionData(motion_buffer_.get());
   ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
 
-  sensorManager.GotAcceleration(0, 0, 1, 2, 3);
+  sensorManager.GotAcceleration(nullptr, nullptr, 1, 2, 3);
   ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
   ASSERT_EQ(1, motion_buffer_->data.accelerationX);
   ASSERT_TRUE(motion_buffer_->data.hasAccelerationX);
@@ -71,7 +85,7 @@
   ASSERT_EQ(3, motion_buffer_->data.accelerationZ);
   ASSERT_TRUE(motion_buffer_->data.hasAccelerationZ);
 
-  sensorManager.GotAccelerationIncludingGravity(0, 0, 4, 5, 6);
+  sensorManager.GotAccelerationIncludingGravity(nullptr, nullptr, 4, 5, 6);
   ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
   ASSERT_EQ(4, motion_buffer_->data.accelerationIncludingGravityX);
   ASSERT_TRUE(motion_buffer_->data.hasAccelerationIncludingGravityX);
@@ -80,7 +94,7 @@
   ASSERT_EQ(6, motion_buffer_->data.accelerationIncludingGravityZ);
   ASSERT_TRUE(motion_buffer_->data.hasAccelerationIncludingGravityZ);
 
-  sensorManager.GotRotationRate(0, 0, 7, 8, 9);
+  sensorManager.GotRotationRate(nullptr, nullptr, 7, 8, 9);
   ASSERT_TRUE(motion_buffer_->data.allAvailableSensorsAreActive);
   ASSERT_EQ(7, motion_buffer_->data.rotationRateAlpha);
   ASSERT_TRUE(motion_buffer_->data.hasRotationRateAlpha);
@@ -103,10 +117,10 @@
   sensorManager.StartFetchingDeviceMotionData(motion_buffer_.get());
   ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
 
-  sensorManager.GotAcceleration(0, 0, 1, 2, 3);
+  sensorManager.GotAcceleration(nullptr, nullptr, 1, 2, 3);
   ASSERT_FALSE(motion_buffer_->data.allAvailableSensorsAreActive);
 
-  sensorManager.GotAccelerationIncludingGravity(0, 0, 1, 2, 3);
+  sensorManager.GotAccelerationIncludingGravity(nullptr, nullptr, 1, 2, 3);
   ASSERT_TRUE(motion_buffer_->data.allAvailableSensorsAreActive);
   ASSERT_EQ(kInertialSensorIntervalMicroseconds / 1000.,
             motion_buffer_->data.interval);
@@ -136,14 +150,23 @@
   sensorManager.StartFetchingDeviceOrientationData(orientation_buffer_.get());
   ASSERT_FALSE(orientation_buffer_->data.allAvailableSensorsAreActive);
 
-  sensorManager.GotOrientation(0, 0, 1, 2, 3);
-  ASSERT_TRUE(orientation_buffer_->data.allAvailableSensorsAreActive);
-  ASSERT_EQ(1, orientation_buffer_->data.alpha);
-  ASSERT_TRUE(orientation_buffer_->data.hasAlpha);
-  ASSERT_EQ(2, orientation_buffer_->data.beta);
-  ASSERT_TRUE(orientation_buffer_->data.hasBeta);
-  ASSERT_EQ(3, orientation_buffer_->data.gamma);
-  ASSERT_TRUE(orientation_buffer_->data.hasGamma);
+  sensorManager.GotOrientation(nullptr, nullptr, 1, 2, 3);
+  VerifyOrientationBufferValues(orientation_buffer_.get(), 1, 2, 3);
+
+  sensorManager.StopFetchingDeviceOrientationData();
+  ASSERT_FALSE(orientation_buffer_->data.allAvailableSensorsAreActive);
+}
+
+TEST_F(AndroidSensorManagerTest, DeviceOrientationAbsoluteSensorsActive) {
+  FakeSensorManagerAndroid::Register(base::android::AttachCurrentThread());
+  FakeSensorManagerAndroid sensorManager;
+
+  sensorManager.StartFetchingDeviceOrientationAbsoluteData(
+      orientation_absolute_buffer_.get());
+  ASSERT_FALSE(orientation_buffer_->data.allAvailableSensorsAreActive);
+
+  sensorManager.GotOrientationAbsolute(nullptr, nullptr, 4, 5, 6);
+  VerifyOrientationBufferValues(orientation_absolute_buffer_.get(), 4, 5, 6);
 
   sensorManager.StopFetchingDeviceOrientationData();
   ASSERT_FALSE(orientation_buffer_->data.allAvailableSensorsAreActive);
@@ -156,7 +179,7 @@
 
   sensorManager.StartFetchingDeviceLightData(light_buffer_.get());
 
-  sensorManager.GotLight(0, 0, 100);
+  sensorManager.GotLight(nullptr, nullptr, 100);
   ASSERT_EQ(100, light_buffer_->data.value);
 
   sensorManager.StopFetchingDeviceLightData();
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index d7c3423..d045571 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -31,7 +31,10 @@
                                                     tethering_task_runner)),
       tracing_handler_(new devtools::tracing::TracingHandler(
           devtools::tracing::TracingHandler::Browser, GetIOContext())),
-      protocol_handler_(new DevToolsProtocolHandler(this)) {
+      protocol_handler_(new DevToolsProtocolHandler(
+          this,
+          base::Bind(&BrowserDevToolsAgentHost::SendMessageToClient,
+                     base::Unretained(this)))) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetIOHandler(io_handler_.get());
   dispatcher->SetMemoryHandler(memory_handler_.get());
@@ -71,7 +74,7 @@
 
 bool BrowserDevToolsAgentHost::DispatchProtocolMessage(
     const std::string& message) {
-  protocol_handler_->HandleMessage(session_id(), message);
+  protocol_handler_->HandleMessage(message);
   return true;
 }
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 28318e0..4d93551 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -76,7 +76,8 @@
 }
 
 DevToolsAgentHostImpl::DevToolsAgentHostImpl()
-    : id_(base::GenerateGUID()), session_id_(0), client_(NULL) {
+    : id_(base::GenerateGUID()),
+      client_(NULL) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   g_instances.Get()[id_] = this;
 }
@@ -105,7 +106,6 @@
 
 void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
-  ++session_id_;
   if (client_) {
     client_->AgentHostClosed(this, true);
     InnerDetach();
@@ -153,16 +153,6 @@
 void DevToolsAgentHostImpl::ConnectWebContents(WebContents* wc) {
 }
 
-void DevToolsAgentHostImpl::SendProtocolResponse(int session_id,
-                                                 const std::string& message) {
-  SendMessageToClient(session_id, message);
-}
-
-void DevToolsAgentHostImpl::SendProtocolNotification(
-    const std::string& message) {
-  SendMessageToClient(session_id(), message);
-}
-
 void DevToolsAgentHostImpl::HostClosed() {
   if (!client_)
     return;
@@ -174,13 +164,9 @@
   client->AgentHostClosed(this, false);
 }
 
-void DevToolsAgentHostImpl::SendMessageToClient(int session_id,
-                                                const std::string& message) {
+void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) {
   if (!client_)
     return;
-  // Filter any messages from previous sessions.
-  if (session_id != session_id_)
-    return;
   client_->DispatchProtocolMessage(this, message);
 }
 
@@ -263,7 +249,7 @@
 
   if (chunk.is_first && chunk.is_last) {
     CHECK(message_buffer_size_ == 0);
-    callback_.Run(chunk.session_id, chunk.data);
+    callback_.Run(chunk.data);
     return;
   }
 
@@ -279,7 +265,7 @@
 
   if (chunk.is_last) {
     CHECK(message_buffer_.size() == message_buffer_size_);
-    callback_.Run(chunk.session_id, message_buffer_);
+    callback_.Run(message_buffer_);
     message_buffer_ = std::string();
     message_buffer_size_ = 0;
   }
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 3d27cd7..8474c0a 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -9,7 +9,6 @@
 
 #include "base/compiler_specific.h"
 #include "content/browser/devtools/devtools_io_context.h"
-#include "content/browser/devtools/protocol/devtools_protocol_delegate.h"
 #include "content/common/content_export.h"
 #include "content/common/devtools_messages.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -23,8 +22,7 @@
 class BrowserContext;
 
 // Describes interface for managing devtools agents from the browser process.
-class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost,
-                                             public DevToolsProtocolDelegate {
+class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
  public:
   // Informs the hosted agent that a client host has attached.
   virtual void Attach() = 0;
@@ -46,21 +44,14 @@
   void DisconnectWebContents() override;
   void ConnectWebContents(WebContents* wc) override;
 
-  // DevToolsProtocolDelegate implementation.
-  void SendProtocolResponse(int session_id,
-                            const std::string& message) override;
-  void SendProtocolNotification(const std::string& message) override;
-
  protected:
   DevToolsAgentHostImpl();
   ~DevToolsAgentHostImpl() override;
 
   void HostClosed();
-  void SendMessageToClient(int session_id, const std::string& message);
+  void SendMessageToClient(const std::string& message);
   devtools::DevToolsIOContext* GetIOContext() { return &io_context_; }
 
-  int session_id() { return session_id_; }
-
   static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached);
 
  private:
@@ -68,14 +59,13 @@
   void InnerDetach();
 
   const std::string id_;
-  int session_id_;
   DevToolsAgentHostClient* client_;
   devtools::DevToolsIOContext io_context_;
 };
 
 class DevToolsMessageChunkProcessor {
  public:
-  using SendMessageCallback = base::Callback<void(int, const std::string&)>;
+  using SendMessageCallback = base::Callback<void(const std::string&)>;
   explicit DevToolsMessageChunkProcessor(const SendMessageCallback& callback);
   ~DevToolsMessageChunkProcessor();
 
diff --git a/content/browser/devtools/devtools_protocol_handler.cc b/content/browser/devtools/devtools_protocol_handler.cc
index 9f69cfb..86ccd8e 100644
--- a/content/browser/devtools/devtools_protocol_handler.cc
+++ b/content/browser/devtools/devtools_protocol_handler.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_manager.h"
 #include "content/public/browser/devtools_manager_delegate.h"
 
@@ -37,35 +36,35 @@
 }  // namespace
 
 DevToolsProtocolHandler::DevToolsProtocolHandler(
-    DevToolsAgentHostImpl* agent_host)
-    : agent_host_(agent_host), client_(agent_host), dispatcher_(agent_host) {}
+    DevToolsAgentHost* agent_host, const Notifier& notifier)
+    : agent_host_(agent_host),
+      client_(notifier),
+      dispatcher_(notifier) {
+}
 
 DevToolsProtocolHandler::~DevToolsProtocolHandler() {
 }
 
-void DevToolsProtocolHandler::HandleMessage(int session_id,
-                                            const std::string& message) {
-  scoped_ptr<base::DictionaryValue> command = ParseCommand(session_id, message);
+void DevToolsProtocolHandler::HandleMessage(const std::string& message) {
+  scoped_ptr<base::DictionaryValue> command = ParseCommand(message);
   if (!command)
     return;
-  if (PassCommandToDelegate(session_id, command.get()))
+  if (PassCommandToDelegate(command.get()))
     return;
-  HandleCommand(session_id, command.Pass());
+  HandleCommand(command.Pass());
 }
 
-bool DevToolsProtocolHandler::HandleOptionalMessage(int session_id,
-                                                    const std::string& message,
-                                                    int* call_id) {
-  scoped_ptr<base::DictionaryValue> command = ParseCommand(session_id, message);
+bool DevToolsProtocolHandler::HandleOptionalMessage(
+    const std::string& message, int* call_id) {
+  scoped_ptr<base::DictionaryValue> command = ParseCommand(message);
   if (!command)
     return true;
-  if (PassCommandToDelegate(session_id, command.get()))
+  if (PassCommandToDelegate(command.get()))
     return true;
-  return HandleOptionalCommand(session_id, command.Pass(), call_id);
+  return HandleOptionalCommand(command.Pass(), call_id);
 }
 
 bool DevToolsProtocolHandler::PassCommandToDelegate(
-    int session_id,
     base::DictionaryValue* command) {
   DevToolsManagerDelegate* delegate =
       DevToolsManager::GetInstance()->delegate();
@@ -75,41 +74,41 @@
   scoped_ptr<base::DictionaryValue> response(
       delegate->HandleCommand(agent_host_, command));
   if (response) {
-    client_.SendMessage(session_id, *response);
+    std::string json_response;
+    base::JSONWriter::Write(*response, &json_response);
+    client_.SendRawMessage(json_response);
     return true;
   }
 
   return false;
 }
 
-scoped_ptr<base::DictionaryValue> DevToolsProtocolHandler::ParseCommand(
-    int session_id,
-    const std::string& message) {
+scoped_ptr<base::DictionaryValue>
+DevToolsProtocolHandler::ParseCommand(const std::string& message) {
   scoped_ptr<base::Value> value = base::JSONReader::Read(message);
   if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
-    client_.SendError(
-        DevToolsCommandId(DevToolsCommandId::kNoId, session_id),
-        Response(kStatusParseError, "Message must be in JSON format"));
+    client_.SendError(DevToolsProtocolClient::kNoId,
+                      Response(kStatusParseError,
+                               "Message must be in JSON format"));
     return nullptr;
   }
 
   scoped_ptr<base::DictionaryValue> command =
       make_scoped_ptr(static_cast<base::DictionaryValue*>(value.release()));
-  int call_id = DevToolsCommandId::kNoId;
-  bool ok = command->GetInteger(kIdParam, &call_id) && call_id >= 0;
+  int id = DevToolsProtocolClient::kNoId;
+  bool ok = command->GetInteger(kIdParam, &id) && id >= 0;
   if (!ok) {
-    client_.SendError(DevToolsCommandId(call_id, session_id),
-                      Response(kStatusInvalidRequest,
-                               "The type of 'id' property must be number"));
+    client_.SendError(id, Response(kStatusInvalidRequest,
+                                   "The type of 'id' property must be number"));
     return nullptr;
   }
 
   std::string method;
   ok = command->GetString(kMethodParam, &method);
   if (!ok) {
-    client_.SendError(DevToolsCommandId(call_id, session_id),
-                      Response(kStatusInvalidRequest,
-                               "The type of 'method' property must be string"));
+    client_.SendError(id,
+        Response(kStatusInvalidRequest,
+                 "The type of 'method' property must be string"));
     return nullptr;
   }
 
@@ -117,39 +116,34 @@
 }
 
 void DevToolsProtocolHandler::HandleCommand(
-    int session_id,
     scoped_ptr<base::DictionaryValue> command) {
-  int call_id = DevToolsCommandId::kNoId;
+  int id = DevToolsProtocolClient::kNoId;
   std::string method;
-  command->GetInteger(kIdParam, &call_id);
+  command->GetInteger(kIdParam, &id);
   command->GetString(kMethodParam, &method);
   DevToolsProtocolDispatcher::CommandHandler command_handler(
       dispatcher_.FindCommandHandler(method));
   if (command_handler.is_null()) {
-    client_.SendError(DevToolsCommandId(call_id, session_id),
-                      Response(kStatusNoSuchMethod, "No such method"));
+    client_.SendError(id, Response(kStatusNoSuchMethod, "No such method"));
     return;
   }
 
   bool result =
-      command_handler.Run(DevToolsCommandId(call_id, session_id),
-                          TakeDictionary(command.get(), kParamsParam));
+      command_handler.Run(id, TakeDictionary(command.get(), kParamsParam));
   DCHECK(result);
 }
 
 bool DevToolsProtocolHandler::HandleOptionalCommand(
-    int session_id,
-    scoped_ptr<base::DictionaryValue> command,
-    int* call_id) {
-  *call_id = DevToolsCommandId::kNoId;
+    scoped_ptr<base::DictionaryValue> command, int* call_id) {
+  *call_id = DevToolsProtocolClient::kNoId;
   std::string method;
   command->GetInteger(kIdParam, call_id);
   command->GetString(kMethodParam, &method);
   DevToolsProtocolDispatcher::CommandHandler command_handler(
       dispatcher_.FindCommandHandler(method));
   if (!command_handler.is_null()) {
-    return command_handler.Run(DevToolsCommandId(*call_id, session_id),
-                               TakeDictionary(command.get(), kParamsParam));
+    return command_handler.Run(
+        *call_id, TakeDictionary(command.get(), kParamsParam));
   }
   return false;
 }
diff --git a/content/browser/devtools/devtools_protocol_handler.h b/content/browser/devtools/devtools_protocol_handler.h
index 32f4928..299b342 100644
--- a/content/browser/devtools/devtools_protocol_handler.h
+++ b/content/browser/devtools/devtools_protocol_handler.h
@@ -10,30 +10,26 @@
 namespace content {
 
 class DevToolsAgentHost;
-class DevToolsAgentHostImpl;
-class DevToolsProtocolDelegate;
 
 class DevToolsProtocolHandler {
  public:
   using Response = DevToolsProtocolClient::Response;
+  using Notifier = base::Callback<void(const std::string& message)>;
 
-  explicit DevToolsProtocolHandler(DevToolsAgentHostImpl* agent_host);
+  DevToolsProtocolHandler(DevToolsAgentHost* agent_host,
+                          const Notifier& notifier);
   virtual ~DevToolsProtocolHandler();
 
-  void HandleMessage(int session_id, const std::string& message);
-  bool HandleOptionalMessage(int session_id,
-                             const std::string& message,
-                             int* call_id);
+  void HandleMessage(const std::string& message);
+  bool HandleOptionalMessage(const std::string& message, int* call_id);
 
   DevToolsProtocolDispatcher* dispatcher() { return &dispatcher_; }
 
  private:
-  scoped_ptr<base::DictionaryValue> ParseCommand(int session_id,
-                                                 const std::string& message);
-  bool PassCommandToDelegate(int session_id, base::DictionaryValue* command);
-  void HandleCommand(int session_id, scoped_ptr<base::DictionaryValue> command);
-  bool HandleOptionalCommand(int session_id,
-                             scoped_ptr<base::DictionaryValue> command,
+  scoped_ptr<base::DictionaryValue> ParseCommand(const std::string& message);
+  bool PassCommandToDelegate(base::DictionaryValue* command);
+  void HandleCommand(scoped_ptr<base::DictionaryValue> command);
+  bool HandleOptionalCommand(scoped_ptr<base::DictionaryValue> command,
                              int* call_id);
 
   DevToolsAgentHost* agent_host_;
diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc
index b8b8c2f8..ef7f82c 100644
--- a/content/browser/devtools/forwarding_agent_host.cc
+++ b/content/browser/devtools/forwarding_agent_host.cc
@@ -18,7 +18,7 @@
 }
 
 void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) {
-  SendMessageToClient(session_id(), message);
+  SendMessageToClient(message);
 }
 
 void ForwardingAgentHost::ConnectionClosed() {
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.cc b/content/browser/devtools/protocol/devtools_protocol_client.cc
index 9ca03f9d..4b7c25d 100644
--- a/content/browser/devtools/protocol/devtools_protocol_client.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_client.cc
@@ -6,7 +6,6 @@
 
 #include "base/json/json_writer.h"
 #include "base/strings/stringprintf.h"
-#include "content/browser/devtools/protocol/devtools_protocol_delegate.h"
 
 namespace content {
 
@@ -31,24 +30,24 @@
 }  // namespace
 
 // static
-const int DevToolsCommandId::kNoId = -1;
+const DevToolsCommandId DevToolsProtocolClient::kNoId = -1;
 
 DevToolsProtocolClient::DevToolsProtocolClient(
-    DevToolsProtocolDelegate* notifier)
-    : notifier_(notifier) {}
+    const RawMessageCallback& raw_message_callback)
+    : raw_message_callback_(raw_message_callback) {
+}
 
 DevToolsProtocolClient::~DevToolsProtocolClient() {
 }
 
-void DevToolsProtocolClient::SendRawNotification(const std::string& message) {
-  notifier_->SendProtocolNotification(message);
+void DevToolsProtocolClient::SendRawMessage(const std::string& message) {
+  raw_message_callback_.Run(message);
 }
 
-void DevToolsProtocolClient::SendMessage(int session_id,
-                                         const base::DictionaryValue& message) {
+void DevToolsProtocolClient::SendMessage(const base::DictionaryValue& message) {
   std::string json_message;
   base::JSONWriter::Write(message, &json_message);
-  notifier_->SendProtocolResponse(session_id, json_message);
+  SendRawMessage(json_message);
 }
 
 void DevToolsProtocolClient::SendNotification(
@@ -59,21 +58,19 @@
   if (params)
     notification.Set(kParamsParam, params.release());
 
-  std::string json_message;
-  base::JSONWriter::Write(notification, &json_message);
-  SendRawNotification(json_message);
+  SendMessage(notification);
 }
 
 void DevToolsProtocolClient::SendSuccess(
     DevToolsCommandId command_id,
     scoped_ptr<base::DictionaryValue> params) {
   base::DictionaryValue response;
-  response.SetInteger(kIdParam, command_id.call_id);
+  response.SetInteger(kIdParam, command_id);
 
   response.Set(kResultParam,
       params ? params.release() : new base::DictionaryValue());
 
-  SendMessage(command_id.session_id, response);
+  SendMessage(response);
 }
 
 bool DevToolsProtocolClient::SendError(DevToolsCommandId command_id,
@@ -83,10 +80,10 @@
     return false;
   }
   base::DictionaryValue dict;
-  if (command_id.call_id == DevToolsCommandId::kNoId)
+  if (command_id == kNoId)
     dict.Set(kIdParam, base::Value::CreateNullValue());
   else
-    dict.SetInteger(kIdParam, command_id.call_id);
+    dict.SetInteger(kIdParam, command_id);
 
   base::DictionaryValue* error_object = new base::DictionaryValue();
   error_object->SetInteger(kErrorCodeParam, response.status());
@@ -94,7 +91,7 @@
     error_object->SetString(kErrorMessageParam, response.message());
 
   dict.Set(kErrorParam, error_object);
-  SendMessage(command_id.session_id, dict);
+  SendMessage(dict);
   return true;
 }
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_client.h b/content/browser/devtools/protocol/devtools_protocol_client.h
index 780bc74..9297187 100644
--- a/content/browser/devtools/protocol/devtools_protocol_client.h
+++ b/content/browser/devtools/protocol/devtools_protocol_client.h
@@ -10,22 +10,16 @@
 
 namespace content {
 
-struct DevToolsCommandId {
-  static const int kNoId;
-
-  DevToolsCommandId(int call_id, int session_id)
-      : call_id(call_id), session_id(session_id) {}
-
-  int call_id;
-  int session_id;
-};
-
-class DevToolsProtocolDelegate;
-class DevToolsProtocolDispatcher;
+using DevToolsCommandId = int;
 class DevToolsProtocolHandler;
+class DevToolsProtocolDispatcher;
 
 class DevToolsProtocolClient {
  public:
+  typedef base::Callback<void(const std::string& message)>
+      RawMessageCallback;
+  static const DevToolsCommandId kNoId;
+
   struct Response {
    public:
     static Response FallThrough();
@@ -52,13 +46,12 @@
   bool SendError(DevToolsCommandId command_id,
                  const Response& response);
 
-  // Sends notification to client, the caller is presumed to properly
+  // Sends message to client, the caller is presumed to properly
   // format the message. Do not use unless you must.
-  void SendRawNotification(const std::string& message);
+  void SendRawMessage(const std::string& message);
 
-  void SendMessage(int session_id, const base::DictionaryValue& message);
-
-  explicit DevToolsProtocolClient(DevToolsProtocolDelegate* notifier);
+  explicit DevToolsProtocolClient(
+      const RawMessageCallback& raw_message_callback);
   virtual ~DevToolsProtocolClient();
 
  protected:
@@ -70,7 +63,9 @@
  private:
   friend class DevToolsProtocolDispatcher;
 
-  DevToolsProtocolDelegate* notifier_;
+  void SendMessage(const base::DictionaryValue& message);
+
+  RawMessageCallback raw_message_callback_;
   DISALLOW_COPY_AND_ASSIGN(DevToolsProtocolClient);
 };
 
diff --git a/content/browser/devtools/protocol/devtools_protocol_delegate.h b/content/browser/devtools/protocol/devtools_protocol_delegate.h
deleted file mode 100644
index 20c476bd..0000000
--- a/content/browser/devtools/protocol/devtools_protocol_delegate.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
-#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
-
-#include "content/common/content_export.h"
-
-namespace content {
-
-class CONTENT_EXPORT DevToolsProtocolDelegate {
-public:
-  virtual ~DevToolsProtocolDelegate(){}
-  virtual void SendProtocolResponse(int session_id,
-                                    const std::string& message) = 0;
-  virtual void SendProtocolNotification(const std::string& message) = 0;
-};
-
-} // content
-
-#endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_PROTOCOL_DELEGATE_H_
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
index 6377be6f..6bce71e 100755
--- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
+++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -74,11 +74,11 @@
 
 class DevToolsProtocolDispatcher {
  public:
+  using Notifier = DevToolsProtocolClient::RawMessageCallback;
   using CommandHandler =
-      base::Callback<bool(DevToolsCommandId,
-                          scoped_ptr<base::DictionaryValue>)>;
+      base::Callback<bool(int, scoped_ptr<base::DictionaryValue>)>;
 
-  explicit DevToolsProtocolDispatcher(DevToolsProtocolDelegate* notifier);
+  explicit DevToolsProtocolDispatcher(const Notifier& notifier);
   ~DevToolsProtocolDispatcher();
 
   CommandHandler FindCommandHandler(const std::string& method);
@@ -91,7 +91,7 @@
 
 ${methods}\
 
-  DevToolsProtocolDelegate* notifier_;
+  Notifier notifier_;
   DevToolsProtocolClient client_;
   CommandHandlers command_handlers_;
 ${fields}\
@@ -208,7 +208,7 @@
 namespace ${domain} {
 class Client : public DevToolsProtocolClient {
  public:
-  explicit Client(DevToolsProtocolDelegate* notifier);
+  explicit Client(const RawMessageCallback& raw_message_callback);
   ~Client() override;
 
 ${methods}\
@@ -252,7 +252,7 @@
 namespace content {
 
 DevToolsProtocolDispatcher::DevToolsProtocolDispatcher(
-    DevToolsProtocolDelegate* notifier)
+    const Notifier& notifier)
     : notifier_(notifier),
       client_(notifier),
       ${fields_init} {
@@ -405,8 +405,8 @@
 tmpl_client_impl = string.Template("""\
 namespace ${domain} {
 
-Client::Client(DevToolsProtocolDelegate* notifier)
-    : DevToolsProtocolClient(notifier) {
+Client::Client(const RawMessageCallback& raw_message_callback)
+    : DevToolsProtocolClient(raw_message_callback) {
 }
 
 Client::~Client() {
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index cae9f00..9659991 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -35,11 +35,19 @@
   return result;
 }
 
+// When continuously applying device emulation, we wait for compositor frame
+// before applying new values. If the frame does not arrive during this
+// timeout, we proceed anyway.
+const int kFrameTimeoutMs = 67;
+
 }  // namespace
 
 EmulationHandler::EmulationHandler(page::PageHandler* page_handler)
     : touch_emulation_enabled_(false),
       device_emulation_enabled_(false),
+      device_emulation_needs_update_(false),
+      device_emulation_waiting_for_frame_(false),
+      frame_timer_(new base::Timer(false, false)),
       page_handler_(page_handler),
       host_(nullptr)
 {
@@ -59,14 +67,14 @@
 
   host_ = host;
   UpdateTouchEventEmulationState();
-  UpdateDeviceEmulationState();
+  ApplyDeviceEmulationState();
 }
 
 void EmulationHandler::Detached() {
   touch_emulation_enabled_ = false;
   device_emulation_enabled_ = false;
   UpdateTouchEventEmulationState();
-  UpdateDeviceEmulationState();
+  ApplyDeviceEmulationState();
 }
 
 Response EmulationHandler::SetGeolocationOverride(
@@ -192,7 +200,7 @@
 
   device_emulation_enabled_ = true;
   device_emulation_params_ = params;
-  UpdateDeviceEmulationState();
+  DeviceEmulationNeedsUpdate();
   return Response::OK();
 }
 
@@ -201,7 +209,7 @@
     return Response::OK();
 
   device_emulation_enabled_ = false;
-  UpdateDeviceEmulationState();
+  DeviceEmulationNeedsUpdate();
   return Response::OK();
 }
 
@@ -225,11 +233,31 @@
     GetWebContents()->SetForceDisableOverscrollContent(enabled);
 }
 
-void EmulationHandler::UpdateDeviceEmulationState() {
+void EmulationHandler::DeviceEmulationNeedsUpdate() {
+  device_emulation_needs_update_ = true;
+  if (!device_emulation_waiting_for_frame_)
+    ApplyDeviceEmulationState();
+}
+
+void EmulationHandler::OnSwapCompositorFrame() {
+  frame_timer_->Stop();
+  device_emulation_waiting_for_frame_ = false;
+  if (device_emulation_needs_update_)
+    ApplyDeviceEmulationState();
+}
+
+void EmulationHandler::ApplyDeviceEmulationState() {
+  device_emulation_needs_update_ = false;
   RenderWidgetHostImpl* widget_host =
       host_ ? host_->GetRenderWidgetHost() : nullptr;
   if (!widget_host)
     return;
+  device_emulation_waiting_for_frame_ = true;
+  frame_timer_->Start(
+      FROM_HERE,
+      base::TimeDelta::FromMilliseconds(kFrameTimeoutMs),
+      base::Bind(&EmulationHandler::OnSwapCompositorFrame,
+                 base::Unretained(this)));
   if (device_emulation_enabled_) {
     widget_host->Send(new ViewMsg_EnableDeviceEmulation(
         widget_host->GetRoutingID(), device_emulation_params_));
diff --git a/content/browser/devtools/protocol/emulation_handler.h b/content/browser/devtools/protocol/emulation_handler.h
index c2a4bd3..4f1e26f 100644
--- a/content/browser/devtools/protocol/emulation_handler.h
+++ b/content/browser/devtools/protocol/emulation_handler.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
 
+#include "base/timer/timer.h"
 #include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
 #include "content/browser/devtools/protocol/page_handler.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
@@ -32,6 +33,7 @@
 
   void SetRenderFrameHost(RenderFrameHostImpl* host);
   void Detached();
+  void OnSwapCompositorFrame();
 
   Response SetGeolocationOverride(double* latitude,
                                   double* longitude,
@@ -59,13 +61,18 @@
  private:
   WebContentsImpl* GetWebContents();
   void UpdateTouchEventEmulationState();
-  void UpdateDeviceEmulationState();
+
+  void DeviceEmulationNeedsUpdate();
+  void ApplyDeviceEmulationState();
 
   bool touch_emulation_enabled_;
   std::string touch_emulation_configuration_;
 
   bool device_emulation_enabled_;
   blink::WebDeviceEmulationParams device_emulation_params_;
+  bool device_emulation_needs_update_;
+  bool device_emulation_waiting_for_frame_;
+  scoped_ptr<base::Timer> frame_timer_;
 
   page::PageHandler* page_handler_;
   RenderFrameHostImpl* host_;
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index c0def4e4..0b4bdcc3 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -398,8 +398,8 @@
     DevToolsCommandId command_id) {
   if (!interaction_marker_name.empty()) {
     // TODO(alexclarke): Can we move this elsewhere? It doesn't really fit here.
-    TRACE_EVENT_COPY_ASYNC_BEGIN0("benchmark", interaction_marker_name.c_str(),
-                                  command_id.call_id);
+    TRACE_EVENT_COPY_ASYNC_BEGIN0("benchmark",
+                                  interaction_marker_name.c_str(), command_id);
   }
 
   host_->QueueSyntheticGesture(
@@ -417,8 +417,8 @@
     DevToolsCommandId command_id,
     SyntheticGesture::Result result) {
   if (!interaction_marker_name.empty()) {
-    TRACE_EVENT_COPY_ASYNC_END0("benchmark", interaction_marker_name.c_str(),
-                                command_id.call_id);
+    TRACE_EVENT_COPY_ASYNC_END0("benchmark",
+                                interaction_marker_name.c_str(), command_id);
   }
 
   if (repeat_count > 0) {
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 2fd8e4b..24890db 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -113,7 +113,7 @@
   message.reserve(message.size() + trace_fragment.size() + messageSuffixSize);
   message += trace_fragment;
   message += "] } }";
-  client_->SendRawNotification(message);
+  client_->SendRawMessage(message);
 }
 
 void TracingHandler::OnTraceComplete() {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 71ab308..4c5b369b3 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -86,9 +86,7 @@
   void Attach();
   void Reattach(FrameHostHolder* old);
   void Detach();
-  void DispatchProtocolMessage(int session_id,
-                               int call_id,
-                               const std::string& message);
+  void DispatchProtocolMessage(int call_id, const std::string& message);
   void InspectElement(int x, int y);
   void ProcessChunkedMessageFromAgent(const DevToolsMessageChunk& chunk);
   void Suspend();
@@ -97,17 +95,15 @@
  private:
   void GrantPolicy();
   void RevokePolicy();
-  void SendMessageToClient(int session_id, const std::string& message);
+  void SendMessageToClient(const std::string& message);
 
   RenderFrameDevToolsAgentHost* agent_;
   RenderFrameHostImpl* host_;
   bool attached_;
   bool suspended_;
   DevToolsMessageChunkProcessor chunk_processor_;
-  // <session_id, message>
-  std::vector<std::pair<int, std::string>> pending_messages_;
-  // <call_id> -> <session_id, message>
-  std::map<int, std::pair<int, std::string>> sent_messages_;
+  std::vector<std::string> pending_messages_;
+  std::map<int, std::string> sent_messages_;
 };
 
 RenderFrameDevToolsAgentHost::FrameHostHolder::FrameHostHolder(
@@ -130,7 +126,7 @@
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach() {
   host_->Send(new DevToolsAgentMsg_Attach(
-      host_->GetRoutingID(), agent_->GetId(), agent_->session_id()));
+      host_->GetRoutingID(), agent_->GetId()));
   GrantPolicy();
   attached_ = true;
 }
@@ -140,13 +136,10 @@
   if (old)
     chunk_processor_.set_state_cookie(old->chunk_processor_.state_cookie());
   host_->Send(new DevToolsAgentMsg_Reattach(
-      host_->GetRoutingID(), agent_->GetId(), agent_->session_id(),
-      chunk_processor_.state_cookie()));
+      host_->GetRoutingID(), agent_->GetId(), chunk_processor_.state_cookie()));
   if (old) {
-    for (const auto& pair : old->sent_messages_) {
-      DispatchProtocolMessage(pair.second.first, pair.first,
-                              pair.second.second);
-    }
+    for (const auto& pair : old->sent_messages_)
+      DispatchProtocolMessage(pair.first, pair.second);
   }
   GrantPolicy();
   attached_ = true;
@@ -186,18 +179,16 @@
   }
 }
 void RenderFrameDevToolsAgentHost::FrameHostHolder::DispatchProtocolMessage(
-    int session_id,
-    int call_id,
-    const std::string& message) {
+    int call_id, const std::string& message) {
   host_->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-      host_->GetRoutingID(), session_id, message));
-  sent_messages_[call_id] = std::make_pair(session_id, message);
+      host_->GetRoutingID(), message));
+  sent_messages_[call_id] = message;
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::InspectElement(
     int x, int y) {
   host_->Send(new DevToolsAgentMsg_InspectElement(
-      host_->GetRoutingID(), agent_->GetId(), agent_->session_id(), x, y));
+      host_->GetRoutingID(), agent_->GetId(), x, y));
 }
 
 void
@@ -207,13 +198,12 @@
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::SendMessageToClient(
-    int session_id,
     const std::string& message) {
   sent_messages_.erase(chunk_processor_.last_call_id());
   if (suspended_)
-    pending_messages_.push_back(std::make_pair(session_id, message));
+    pending_messages_.push_back(message);
   else
-    agent_->SendMessageToClient(session_id, message);
+    agent_->SendMessageToClient(message);
 }
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Suspend() {
@@ -222,9 +212,9 @@
 
 void RenderFrameDevToolsAgentHost::FrameHostHolder::Resume() {
   suspended_ = false;
-  for (const auto& pair : pending_messages_)
-    agent_->SendMessageToClient(pair.first, pair.second);
-  std::vector<std::pair<int, std::string>> empty;
+  for (const std::string& message : pending_messages_)
+    agent_->SendMessageToClient(message);
+  std::vector<std::string> empty;
   pending_messages_.swap(empty);
 }
 
@@ -335,7 +325,10 @@
           GetIOContext())),
       emulation_handler_(nullptr),
       frame_trace_recorder_(nullptr),
-      protocol_handler_(new DevToolsProtocolHandler(this)),
+      protocol_handler_(new DevToolsProtocolHandler(
+          this,
+          base::Bind(&RenderFrameDevToolsAgentHost::SendMessageToClient,
+                     base::Unretained(this)))),
       current_frame_crashed_(false) {
   DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher();
   dispatcher->SetDOMHandler(dom_handler_.get());
@@ -430,13 +423,13 @@
 bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
     const std::string& message) {
   int call_id = 0;
-  if (protocol_handler_->HandleOptionalMessage(session_id(), message, &call_id))
+  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
     return true;
 
   if (current_)
-    current_->DispatchProtocolMessage(session_id(), call_id, message);
+    current_->DispatchProtocolMessage(call_id, message);
   if (pending_)
-    pending_->DispatchProtocolMessage(session_id(), call_id, message);
+    pending_->DispatchProtocolMessage(call_id, message);
   return true;
 }
 
@@ -723,6 +716,8 @@
     page_handler_->OnSwapCompositorFrame(base::get<1>(param).metadata);
   if (input_handler_)
     input_handler_->OnSwapCompositorFrame(base::get<1>(param).metadata);
+  if (emulation_handler_)
+    emulation_handler_->OnSwapCompositorFrame();
   if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
     frame_trace_recorder_->OnSwapCompositorFrame(
         current_ ? current_->host() : nullptr,
@@ -736,6 +731,8 @@
     page_handler_->OnSynchronousSwapCompositorFrame(frame_metadata);
   if (input_handler_)
     input_handler_->OnSwapCompositorFrame(frame_metadata);
+  if (emulation_handler_)
+    emulation_handler_->OnSwapCompositorFrame();
   if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
     frame_trace_recorder_->OnSynchronousSwapCompositorFrame(
         current_ ? current_->host() : nullptr,
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index d7be60a..32cd668e 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -21,8 +21,7 @@
     AttachToWorker();
   }
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
-    host->Send(
-        new DevToolsAgentMsg_Attach(worker_id_.second, GetId(), session_id()));
+    host->Send(new DevToolsAgentMsg_Attach(worker_id_.second, GetId()));
   OnAttachedStateChanged(true);
   DevToolsAgentHostImpl::NotifyCallbacks(this, true);
 }
@@ -46,12 +45,12 @@
     return true;
 
   int call_id;
-  if (protocol_handler_->HandleOptionalMessage(session_id(), message, &call_id))
+  if (protocol_handler_->HandleOptionalMessage(message, &call_id))
     return true;
 
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
     host->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-        worker_id_.second, session_id(), message));
+        worker_id_.second, message));
   }
   return true;
 }
@@ -84,8 +83,7 @@
     AttachToWorker();
     if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
       host->Send(new DevToolsAgentMsg_Reattach(
-          worker_id_.second, GetId(), session_id(),
-          chunk_processor_.state_cookie()));
+          worker_id_.second, GetId(), chunk_processor_.state_cookie()));
     }
     OnAttachedStateChanged(true);
   }
@@ -103,7 +101,10 @@
   if (state_ == WORKER_INSPECTED) {
     DCHECK(IsAttached());
     // Client host is debugging this worker agent host.
-    devtools::inspector::Client inspector(this);
+    base::Callback<void(const std::string&)> raw_message_callback(
+        base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+                base::Unretained(this)));
+    devtools::inspector::Client inspector(raw_message_callback);
     inspector.TargetCrashed(
         devtools::inspector::TargetCrashedParams::Create());
     DetachFromWorker();
@@ -116,10 +117,15 @@
   return state_ == WORKER_TERMINATED;
 }
 
-WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(WorkerId worker_id)
-    : protocol_handler_(new DevToolsProtocolHandler(this)),
-      chunk_processor_(base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
-                                  base::Unretained(this))),
+WorkerDevToolsAgentHost::WorkerDevToolsAgentHost(
+    WorkerId worker_id)
+    : protocol_handler_(new DevToolsProtocolHandler(
+          this,
+          base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+                     base::Unretained(this)))),
+      chunk_processor_(
+          base::Bind(&WorkerDevToolsAgentHost::SendMessageToClient,
+                     base::Unretained(this))),
       state_(WORKER_UNINSPECTED),
       worker_id_(worker_id) {
   WorkerCreated();
diff --git a/content/browser/download/download_stats.cc b/content/browser/download/download_stats.cc
index b7ddeea..3f7d692 100644
--- a/content/browser/download/download_stats.cc
+++ b/content/browser/download/download_stats.cc
@@ -231,6 +231,94 @@
   FILE_PATH_LITERAL(".u3p"),
   FILE_PATH_LITERAL(".vbscript"),
   FILE_PATH_LITERAL(".workflow"),
+  FILE_PATH_LITERAL(".001"),
+  FILE_PATH_LITERAL(".7z"),
+  FILE_PATH_LITERAL(".ace"),
+  FILE_PATH_LITERAL(".arc"),
+  FILE_PATH_LITERAL(".arj"),
+  FILE_PATH_LITERAL(".b64"),
+  FILE_PATH_LITERAL(".balz"),
+  FILE_PATH_LITERAL(".bhx"),
+  FILE_PATH_LITERAL(".bz"),
+  FILE_PATH_LITERAL(".bz2"),
+  FILE_PATH_LITERAL(".bzip2"),
+  FILE_PATH_LITERAL(".cab"),
+  FILE_PATH_LITERAL(".cpio"),
+  FILE_PATH_LITERAL(".fat"),
+  FILE_PATH_LITERAL(".gz"),
+  FILE_PATH_LITERAL(".gzip"),
+  FILE_PATH_LITERAL(".hfs"),
+  FILE_PATH_LITERAL(".hqx"),
+  FILE_PATH_LITERAL(".iso"),
+  FILE_PATH_LITERAL(".lha"),
+  FILE_PATH_LITERAL(".lpaq1"),
+  FILE_PATH_LITERAL(".lpaq5"),
+  FILE_PATH_LITERAL(".lpaq8"),
+  FILE_PATH_LITERAL(".lzh"),
+  FILE_PATH_LITERAL(".lzma"),
+  FILE_PATH_LITERAL(".mim"),
+  FILE_PATH_LITERAL(".ntfs"),
+  FILE_PATH_LITERAL(".paq8f"),
+  FILE_PATH_LITERAL(".paq8jd"),
+  FILE_PATH_LITERAL(".paq8l"),
+  FILE_PATH_LITERAL(".paq8o"),
+  FILE_PATH_LITERAL(".pea"),
+  FILE_PATH_LITERAL(".quad"),
+  FILE_PATH_LITERAL(".r00"),
+  FILE_PATH_LITERAL(".r01"),
+  FILE_PATH_LITERAL(".r02"),
+  FILE_PATH_LITERAL(".r03"),
+  FILE_PATH_LITERAL(".r04"),
+  FILE_PATH_LITERAL(".r05"),
+  FILE_PATH_LITERAL(".r06"),
+  FILE_PATH_LITERAL(".r07"),
+  FILE_PATH_LITERAL(".r08"),
+  FILE_PATH_LITERAL(".r09"),
+  FILE_PATH_LITERAL(".r10"),
+  FILE_PATH_LITERAL(".r11"),
+  FILE_PATH_LITERAL(".r12"),
+  FILE_PATH_LITERAL(".r13"),
+  FILE_PATH_LITERAL(".r14"),
+  FILE_PATH_LITERAL(".r15"),
+  FILE_PATH_LITERAL(".r16"),
+  FILE_PATH_LITERAL(".r17"),
+  FILE_PATH_LITERAL(".r18"),
+  FILE_PATH_LITERAL(".r19"),
+  FILE_PATH_LITERAL(".r20"),
+  FILE_PATH_LITERAL(".r21"),
+  FILE_PATH_LITERAL(".r22"),
+  FILE_PATH_LITERAL(".r23"),
+  FILE_PATH_LITERAL(".r24"),
+  FILE_PATH_LITERAL(".r25"),
+  FILE_PATH_LITERAL(".r26"),
+  FILE_PATH_LITERAL(".r27"),
+  FILE_PATH_LITERAL(".r28"),
+  FILE_PATH_LITERAL(".r29"),
+  FILE_PATH_LITERAL(".rar"),
+  FILE_PATH_LITERAL(".squashfs"),
+  FILE_PATH_LITERAL(".swm"),
+  FILE_PATH_LITERAL(".tar"),
+  FILE_PATH_LITERAL(".taz"),
+  FILE_PATH_LITERAL(".tbz"),
+  FILE_PATH_LITERAL(".tbz2"),
+  FILE_PATH_LITERAL(".tgz"),
+  FILE_PATH_LITERAL(".tpz"),
+  FILE_PATH_LITERAL(".txz"),
+  FILE_PATH_LITERAL(".tz"),
+  FILE_PATH_LITERAL(".udf"),
+  FILE_PATH_LITERAL(".uu"),
+  FILE_PATH_LITERAL(".uue"),
+  FILE_PATH_LITERAL(".vhd"),
+  FILE_PATH_LITERAL(".vmdk"),
+  FILE_PATH_LITERAL(".wim"),
+  FILE_PATH_LITERAL(".wrc"),
+  FILE_PATH_LITERAL(".xar"),
+  FILE_PATH_LITERAL(".xxe"),
+  FILE_PATH_LITERAL(".xz"),
+  FILE_PATH_LITERAL(".z"),
+  FILE_PATH_LITERAL(".zip"),
+  FILE_PATH_LITERAL(".zipx"),
+  FILE_PATH_LITERAL(".zpaq"),
 };
 
 // Maps extensions to their matching UMA histogram int value.
diff --git a/content/browser/net/view_http_cache_job_factory.cc b/content/browser/net/view_http_cache_job_factory.cc
index 41e7b377..823ced9c 100644
--- a/content/browser/net/view_http_cache_job_factory.cc
+++ b/content/browser/net/view_http_cache_job_factory.cc
@@ -10,6 +10,7 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/memory/weak_ptr.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_util.h"
 #include "base/thread_task_runner_handle.h"
@@ -44,8 +45,15 @@
   bool GetCharset(std::string* charset) override {
     return core_->GetCharset(charset);
   }
-  bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read) override {
-    return core_->ReadRawData(buf, buf_size, bytes_read);
+  bool ReadRawData(net::IOBuffer* buf,
+                   int buf_size,
+                   int* out_bytes_read) override {
+    size_t bytes_read;
+    if (!core_->ReadRawData(buf, base::checked_cast<size_t>(buf_size),
+                            &bytes_read))
+      return false;
+    *out_bytes_read = base::checked_cast<int>(bytes_read);
+    return true;
   }
 
  private:
@@ -65,7 +73,7 @@
 
     bool GetMimeType(std::string* mime_type) const;
     bool GetCharset(std::string* charset);
-    bool ReadRawData(net::IOBuffer* buf, int buf_size, int* bytes_read);
+    bool ReadRawData(net::IOBuffer* buf, size_t buf_size, size_t* bytes_read);
 
    private:
     friend class base::RefCounted<Core>;
@@ -76,7 +84,7 @@
     void OnIOComplete(int result);
 
     std::string data_;
-    int data_offset_;
+    size_t data_offset_;
     net::ViewCacheHelper cache_helper_;
     net::CompletionCallback callback_;
     base::Closure user_callback_;
@@ -165,10 +173,11 @@
 }
 
 bool ViewHttpCacheJob::Core::ReadRawData(net::IOBuffer* buf,
-                                         int buf_size,
-                                         int* bytes_read) {
+                                         size_t buf_size,
+                                         size_t* bytes_read) {
   DCHECK(bytes_read);
-  int remaining = static_cast<int>(data_.size()) - data_offset_;
+  DCHECK_LE(data_offset_, data_.size());
+  size_t remaining = data_.size() - data_offset_;
   if (buf_size > remaining)
     buf_size = remaining;
   memcpy(buf->data(), data_.data() + data_offset_, buf_size);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index b295f43..bb9f32a 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -3649,8 +3649,16 @@
 // delay the SwapOut ACK from the A->B navigation, so that the second B->A
 // navigation is initiated before the first page receives the SwapOut ACK.
 // Ensure that the RVH(A) that's pending deletion is not reused in that case.
+// crbug.com/554825
+#if defined(THREAD_SANITIZER)
+#define MAYBE_RenderViewHostPendingDeletionIsNotReused \
+        DISABLED_RenderViewHostPendingDeletionIsNotReused
+#else
+#define MAYBE_RenderViewHostPendingDeletionIsNotReused \
+        RenderViewHostPendingDeletionIsNotReused
+#endif
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       RenderViewHostPendingDeletionIsNotReused) {
+                       MAYBE_RenderViewHostPendingDeletionIsNotReused) {
   GURL a_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
   NavigateToURL(shell(), a_url);
 
diff --git a/content/child/shared_worker_devtools_agent.cc b/content/child/shared_worker_devtools_agent.cc
index 9b1996f..26a51ed 100644
--- a/content/child/shared_worker_devtools_agent.cc
+++ b/content/child/shared_worker_devtools_agent.cc
@@ -44,7 +44,6 @@
 }
 
 void SharedWorkerDevToolsAgent::SendDevToolsMessage(
-    int session_id,
     int call_id,
     const blink::WebString& msg,
     const blink::WebString& state) {
@@ -56,7 +55,6 @@
 
   if (message.length() < kMaxMessageChunkSize) {
     chunk.data.swap(message);
-    chunk.session_id = session_id;
     chunk.call_id = call_id;
     chunk.post_state = post_state;
     chunk.is_last = true;
@@ -67,7 +65,6 @@
 
   for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
     chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
-    chunk.session_id = chunk.is_last ? session_id : 0;
     chunk.call_id = chunk.is_last ? call_id : 0;
     chunk.post_state = chunk.is_last ? post_state : std::string();
     chunk.data = message.substr(pos, kMaxMessageChunkSize);
@@ -78,15 +75,13 @@
   }
 }
 
-void SharedWorkerDevToolsAgent::OnAttach(const std::string& host_id,
-                                         int session_id) {
-  webworker_->attachDevTools(WebString::fromUTF8(host_id), session_id);
+void SharedWorkerDevToolsAgent::OnAttach(const std::string& host_id) {
+  webworker_->attachDevTools(WebString::fromUTF8(host_id));
 }
 
 void SharedWorkerDevToolsAgent::OnReattach(const std::string& host_id,
-                                           int session_id,
                                            const std::string& state) {
-  webworker_->reattachDevTools(WebString::fromUTF8(host_id), session_id,
+  webworker_->reattachDevTools(WebString::fromUTF8(host_id),
                                WebString::fromUTF8(state));
 }
 
@@ -95,9 +90,8 @@
 }
 
 void SharedWorkerDevToolsAgent::OnDispatchOnInspectorBackend(
-    int session_id,
     const std::string& message) {
-  webworker_->dispatchDevToolsMessage(session_id, WebString::fromUTF8(message));
+  webworker_->dispatchDevToolsMessage(WebString::fromUTF8(message));
 }
 
 bool SharedWorkerDevToolsAgent::Send(IPC::Message* message) {
diff --git a/content/child/shared_worker_devtools_agent.h b/content/child/shared_worker_devtools_agent.h
index 19b1ea9..2d6a732a 100644
--- a/content/child/shared_worker_devtools_agent.h
+++ b/content/child/shared_worker_devtools_agent.h
@@ -27,18 +27,15 @@
 
   // Called on the Worker thread.
   bool OnMessageReceived(const IPC::Message& message);
-  void SendDevToolsMessage(int session_id,
-                           int call_id,
+  void SendDevToolsMessage(int call_id,
                            const blink::WebString& message,
                            const blink::WebString& post_state);
 
  private:
-  void OnAttach(const std::string& host_id, int session_id);
-  void OnReattach(const std::string& host_id,
-                  int session_id,
-                  const std::string& state);
+  void OnAttach(const std::string& host_id);
+  void OnReattach(const std::string& host_id, const std::string& state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
+  void OnDispatchOnInspectorBackend(const std::string& message);
 
   bool Send(IPC::Message* message);
   const int route_id_;
diff --git a/content/common/devtools_messages.h b/content/common/devtools_messages.h
index cba6f54b..a6e17ecd 100644
--- a/content/common/devtools_messages.h
+++ b/content/common/devtools_messages.h
@@ -58,14 +58,12 @@
 // Agent -> Client message chunk.
 //   |is_first| marks the first chunk, comes with the |message_size| for
 //   total message size.
-//   |is_last| marks the last chunk. |call_id|, |session_id| and |post_state|
-//   are optional parameters passed with the last chunk of the protocol
-//   response.
+//   |is_last| marks the last chunk. |call_id| and |post_state| are optional
+//    parameters passed with the last chunk of the protocol response.
 IPC_STRUCT_BEGIN(DevToolsMessageChunk)
   IPC_STRUCT_MEMBER(bool, is_first)
   IPC_STRUCT_MEMBER(bool, is_last)
   IPC_STRUCT_MEMBER(int, message_size)
-  IPC_STRUCT_MEMBER(int, session_id)
   IPC_STRUCT_MEMBER(int, call_id)
   IPC_STRUCT_MEMBER(std::string, data)
   IPC_STRUCT_MEMBER(std::string, post_state)
@@ -79,29 +77,25 @@
 // These are messages sent from DevToolsClient to DevToolsAgent through the
 // browser.
 // Tells agent that there is a client host connected to it.
-IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_Attach,
-                    std::string /* host_id */,
-                    int /* session_id */)
+IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_Attach,
+                    std::string /* host_id */)
 
 // Tells agent that a client host was disconnected from another agent and
 // connected to this one.
-IPC_MESSAGE_ROUTED3(DevToolsAgentMsg_Reattach,
+IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_Reattach,
                     std::string /* host_id */,
-                    int /* session_id */,
                     std::string /* agent_state */)
 
 // Tells agent that there is no longer a client host connected to it.
 IPC_MESSAGE_ROUTED0(DevToolsAgentMsg_Detach)
 
 // WebKit-level transport.
-IPC_MESSAGE_ROUTED2(DevToolsAgentMsg_DispatchOnInspectorBackend,
-                    int /* session_id */,
+IPC_MESSAGE_ROUTED1(DevToolsAgentMsg_DispatchOnInspectorBackend,
                     std::string /* message */)
 
 // Inspect element with the given coordinates.
-IPC_MESSAGE_ROUTED4(DevToolsAgentMsg_InspectElement,
+IPC_MESSAGE_ROUTED3(DevToolsAgentMsg_InspectElement,
                     std::string /* host_id */,
-                    int /* session_id */,
                     int /* x */,
                     int /* y */)
 
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 7d2a67c6a..79c893d 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -544,7 +544,6 @@
       'browser/devtools/forwarding_agent_host.h',
       'browser/devtools/protocol/color_picker.cc',
       'browser/devtools/protocol/color_picker.h',
-      'browser/devtools/protocol/devtools_protocol_delegate.h',
       'browser/devtools/protocol/devtools_protocol_client.cc',
       'browser/devtools/protocol/devtools_protocol_client.h',
       'browser/devtools/protocol/dom_handler.cc',
diff --git a/content/public/android/java/src/org/chromium/content/browser/DeviceSensors.java b/content/public/android/java/src/org/chromium/content/browser/DeviceSensors.java
index 76835ce6..fbab3c0 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DeviceSensors.java
+++ b/content/public/android/java/src/org/chromium/content/browser/DeviceSensors.java
@@ -80,6 +80,8 @@
     static final Set<Integer> DEVICE_ORIENTATION_SENSORS_C = CollectionUtil.newHashSet(
             Sensor.TYPE_ACCELEROMETER,
             Sensor.TYPE_MAGNETIC_FIELD);
+    static final Set<Integer> DEVICE_ORIENTATION_ABSOLUTE_SENSORS = CollectionUtil.newHashSet(
+            Sensor.TYPE_ROTATION_VECTOR);
     static final Set<Integer> DEVICE_MOTION_SENSORS = CollectionUtil.newHashSet(
             Sensor.TYPE_ACCELEROMETER,
             Sensor.TYPE_LINEAR_ACCELERATION,
@@ -95,6 +97,7 @@
     boolean mDeviceMotionIsActive = false;
     boolean mDeviceOrientationIsActive = false;
     boolean mDeviceOrientationIsActiveWithBackupSensors = false;
+    boolean mDeviceOrientationAbsoluteIsActive = false;
     boolean mOrientationNotAvailable = false;
 
     protected DeviceSensors(Context context, boolean relativeByDefault) {
@@ -151,8 +154,8 @@
      * @param nativePtr Value to pass to nativeGotOrientation() for each event.
      * @param rateInMicroseconds Requested callback rate in microseconds. The
      *            actual rate may be higher. Unwanted events should be ignored.
-     * @param eventType Type of event to listen to, can be either DEVICE_ORIENTATION or
-     *                  DEVICE_MOTION or DEVICE_LIGHT.
+     * @param eventType Type of event to listen to, can be either DEVICE_ORIENTATION,
+     *            DEVICE_ORIENTATION_ABSOLUTE, DEVICE_MOTION or DEVICE_LIGHT.
      * @return True on success.
      */
     @CalledByNative
@@ -164,9 +167,10 @@
                     success = registerOrientationSensorsWithFallback(rateInMicroseconds);
                     break;
                 case ConsumerType.ORIENTATION_ABSOLUTE:
-                    // not implemented
-                    assert false;
-                    return false;
+                    ensureRotationStructuresAllocated();
+                    success = registerSensors(DEVICE_ORIENTATION_ABSOLUTE_SENSORS,
+                            rateInMicroseconds, true);
+                    break;
                 case ConsumerType.MOTION:
                     // note: device motion spec does not require all sensors to be available
                     success = registerSensors(DEVICE_MOTION_SENSORS, rateInMicroseconds, false);
@@ -224,35 +228,23 @@
     @CalledByNative
     public void stop(int eventType) {
         Set<Integer> sensorsToRemainActive = new HashSet<Integer>();
+
         synchronized (mNativePtrLock) {
-            switch (eventType) {
-                case ConsumerType.ORIENTATION:
-                    if (mDeviceMotionIsActive) {
-                        sensorsToRemainActive.addAll(DEVICE_MOTION_SENSORS);
-                    }
-                    if (mDeviceLightIsActive) {
-                        sensorsToRemainActive.addAll(DEVICE_LIGHT_SENSORS);
-                    }
-                    break;
-                case ConsumerType.MOTION:
-                    if (mDeviceOrientationIsActive) {
-                        sensorsToRemainActive.addAll(mDeviceOrientationSensors);
-                    }
-                    if (mDeviceLightIsActive) {
-                        sensorsToRemainActive.addAll(DEVICE_LIGHT_SENSORS);
-                    }
-                    break;
-                case ConsumerType.LIGHT:
-                    if (mDeviceMotionIsActive) {
-                        sensorsToRemainActive.addAll(DEVICE_MOTION_SENSORS);
-                    }
-                    if (mDeviceOrientationIsActive) {
-                        sensorsToRemainActive.addAll(mDeviceOrientationSensors);
-                    }
-                    break;
-                default:
-                    Log.e(TAG, "Unknown event type: %d", eventType);
-                    return;
+            if (mDeviceOrientationIsActive && eventType != ConsumerType.ORIENTATION) {
+                sensorsToRemainActive.addAll(mDeviceOrientationSensors);
+            }
+
+            if (mDeviceOrientationAbsoluteIsActive
+                    && eventType != ConsumerType.ORIENTATION_ABSOLUTE) {
+                sensorsToRemainActive.addAll(DEVICE_ORIENTATION_ABSOLUTE_SENSORS);
+            }
+
+            if (mDeviceMotionIsActive && eventType != ConsumerType.MOTION) {
+                sensorsToRemainActive.addAll(DEVICE_MOTION_SENSORS);
+            }
+
+            if (mDeviceLightIsActive && eventType != ConsumerType.LIGHT) {
+                sensorsToRemainActive.addAll(DEVICE_LIGHT_SENSORS);
             }
 
             Set<Integer> sensorsToDeactivate = new HashSet<Integer>(mActiveSensors);
@@ -297,21 +289,24 @@
                 }
                 break;
             case Sensor.TYPE_ROTATION_VECTOR:
+                if (mDeviceOrientationAbsoluteIsActive) {
+                    convertRotationVectorToAngles(values, mRotationAngles);
+                    gotOrientationAbsolute(mRotationAngles[0], mRotationAngles[1],
+                            mRotationAngles[2]);
+                }
+                if (mDeviceOrientationIsActive
+                        && mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSORS_B) {
+                    if (!mDeviceOrientationAbsoluteIsActive) {
+                        // only compute if not already computed for absolute orientation above.
+                        convertRotationVectorToAngles(values, mRotationAngles);
+                    }
+                    gotOrientation(mRotationAngles[0], mRotationAngles[1], mRotationAngles[2]);
+                }
+                break;
             case Sensor.TYPE_GAME_ROTATION_VECTOR:
                 if (mDeviceOrientationIsActive) {
-                    if (values.length > 4) {
-                        // On some Samsung devices SensorManager.getRotationMatrixFromVector
-                        // appears to throw an exception if rotation vector has length > 4.
-                        // For the purposes of this class the first 4 values of the
-                        // rotation vector are sufficient (see crbug.com/335298 for details).
-                        if (mTruncatedRotationVector == null) {
-                            mTruncatedRotationVector = new float[4];
-                        }
-                        System.arraycopy(values, 0, mTruncatedRotationVector, 0, 4);
-                        getOrientationFromRotationVector(mTruncatedRotationVector);
-                    } else {
-                        getOrientationFromRotationVector(values);
-                    }
+                    convertRotationVectorToAngles(values, mRotationAngles);
+                    gotOrientation(mRotationAngles[0], mRotationAngles[1], mRotationAngles[2]);
                 }
                 break;
             case Sensor.TYPE_MAGNETIC_FIELD:
@@ -418,13 +413,26 @@
         return values;
     }
 
-    private void getOrientationFromRotationVector(float[] rotationVector) {
-        SensorManager.getRotationMatrixFromVector(mDeviceRotationMatrix, rotationVector);
-        computeDeviceOrientationFromRotationMatrix(mDeviceRotationMatrix, mRotationAngles);
-
-        gotOrientation(Math.toDegrees(mRotationAngles[0]),
-                       Math.toDegrees(mRotationAngles[1]),
-                       Math.toDegrees(mRotationAngles[2]));
+    /*
+     * Converts a given rotation vector to its Euler angles representation. The angles
+     * are in degrees.
+     */
+    public void convertRotationVectorToAngles(float[] rotationVector, double[] angles) {
+        if (rotationVector.length > 4) {
+            // On some Samsung devices SensorManager.getRotationMatrixFromVector
+            // appears to throw an exception if rotation vector has length > 4.
+            // For the purposes of this class the first 4 values of the
+            // rotation vector are sufficient (see crbug.com/335298 for details).
+            System.arraycopy(rotationVector, 0, mTruncatedRotationVector, 0, 4);
+            SensorManager.getRotationMatrixFromVector(mDeviceRotationMatrix,
+                    mTruncatedRotationVector);
+        } else {
+            SensorManager.getRotationMatrixFromVector(mDeviceRotationMatrix, rotationVector);
+        }
+        computeDeviceOrientationFromRotationMatrix(mDeviceRotationMatrix, angles);
+        for (int i = 0; i < 3; i++) {
+            angles[i] = Math.toDegrees(angles[i]);
+        }
     }
 
     private void getOrientationFromGeomagneticVectors(float[] acceleration, float[] magnetic) {
@@ -468,6 +476,9 @@
                 mDeviceOrientationIsActiveWithBackupSensors = active
                         && (mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSORS_C);
                 return;
+            case ConsumerType.ORIENTATION_ABSOLUTE:
+                mDeviceOrientationAbsoluteIsActive = active;
+                return;
             case ConsumerType.MOTION:
                 mDeviceMotionIsActive = active;
                 return;
@@ -484,6 +495,9 @@
         if (mRotationAngles == null) {
             mRotationAngles = new double[3];
         }
+        if (mTruncatedRotationVector == null) {
+            mTruncatedRotationVector = new float[4];
+        }
     }
 
     /**
@@ -497,8 +511,9 @@
             boolean failOnMissingSensor) {
         Set<Integer> sensorsToActivate = new HashSet<Integer>(sensorTypes);
         sensorsToActivate.removeAll(mActiveSensors);
-        boolean success = false;
+        if (sensorsToActivate.isEmpty()) return true;
 
+        boolean success = false;
         for (Integer sensorType : sensorsToActivate) {
             boolean result = registerForSensorType(sensorType, rateInMicroseconds);
             if (!result && failOnMissingSensor) {
@@ -539,6 +554,14 @@
         }
     }
 
+    protected void gotOrientationAbsolute(double alpha, double beta, double gamma) {
+        synchronized (mNativePtrLock) {
+            if (mNativePtr != 0) {
+                nativeGotOrientationAbsolute(mNativePtr, alpha, beta, gamma);
+            }
+        }
+    }
+
     protected void gotAcceleration(double x, double y, double z) {
         synchronized (mNativePtrLock) {
             if (mNativePtr != 0) {
@@ -612,6 +635,13 @@
             double alpha, double beta, double gamma);
 
     /**
+     * Absolute orientation of the device with respect to its reference frame.
+     */
+    private native void nativeGotOrientationAbsolute(
+            long nativeSensorManagerAndroid,
+            double alpha, double beta, double gamma);
+
+    /**
      * Linear acceleration without gravity of the device with respect to its body frame.
      */
     private native void nativeGotAcceleration(
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/DeviceSensorsTest.java b/content/public/android/javatests/src/org/chromium/content/browser/DeviceSensorsTest.java
index 38ed238..9f491a2e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/DeviceSensorsTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/DeviceSensorsTest.java
@@ -161,6 +161,67 @@
     }
 
     @SmallTest
+    public void testRegisterSensorsDeviceOrientationAbsolute() {
+        boolean start = mDeviceSensors.start(0, ConsumerType.ORIENTATION_ABSOLUTE, 100);
+
+        assertTrue(start);
+        assertTrue("should contain all absolute orientation sensors",
+                mDeviceSensors.mActiveSensors.containsAll(
+                        DeviceSensors.DEVICE_ORIENTATION_ABSOLUTE_SENSORS));
+        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
+        assertFalse(mDeviceSensors.mDeviceLightIsActive);
+        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
+        assertFalse(mDeviceSensors.mDeviceOrientationIsActiveWithBackupSensors);
+        assertTrue(mDeviceSensors.mDeviceOrientationAbsoluteIsActive);
+
+        assertEquals(DeviceSensors.DEVICE_ORIENTATION_ABSOLUTE_SENSORS.size(),
+                mMockSensorManager.mNumRegistered);
+        assertEquals(0, mMockSensorManager.mNumUnRegistered);
+    }
+
+    @SmallTest
+    public void testUnregisterSensorsDeviceOrientationAbsolute() {
+        mDeviceSensors.start(0, ConsumerType.ORIENTATION_ABSOLUTE, 100);
+        mDeviceSensors.stop(ConsumerType.ORIENTATION_ABSOLUTE);
+
+        assertTrue("should contain no sensors",
+                mDeviceSensors.mActiveSensors.isEmpty());
+        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
+        assertFalse(mDeviceSensors.mDeviceOrientationIsActive);
+        assertFalse(mDeviceSensors.mDeviceOrientationIsActiveWithBackupSensors);
+        assertFalse(mDeviceSensors.mDeviceLightIsActive);
+        assertEquals(DeviceSensors.DEVICE_ORIENTATION_ABSOLUTE_SENSORS.size(),
+                mMockSensorManager.mNumUnRegistered);
+    }
+
+    @SmallTest
+    public void testRegisterSensorsDeviceOrientationAndOrientationAbsolute() {
+        boolean startOrientation = mDeviceSensors.start(0, ConsumerType.ORIENTATION, 100);
+        boolean startOrientationAbsolute = mDeviceSensors.start(0,
+                ConsumerType.ORIENTATION_ABSOLUTE, 100);
+
+        assertTrue(startOrientation);
+        assertTrue(startOrientationAbsolute);
+        assertTrue("should contain all orientation sensors",
+                mDeviceSensors.mActiveSensors.containsAll(
+                        DeviceSensors.DEVICE_ORIENTATION_SENSORS_A));
+        assertTrue("should contain all absolute orientation sensors",
+                mDeviceSensors.mActiveSensors.containsAll(
+                        DeviceSensors.DEVICE_ORIENTATION_ABSOLUTE_SENSORS));
+
+        Set<Integer> union = new HashSet<Integer>(DeviceSensors.DEVICE_ORIENTATION_SENSORS_A);
+        union.addAll(DeviceSensors.DEVICE_ORIENTATION_ABSOLUTE_SENSORS);
+
+        assertEquals(union.size(), mDeviceSensors.mActiveSensors.size());
+        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
+        assertTrue(mDeviceSensors.mDeviceOrientationAbsoluteIsActive);
+        assertFalse(mDeviceSensors.mDeviceMotionIsActive);
+        assertFalse(mDeviceSensors.mDeviceLightIsActive);
+        assertEquals(union.size(), mMockSensorManager.mNumRegistered);
+        assertEquals(0, mMockSensorManager.mNumUnRegistered);
+    }
+
+    @SmallTest
     public void testRegisterSensorsDeviceLight() {
         boolean start = mDeviceSensors.start(0, ConsumerType.LIGHT, 100);
 
@@ -254,27 +315,61 @@
     /**
      * Helper method to trigger an orientation change using the given sensorType.
      */
-    private void changeOrientation(int sensorType) {
-        boolean startOrientation = mDeviceSensors.start(0, ConsumerType.ORIENTATION, 100);
+    private void changeOrientation(int sensorType, boolean absolute, String expectedChange) {
+        boolean startOrientation = mDeviceSensors.start(0,
+                absolute ? ConsumerType.ORIENTATION_ABSOLUTE : ConsumerType.ORIENTATION, 100);
 
         assertTrue(startOrientation);
-        assertTrue(mDeviceSensors.mDeviceOrientationIsActive);
+        assertTrue(absolute ? mDeviceSensors.mDeviceOrientationAbsoluteIsActive
+                            : mDeviceSensors.mDeviceOrientationIsActive);
 
         float alpha = (float) Math.PI / 4;
         float[] values = {0, 0, (float) Math.sin(alpha / 2), (float) Math.cos(alpha / 2), -1};
         mDeviceSensors.sensorChanged(sensorType, values);
-        mDeviceSensors.verifyCalls("gotOrientation");
-        mDeviceSensors.verifyValuesEpsilon(Math.toDegrees(alpha), 0, 0);
+
+        mDeviceSensors.verifyCalls(expectedChange);
+        if (!expectedChange.isEmpty()) {
+            mDeviceSensors.verifyValuesEpsilon(Math.toDegrees(alpha), 0, 0);
+        }
     }
 
     @SmallTest
     public void testSensorChangedGotOrientationViaRotationVector() {
-        changeOrientation(Sensor.TYPE_ROTATION_VECTOR);
+        changeOrientation(Sensor.TYPE_ROTATION_VECTOR, false /* absolute */, "");
     }
 
     @SmallTest
     public void testSensorChangedGotOrientationViaGameRotationVector() {
-        changeOrientation(Sensor.TYPE_GAME_ROTATION_VECTOR);
+        changeOrientation(Sensor.TYPE_GAME_ROTATION_VECTOR, false /* absolute */, "gotOrientation");
+    }
+
+    @SmallTest
+    public void testSensorChangedGotOrientationAbsoluteViaRotationVector() {
+        changeOrientation(Sensor.TYPE_ROTATION_VECTOR, true /* absolute */,
+                "gotOrientationAbsolute");
+    }
+
+    @SmallTest
+    public void testSensorChangedGotOrientationAbsoluteViaGameRotationVector() {
+        changeOrientation(Sensor.TYPE_GAME_ROTATION_VECTOR, true /* absolute */, "");
+    }
+
+    @SmallTest
+    public void testSensorChangedGotOrientationAndOrientationAbsolute() {
+        changeOrientation(Sensor.TYPE_GAME_ROTATION_VECTOR, false /* absolute */, "gotOrientation");
+        changeOrientation(Sensor.TYPE_ROTATION_VECTOR, true /* absolute */,
+                "gotOrientation" + "gotOrientationAbsolute");
+    }
+
+    @SmallTest
+    public void testSensorChangedGotOrientationViaRotationVectorAndOrientationAbsolute() {
+        MockSensorManager mockSensorManager = new MockSensorManager();
+        mockSensorManager.setGameRotationVectorAvailable(false);
+        mDeviceSensors.setSensorManagerProxy(mockSensorManager);
+
+        changeOrientation(Sensor.TYPE_ROTATION_VECTOR, false /* absolute */, "gotOrientation");
+        changeOrientation(Sensor.TYPE_ROTATION_VECTOR, true /* absolute */,
+                "gotOrientation" + "gotOrientationAbsolute" + "gotOrientation");
     }
 
     @SmallTest
@@ -319,7 +414,7 @@
 
         float alpha = (float) Math.PI / 4;
         float[] values = {0, 0, (float) Math.sin(alpha / 2), (float) Math.cos(alpha / 2), -1};
-        mDeviceSensors.sensorChanged(Sensor.TYPE_ROTATION_VECTOR, values);
+        mDeviceSensors.sensorChanged(Sensor.TYPE_GAME_ROTATION_VECTOR, values);
         mDeviceSensors.verifyCalls("gotOrientation");
         mDeviceSensors.verifyValuesEpsilon(Math.toDegrees(alpha), 0, 0);
 
@@ -475,6 +570,14 @@
         }
 
         @Override
+        protected void gotOrientationAbsolute(double alpha, double beta, double gamma) {
+            mValue1 = alpha;
+            mValue2 = beta;
+            mValue3 = gamma;
+            mCalls = mCalls.concat("gotOrientationAbsolute");
+        }
+
+        @Override
         protected void gotAcceleration(double x, double y, double z) {
             mValue1 = x;
             mValue2 = y;
diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc
index a7d91cac..d464b15b 100644
--- a/content/renderer/devtools/devtools_agent.cc
+++ b/content/renderer/devtools/devtools_agent.cc
@@ -101,12 +101,12 @@
   ContinueProgram();
 }
 
-void DevToolsAgent::sendProtocolMessage(int session_id,
-                                        int call_id,
-                                        const blink::WebString& message,
-                                        const blink::WebString& state_cookie) {
-  SendChunkedProtocolMessage(this, routing_id(), session_id, call_id,
-                             message.utf8(), state_cookie.utf8());
+void DevToolsAgent::sendProtocolMessage(
+    int call_id,
+    const blink::WebString& message,
+    const blink::WebString& state_cookie) {
+  SendChunkedProtocolMessage(
+      this, routing_id(), call_id, message.utf8(), state_cookie.utf8());
 }
 
 blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
@@ -151,19 +151,18 @@
 }
 
 // static
-void DevToolsAgent::SendChunkedProtocolMessage(IPC::Sender* sender,
-                                               int routing_id,
-                                               int session_id,
-                                               int call_id,
-                                               const std::string& message,
-                                               const std::string& post_state) {
+void DevToolsAgent::SendChunkedProtocolMessage(
+    IPC::Sender* sender,
+    int routing_id,
+    int call_id,
+    const std::string& message,
+    const std::string& post_state) {
   DevToolsMessageChunk chunk;
   chunk.message_size = message.size();
   chunk.is_first = true;
 
   if (message.length() < kMaxMessageChunkSize) {
     chunk.data = message;
-    chunk.session_id = session_id;
     chunk.call_id = call_id;
     chunk.post_state = post_state;
     chunk.is_last = true;
@@ -174,7 +173,6 @@
 
   for (size_t pos = 0; pos < message.length(); pos += kMaxMessageChunkSize) {
     chunk.is_last = pos + kMaxMessageChunkSize >= message.length();
-    chunk.session_id = chunk.is_last ? session_id : 0;
     chunk.call_id = chunk.is_last ? call_id : 0;
     chunk.post_state = chunk.is_last ? post_state : std::string();
     chunk.data = message.substr(pos, kMaxMessageChunkSize);
@@ -185,20 +183,19 @@
   }
 }
 
-void DevToolsAgent::OnAttach(const std::string& host_id, int session_id) {
+void DevToolsAgent::OnAttach(const std::string& host_id) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->attach(WebString::fromUTF8(host_id), session_id);
+    web_agent->attach(WebString::fromUTF8(host_id));
     is_attached_ = true;
   }
 }
 
 void DevToolsAgent::OnReattach(const std::string& host_id,
-                               int session_id,
                                const std::string& agent_state) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->reattach(WebString::fromUTF8(host_id), session_id,
+    web_agent->reattach(WebString::fromUTF8(host_id),
                         WebString::fromUTF8(agent_state));
     is_attached_ = true;
   }
@@ -212,22 +209,18 @@
   }
 }
 
-void DevToolsAgent::OnDispatchOnInspectorBackend(int session_id,
-                                                 const std::string& message) {
+void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) {
   TRACE_EVENT0("devtools", "DevToolsAgent::OnDispatchOnInspectorBackend");
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent)
-    web_agent->dispatchOnInspectorBackend(session_id,
-                                          WebString::fromUTF8(message));
+    web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message));
 }
 
-void DevToolsAgent::OnInspectElement(const std::string& host_id,
-                                     int session_id,
-                                     int x,
-                                     int y) {
+void DevToolsAgent::OnInspectElement(
+    const std::string& host_id, int x, int y) {
   WebDevToolsAgent* web_agent = GetWebAgent();
   if (web_agent) {
-    web_agent->attach(WebString::fromUTF8(host_id), session_id);
+    web_agent->attach(WebString::fromUTF8(host_id));
     web_agent->inspectElementAt(WebPoint(x, y));
     is_attached_ = true;
   }
diff --git a/content/renderer/devtools/devtools_agent.h b/content/renderer/devtools/devtools_agent.h
index 865fc0fd8..7b1200b 100644
--- a/content/renderer/devtools/devtools_agent.h
+++ b/content/renderer/devtools/devtools_agent.h
@@ -33,12 +33,12 @@
   // Returns agent instance for its routing id.
   static DevToolsAgent* FromRoutingId(int routing_id);
 
-  static void SendChunkedProtocolMessage(IPC::Sender* sender,
-                                         int routing_id,
-                                         int session_id,
-                                         int call_id,
-                                         const std::string& message,
-                                         const std::string& post_state);
+  static void SendChunkedProtocolMessage(
+      IPC::Sender* sender,
+      int routing_id,
+      int call_id,
+      const std::string& message,
+      const std::string& post_state);
 
   blink::WebDevToolsAgent* GetWebAgent();
 
@@ -55,8 +55,7 @@
   void WidgetWillClose() override;
 
   // WebDevToolsAgentClient implementation.
-  void sendProtocolMessage(int session_id,
-                           int call_id,
+  void sendProtocolMessage(int call_id,
                            const blink::WebString& response,
                            const blink::WebString& state) override;
   blink::WebDevToolsAgentClient::WebKitClientMessageLoop*
@@ -67,16 +66,12 @@
   void enableTracing(const blink::WebString& category_filter) override;
   void disableTracing() override;
 
-  void OnAttach(const std::string& host_id, int session_id);
+  void OnAttach(const std::string& host_id);
   void OnReattach(const std::string& host_id,
-                  int session_id,
                   const std::string& agent_state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
-  void OnInspectElement(const std::string& host_id,
-                        int session_id,
-                        int x,
-                        int y);
+  void OnDispatchOnInspectorBackend(const std::string& message);
+  void OnInspectElement(const std::string& host_id, int x, int y);
   void ContinueProgram();
   void OnSetupDevToolsClient(const std::string& compatibility_script);
 
diff --git a/content/renderer/devtools/devtools_agent_filter.cc b/content/renderer/devtools/devtools_agent_filter.cc
index 94b9e0d4..e1b3af0 100644
--- a/content/renderer/devtools/devtools_agent_filter.cc
+++ b/content/renderer/devtools/devtools_agent_filter.cc
@@ -60,7 +60,6 @@
 DevToolsAgentFilter::~DevToolsAgentFilter() {}
 
 void DevToolsAgentFilter::OnDispatchOnInspectorBackend(
-    int session_id,
     const std::string& message) {
   if (embedded_worker_routes_.find(current_routing_id_) !=
       embedded_worker_routes_.end()) {
@@ -70,7 +69,7 @@
   if (WebDevToolsAgent::shouldInterruptForMessage(
           WebString::fromUTF8(message))) {
     WebDevToolsAgent::interruptAndDispatch(
-        session_id, new MessageImpl(message, current_routing_id_));
+        new MessageImpl(message, current_routing_id_));
   }
 
 }
diff --git a/content/renderer/devtools/devtools_agent_filter.h b/content/renderer/devtools/devtools_agent_filter.h
index 9113ae2..c8ba687 100644
--- a/content/renderer/devtools/devtools_agent_filter.h
+++ b/content/renderer/devtools/devtools_agent_filter.h
@@ -43,7 +43,7 @@
   ~DevToolsAgentFilter() override;
 
  private:
-  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
+  void OnDispatchOnInspectorBackend(const std::string& message);
 
   // Called on IO thread
   void AddEmbeddedWorkerRoute(int32 routing_id);
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 4c0477b..9b4d312c 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -146,7 +146,7 @@
     const MediaSourceOpenedCB& media_source_opened_cb,
     const media::Demuxer::EncryptedMediaInitDataCB&
         encrypted_media_init_data_cb,
-    const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const media::SetCdmReadyCB& set_cdm_ready_cb,
     const UpdateNetworkStateCB& update_network_state_cb,
     const DurationChangeCB& duration_change_cb,
     const base::Closure& waiting_for_decryption_key_cb) {
@@ -154,7 +154,7 @@
   DCHECK(!media_source_opened_cb.is_null());
   media_source_opened_cb_ = media_source_opened_cb;
   encrypted_media_init_data_cb_ = encrypted_media_init_data_cb;
-  set_decryptor_ready_cb_ = media::BindToCurrentLoop(set_decryptor_ready_cb);
+  set_cdm_ready_cb_ = media::BindToCurrentLoop(set_cdm_ready_cb);
   update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
   duration_change_cb_ = duration_change_cb;
   waiting_for_decryption_key_cb_ =
@@ -496,7 +496,7 @@
   video_stream_ = chunk_demuxer_->GetStream(DemuxerStream::VIDEO);
 
   if (audio_stream_ && audio_stream_->audio_decoder_config().is_encrypted() &&
-      !set_decryptor_ready_cb_.is_null()) {
+      !set_cdm_ready_cb_.is_null()) {
     InitAudioDecryptingDemuxerStream();
     // InitVideoDecryptingDemuxerStream() will be called in
     // OnAudioDecryptingDemuxerStreamInitDone().
@@ -504,7 +504,7 @@
   }
 
   if (video_stream_ && video_stream_->video_decoder_config().is_encrypted() &&
-      !set_decryptor_ready_cb_.is_null()) {
+      !set_cdm_ready_cb_.is_null()) {
     InitVideoDecryptingDemuxerStream();
     return;
   }
@@ -517,10 +517,10 @@
 void MediaSourceDelegate::InitAudioDecryptingDemuxerStream() {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
-  DCHECK(!set_decryptor_ready_cb_.is_null());
+  DCHECK(!set_cdm_ready_cb_.is_null());
 
   audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, media_log_, set_decryptor_ready_cb_,
+      media_task_runner_, media_log_, set_cdm_ready_cb_,
       waiting_for_decryption_key_cb_));
   audio_decrypting_demuxer_stream_->Initialize(
       audio_stream_,
@@ -531,10 +531,10 @@
 void MediaSourceDelegate::InitVideoDecryptingDemuxerStream() {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
   DVLOG(1) << __FUNCTION__ << " : " << demuxer_client_id_;
-  DCHECK(!set_decryptor_ready_cb_.is_null());
+  DCHECK(!set_cdm_ready_cb_.is_null());
 
   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, media_log_, set_decryptor_ready_cb_,
+      media_task_runner_, media_log_, set_cdm_ready_cb_,
       waiting_for_decryption_key_cb_));
   video_decrypting_demuxer_stream_->Initialize(
       video_stream_,
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index e6442308..ee5e1a4 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -13,7 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
-#include "media/base/decryptor.h"
+#include "media/base/cdm_context.h"
 #include "media/base/demuxer.h"
 #include "media/base/media_keys.h"
 #include "media/base/pipeline_status.h"
@@ -60,7 +60,7 @@
       const MediaSourceOpenedCB& media_source_opened_cb,
       const media::Demuxer::EncryptedMediaInitDataCB&
           encrypted_media_init_data_cb,
-      const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const media::SetCdmReadyCB& set_cdm_ready_cb,
       const UpdateNetworkStateCB& update_network_state_cb,
       const DurationChangeCB& duration_change_cb,
       const base::Closure& waiting_for_decryption_key_cb);
@@ -186,7 +186,7 @@
   scoped_ptr<media::ChunkDemuxer> chunk_demuxer_;
   bool is_demuxer_ready_;
 
-  media::SetDecryptorReadyCB set_decryptor_ready_cb_;
+  media::SetCdmReadyCB set_cdm_ready_cb_;
 
   scoped_ptr<media::DecryptingDemuxerStream> audio_decrypting_demuxer_stream_;
   scoped_ptr<media::DecryptingDemuxerStream> video_decrypting_demuxer_stream_;
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index ceecc08..cfd92af 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -186,19 +186,18 @@
       needs_establish_peer_(true),
       has_size_info_(false),
       // Threaded compositing isn't enabled universally yet.
-      compositor_task_runner_(
-          params.compositor_task_runner()
-              ? params.compositor_task_runner()
-              : base::ThreadTaskRunnerHandle::Get()),
+      compositor_task_runner_(params.compositor_task_runner()
+                                  ? params.compositor_task_runner()
+                                  : base::ThreadTaskRunnerHandle::Get()),
       stream_texture_factory_(factory),
       needs_external_surface_(false),
       is_fullscreen_(false),
-      video_frame_provider_client_(NULL),
+      video_frame_provider_client_(nullptr),
       player_type_(MEDIA_PLAYER_TYPE_URL),
       is_remote_(false),
       media_log_(params.media_log()),
       init_data_type_(media::EmeInitDataType::UNKNOWN),
-      cdm_context_(NULL),
+      cdm_context_(nullptr),
       allow_stored_credentials_(false),
       is_local_resource_(false),
       interpolator_(&default_tick_clock_),
@@ -326,7 +325,7 @@
                      weak_factory_.GetWeakPtr()),
           base::Bind(&WebMediaPlayerAndroid::OnEncryptedMediaInitData,
                      weak_factory_.GetWeakPtr()),
-          base::Bind(&WebMediaPlayerAndroid::SetDecryptorReadyCB,
+          base::Bind(&WebMediaPlayerAndroid::SetCdmReadyCB,
                      weak_factory_.GetWeakPtr()),
           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
                      weak_factory_.GetWeakPtr()),
@@ -1711,12 +1710,12 @@
   cdm_context_ = media::ToWebContentDecryptionModuleImpl(cdm)->GetCdmContext();
 
   if (is_player_initialized_) {
-    SetCdmInternal(media::BindToCurrentLoop(
+    SetCdmInternal(
         base::Bind(&WebMediaPlayerAndroid::ContentDecryptionModuleAttached,
-                   weak_factory_.GetWeakPtr(), result)));
+                   weak_factory_.GetWeakPtr(), result));
   } else {
     // No pipeline/decoder connected, so resolve the promise. When something
-    // is connected, setting the CDM will happen in SetDecryptorReadyCB().
+    // is connected, setting the CDM will happen in SetCdmReadyCB().
     ContentDecryptionModuleAttached(result, true);
   }
 }
@@ -1830,70 +1829,69 @@
 
 void WebMediaPlayerAndroid::SetCdmInternal(
     const media::CdmAttachedCB& cdm_attached_cb) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK(cdm_context_ && is_player_initialized_);
   DCHECK(cdm_context_->GetDecryptor() ||
          cdm_context_->GetCdmId() != media::CdmContext::kInvalidCdmId)
       << "CDM should support either a Decryptor or a CDM ID.";
 
-  media::Decryptor* decryptor = cdm_context_->GetDecryptor();
-
-  // Note:
-  // - If |decryptor| is non-null, only handles |decryptor_ready_cb_| and
-  //   ignores the CDM ID.
-  // - If |decryptor| is null (in which case the CDM ID should be valid),
-  //   returns any pending |decryptor_ready_cb_| with null, so that
-  //   MediaSourceDelegate will fall back to use a browser side (IPC-based) CDM,
-  //   then calls SetCdm() through the |player_manager_|.
-
-  if (decryptor) {
-    if (!decryptor_ready_cb_.is_null()) {
-      base::ResetAndReturn(&decryptor_ready_cb_)
-          .Run(decryptor, cdm_attached_cb);
-    } else {
-      cdm_attached_cb.Run(true);
-    }
+  if (cdm_ready_cb_.is_null()) {
+    cdm_attached_cb.Run(true);
     return;
   }
 
-  // |decryptor| is null.
-  if (!decryptor_ready_cb_.is_null()) {
-    base::ResetAndReturn(&decryptor_ready_cb_)
-        .Run(nullptr, base::Bind(&media::IgnoreCdmAttached));
+  // Satisfy |cdm_ready_cb_|. Use BindToCurrentLoop() since the callback could
+  // be fired on other threads.
+  base::ResetAndReturn(&cdm_ready_cb_)
+      .Run(cdm_context_, media::BindToCurrentLoop(base::Bind(
+                             &WebMediaPlayerAndroid::OnCdmAttached,
+                             weak_factory_.GetWeakPtr(), cdm_attached_cb)));
+}
+
+void WebMediaPlayerAndroid::OnCdmAttached(
+    const media::CdmAttachedCB& cdm_attached_cb,
+    bool success) {
+  DCHECK(main_thread_checker_.CalledOnValidThread());
+
+  if (!success) {
+    if (cdm_context_->GetCdmId() == media::CdmContext::kInvalidCdmId) {
+      NOTREACHED() << "CDM cannot be attached to media player.";
+      cdm_attached_cb.Run(false);
+      return;
+    }
+
+    // If the CDM is not attached (e.g. the CDM does not support a Decryptor),
+    // MediaSourceDelegate will fall back to use a browser side (IPC-based) CDM.
+    player_manager_->SetCdm(player_id_, cdm_context_->GetCdmId());
   }
 
-  DCHECK(cdm_context_->GetCdmId() != media::CdmContext::kInvalidCdmId);
-  player_manager_->SetCdm(player_id_, cdm_context_->GetCdmId());
   cdm_attached_cb.Run(true);
 }
 
-void WebMediaPlayerAndroid::SetDecryptorReadyCB(
-    const media::DecryptorReadyCB& decryptor_ready_cb) {
+void WebMediaPlayerAndroid::SetCdmReadyCB(
+    const media::CdmReadyCB& cdm_ready_cb) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
   DCHECK(is_player_initialized_);
 
-  // Cancels the previous decryptor request.
-  if (decryptor_ready_cb.is_null()) {
-    if (!decryptor_ready_cb_.is_null()) {
-      base::ResetAndReturn(&decryptor_ready_cb_)
-          .Run(NULL, base::Bind(&media::IgnoreCdmAttached));
+  // Cancels the previous CDM request.
+  if (cdm_ready_cb.is_null()) {
+    if (!cdm_ready_cb_.is_null()) {
+      base::ResetAndReturn(&cdm_ready_cb_)
+          .Run(nullptr, base::Bind(&media::IgnoreCdmAttached));
     }
     return;
   }
 
-  // TODO(xhwang): Support multiple decryptor notification request (e.g. from
+  // TODO(xhwang): Support multiple CDM notification request (e.g. from
   // video and audio). The current implementation is okay for the current
   // media pipeline since we initialize audio and video decoders in sequence.
-  // But WebMediaPlayerImpl should not depend on media pipeline's implementation
-  // detail.
-  DCHECK(decryptor_ready_cb_.is_null());
+  // But WebMediaPlayerAndroid should not depend on media pipeline's
+  // implementation detail.
+  DCHECK(cdm_ready_cb_.is_null());
+  cdm_ready_cb_ = cdm_ready_cb;
 
-  if (cdm_context_) {
-    decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
-                           base::Bind(&media::IgnoreCdmAttached));
-    return;
-  }
-
-  decryptor_ready_cb_ = decryptor_ready_cb;
+  if (cdm_context_)
+    SetCdmInternal(base::Bind(&media::IgnoreCdmAttached));
 }
 
 bool WebMediaPlayerAndroid::supportsOverlayFullscreenVideo() {
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 2dea4b4d..59859ff1 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -320,15 +320,18 @@
   void OnCdmContextReady(media::CdmContext* cdm_context);
 
   // Sets the CDM. Should only be called when |is_player_initialized_| is true
-  // and a new non-null |cdm_context_| is available. Fires |cdm_attached_cb_|
-  // with the result after the CDM is attached.
+  // and a new non-null |cdm_context_| is available. Fires |cdm_attached_cb_| on
+  // the main thread with the result after the CDM is attached.
   void SetCdmInternal(const media::CdmAttachedCB& cdm_attached_cb);
 
-  // Requests that this object notifies when a decryptor is ready through the
-  // |decryptor_ready_cb| provided.
-  // If |decryptor_ready_cb| is null, the existing callback will be fired with
+  // Called when the CDM is attached.
+  void OnCdmAttached(const media::CdmAttachedCB& cdm_attached_cb, bool success);
+
+  // Requests that this object notifies when a CDM is ready through the
+  // |cdm_ready_cb| provided.
+  // If |cdm_ready_cb| is null, the existing callback will be fired with
   // NULL immediately and reset.
-  void SetDecryptorReadyCB(const media::DecryptorReadyCB& decryptor_ready_cb);
+  void SetCdmReadyCB(const media::CdmReadyCB& cdm_ready_cb);
 
   // Called when the ContentDecryptionModule has been attached to the
   // pipeline/decoders.
@@ -509,7 +512,7 @@
   // side CDM will be used. This is similar to WebMediaPlayerImpl. For other key
   // systems, a browser side CDM will be used and we set CDM by calling
   // player_manager_->SetCdm() directly.
-  media::DecryptorReadyCB decryptor_ready_cb_;
+  media::CdmReadyCB cdm_ready_cb_;
 
   SkBitmap bitmap_;
 
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 90715c8..3783e905 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -300,7 +300,7 @@
  public:
   void Attach() {
     std::string host_id = "host_id";
-    agent()->OnAttach(host_id, 17);
+    agent()->OnAttach(host_id);
   }
 
   void Detach() {
@@ -312,7 +312,7 @@
   }
 
   void DispatchDevToolsMessage(const std::string& message) {
-    agent()->OnDispatchOnInspectorBackend(17, message);
+    agent()->OnDispatchOnInspectorBackend(message);
   }
 
   void CloseWhilePaused() {
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.cc b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
index a099729..e1c640a 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.cc
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.cc
@@ -40,15 +40,13 @@
   return handled;
 }
 
-void EmbeddedWorkerDevToolsAgent::OnAttach(const std::string& host_id,
-                                           int session_id) {
-  webworker_->attachDevTools(WebString::fromUTF8(host_id), session_id);
+void EmbeddedWorkerDevToolsAgent::OnAttach(const std::string& host_id) {
+  webworker_->attachDevTools(WebString::fromUTF8(host_id));
 }
 
 void EmbeddedWorkerDevToolsAgent::OnReattach(const std::string& host_id,
-                                             int session_id,
                                              const std::string& state) {
-  webworker_->reattachDevTools(WebString::fromUTF8(host_id), session_id,
+  webworker_->reattachDevTools(WebString::fromUTF8(host_id),
                                WebString::fromUTF8(state));
 }
 
@@ -57,9 +55,8 @@
 }
 
 void EmbeddedWorkerDevToolsAgent::OnDispatchOnInspectorBackend(
-    int session_id,
     const std::string& message) {
-  webworker_->dispatchDevToolsMessage(session_id, WebString::fromUTF8(message));
+  webworker_->dispatchDevToolsMessage(WebString::fromUTF8(message));
 }
 
 }  // namespace content
diff --git a/content/renderer/service_worker/embedded_worker_devtools_agent.h b/content/renderer/service_worker/embedded_worker_devtools_agent.h
index c63081e..97c15824 100644
--- a/content/renderer/service_worker/embedded_worker_devtools_agent.h
+++ b/content/renderer/service_worker/embedded_worker_devtools_agent.h
@@ -30,12 +30,10 @@
   bool OnMessageReceived(const IPC::Message& message) override;
 
  private:
-  void OnAttach(const std::string& host_id, int session_id);
-  void OnReattach(const std::string& host_id,
-                  int session_id,
-                  const std::string& state);
+  void OnAttach(const std::string& host_id);
+  void OnReattach(const std::string& host_id, const std::string& state);
   void OnDetach();
-  void OnDispatchOnInspectorBackend(int session_id, const std::string& message);
+  void OnDispatchOnInspectorBackend(const std::string& message);
 
   blink::WebEmbeddedWorker* webworker_;
   int route_id_;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 8e556c0..f11338fb 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -468,13 +468,12 @@
 }
 
 void ServiceWorkerContextClient::sendDevToolsMessage(
-    int session_id,
     int call_id,
     const blink::WebString& message,
     const blink::WebString& state_cookie) {
   DevToolsAgent::SendChunkedProtocolMessage(
-      sender_.get(), worker_devtools_agent_route_id_, session_id, call_id,
-      message.utf8(), state_cookie.utf8());
+      sender_.get(), worker_devtools_agent_route_id_,
+      call_id, message.utf8(), state_cookie.utf8());
 }
 
 void ServiceWorkerContextClient::didHandleActivateEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 6223c7e..b3fd33d9 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -117,8 +117,7 @@
                             const blink::WebString& message,
                             int line_number,
                             const blink::WebString& source_url) override;
-  void sendDevToolsMessage(int session_id,
-                           int call_id,
+  void sendDevToolsMessage(int call_id,
                            const blink::WebString& message,
                            const blink::WebString& state) override;
   void didHandleActivateEvent(int request_id,
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 975bab9..934dade 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -253,12 +253,10 @@
 }
 
 void EmbeddedSharedWorkerStub::sendDevToolsMessage(
-    int session_id,
     int call_id,
     const blink::WebString& message,
     const blink::WebString& state) {
-  worker_devtools_agent_->SendDevToolsMessage(
-      session_id, call_id, message, state);
+  worker_devtools_agent_->SendDevToolsMessage(call_id, message, state);
 }
 
 void EmbeddedSharedWorkerStub::Shutdown() {
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.h b/content/renderer/shared_worker/embedded_shared_worker_stub.h
index a7d62d0..9f2c6c0 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.h
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.h
@@ -70,8 +70,7 @@
       const blink::WebSecurityOrigin& origin) override;
   blink::WebServiceWorkerNetworkProvider* createServiceWorkerNetworkProvider(
       blink::WebDataSource*) override;
-  void sendDevToolsMessage(int session_id,
-                           int call_id,
+  void sendDevToolsMessage(int call_id,
                            const blink::WebString& message,
                            const blink::WebString& state) override;
 
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 57719c6a..64cde4d 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -3413,16 +3413,16 @@
   'SwapBuffers': {
     'impl_func': False,
     'decoder_func': 'DoSwapBuffers',
-    'unit_test': False,
     'client_test': False,
+    'expectation': False,
     'extension': True,
     'trace_level': 1,
   },
   'SwapInterval': {
     'impl_func': False,
     'decoder_func': 'DoSwapInterval',
-    'unit_test': False,
     'client_test': False,
+    'expectation': False,
     'extension': True,
     'trace_level': 1,
   },
diff --git a/gpu/command_buffer/common/cmd_buffer_common.h b/gpu/command_buffer/common/cmd_buffer_common.h
index a2b8c5a..e8989be 100644
--- a/gpu/command_buffer/common/cmd_buffer_common.h
+++ b/gpu/command_buffer/common/cmd_buffer_common.h
@@ -100,7 +100,10 @@
               "kCommandBufferEntrySize");
 
 // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
-#pragma pack(push, GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT)
+#pragma pack(push, 4)
+static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4,
+              "pragma pack alignment must be equal to "
+              "GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT");
 
 // Gets the address of memory just after a structure in a typesafe way. This is
 // used for IMMEDIATE commands to get the address of the place to put the data.
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 05d1d48..dd42a95c 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -51,7 +51,10 @@
 namespace gles2 {
 
 // Command buffer is GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT byte aligned.
-#pragma pack(push, GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT)
+#pragma pack(push, 4)
+static_assert(GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT == 4,
+              "pragma pack alignment must be equal to "
+              "GPU_COMMAND_BUFFER_ENTRY_ALIGNMENT");
 
 namespace id_namespaces {
 
@@ -250,6 +253,12 @@
   base::subtle::Atomic32 disjoint_count;
 };
 
+static_assert(sizeof(QuerySync) == 12, "size of QuerySync should be 12");
+static_assert(offsetof(QuerySync, process_count) == 0,
+              "offset of QuerySync.process_count should be 0");
+static_assert(offsetof(QuerySync, result) == 4,
+              "offset of QuerySync.result should be 4");
+
 static_assert(sizeof(ProgramInput) == 20, "size of ProgramInput should be 20");
 static_assert(offsetof(ProgramInput, type) == 0,
               "offset of ProgramInput.type should be 0");
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 8c7fae8..e8b9eb6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -368,6 +368,14 @@
   EXPECT_EQ(GL_NO_ERROR, GetGLError());
 }
 
+TEST_P(GLES2DecoderTest3, SwapBuffersValidArgs) {
+  SpecializedSetup<cmds::SwapBuffers, 0>(true);
+  cmds::SwapBuffers cmd;
+  cmd.Init();
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
 TEST_P(GLES2DecoderTest3, IsValuebufferCHROMIUMValidArgs) {
   SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(true);
   cmds::IsValuebufferCHROMIUM cmd;
@@ -386,4 +394,12 @@
            kInvalidSharedMemoryOffset);
   EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
 }
+
+TEST_P(GLES2DecoderTest3, SwapIntervalValidArgs) {
+  SpecializedSetup<cmds::SwapInterval, 0>(true);
+  cmds::SwapInterval cmd;
+  cmd.Init(1);
+  EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+  EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
 #endif  // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/ios/chrome/browser/ui/legacy_size_class_support_util.h b/ios/chrome/browser/ui/legacy_size_class_support_util.h
index 6f578b9..a5eac62 100644
--- a/ios/chrome/browser/ui/legacy_size_class_support_util.h
+++ b/ios/chrome/browser/ui/legacy_size_class_support_util.h
@@ -9,8 +9,7 @@
 
 // Temporary functions for supporting size classes on pre-iOS8 devices.  The
 // return values are based on the bounds of the main UIScreen.
-// TODO(kkhorimoto): Remove once Chrome for iOS drops support for iOS7.
-// http://crbug.com/519568
+// TODO(crbug.com/519568): Remove once Chrome for iOS drops support for iOS7.
 SizeClassIdiom CurrentWidthSizeClass();
 SizeClassIdiom CurrentHeightSizeClass();
 
diff --git a/ios/chrome/browser/ui/reversed_animation.mm b/ios/chrome/browser/ui/reversed_animation.mm
index a46b0dc..58ce55b 100644
--- a/ios/chrome/browser/ui/reversed_animation.mm
+++ b/ios/chrome/browser/ui/reversed_animation.mm
@@ -225,8 +225,8 @@
                                                         parent:parent
                                                parentBeginTime:parentBeginTime];
   } else {
-    // TODO(kkhorimoto): Investigate possible general-case reversals.  It may
-    // be possible to implement this by manipulating the CAMediaTiming
+    // TODO(crbug.com/546202): Investigate possible general-case reversals.  It
+    // may be possible to implement this by manipulating the CAMediaTiming
     // properties.
   }
   return reversedAnimation;
diff --git a/ios/public/provider/web/web_controller_provider.h b/ios/public/provider/web/web_controller_provider.h
index 4d9f81ba..0845ad6 100644
--- a/ios/public/provider/web/web_controller_provider.h
+++ b/ios/public/provider/web/web_controller_provider.h
@@ -27,6 +27,8 @@
 
 // Interface that provides URL-loading and JavaScript injection with optional
 // dialog suppression.
+// TODO(crbug.com/546231): Remove once JS dialog suppression is exposed via
+// WebState's public interface.
 class WebControllerProvider {
  public:
   // Constructor for a WebControllerProvider backed by a CRWWebController
diff --git a/ios/web/navigation/crw_session_entry.h b/ios/web/navigation/crw_session_entry.h
index 01ff6c1..233c453 100644
--- a/ios/web/navigation/crw_session_entry.h
+++ b/ios/web/navigation/crw_session_entry.h
@@ -67,11 +67,6 @@
 @property(nonatomic, readonly) web::NavigationItem* navigationItem;
 
 // Pointer to the NavigationItemImpl associated with this CRWSessionEntry.
-// TODO(kkhorimoto): This is a convenience property to avoid requiring static
-// casts every time the web layer needs access to members only available in
-// NavigationItemImpl.  Remove once more navigation management moves into
-// NavigationManager and CRWSessionEntry=>web::NavigationItemImpl conversions
-// become less prominent.
 @property(nonatomic, readonly) web::NavigationItemImpl* navigationItemImpl;
 
 // Initialize the session entry with the given NavigationItem.
diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h
index c6b27e5..3ac47d2 100644
--- a/ios/web/navigation/navigation_manager_impl.h
+++ b/ios/web/navigation/navigation_manager_impl.h
@@ -117,7 +117,8 @@
 
   // Returns the current list of transient url rewriters, passing ownership to
   // the caller.
-  // TODO(kkhorimoto): remove once NavigationItem creation occurs in this class.
+  // TODO(crbug.com/546197): remove once NavigationItem creation occurs in this
+  // class.
   scoped_ptr<std::vector<BrowserURLRewriter::URLRewriter>>
   GetTransientURLRewriters();
 
diff --git a/ios/web/public/web_controller_factory.h b/ios/web/public/web_controller_factory.h
index 48fcf8e..574cd12 100644
--- a/ios/web/public/web_controller_factory.h
+++ b/ios/web/public/web_controller_factory.h
@@ -25,7 +25,7 @@
 // By requiring only the BrowserState, this eliminates the dependency on
 // WebStateImpl from components.
 // Note: Callers are responsible for releasing the returned web controller.
-// TODO(kkhorimoto): Move factory method to WebState once the ownership of
+// TODO(crbug.com/546221): Move factory method to WebState once the ownership of
 // WebState and CRWWebController is reversed.
 CRWWebController* CreateWebController(WebViewType web_view_type,
                                       BrowserState* browser_state);
diff --git a/ios/web/public/web_state/crw_web_view_proxy.h b/ios/web/public/web_state/crw_web_view_proxy.h
index acb0f7a..bdca40d1 100644
--- a/ios/web/public/web_state/crw_web_view_proxy.h
+++ b/ios/web/public/web_state/crw_web_view_proxy.h
@@ -13,7 +13,7 @@
 
 // Provides an interface for embedders to access the WebState's web view in a
 // limited and controlled manner.
-// TODO(kkhorimoto): rename protocol to CRWContentViewProxy.
+// TODO(crbug.com/546152): rename protocol to CRWContentViewProxy.
 @protocol CRWWebViewProxy<NSObject>
 
 // The web view's bounding rectangle (relative to its parent).
diff --git a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
index d46735e..592fb56e 100644
--- a/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
+++ b/ios/web/public/web_state/crw_web_view_scroll_view_proxy.h
@@ -20,7 +20,7 @@
 // needed.
 // The class forwards some of the methods onto the UIScrollView. For more
 // information look at the UIScrollView documentation.
-// TODO(kkhorimoto): rename class to CRWContentViewScrollViewProxy.
+// TODO(crbug.com/546152): rename class to CRWContentViewScrollViewProxy.
 @interface CRWWebViewScrollViewProxy : NSObject<UIScrollViewDelegate>
 @property(nonatomic, assign) CGPoint contentOffset;
 @property(nonatomic, assign) UIEdgeInsets contentInset;
diff --git a/ios/web/web_state/crw_web_view_proxy_impl.h b/ios/web/web_state/crw_web_view_proxy_impl.h
index f355d41..87b4d04f 100644
--- a/ios/web/web_state/crw_web_view_proxy_impl.h
+++ b/ios/web/web_state/crw_web_view_proxy_impl.h
@@ -12,7 +12,7 @@
 
 @class CRWWebController;
 
-// TODO(kkhorimoto): Rename class to CRWContentViewProxyImpl.
+// TODO(crbug.com/546152): Rename class to CRWContentViewProxyImpl.
 @interface CRWWebViewProxyImpl : NSObject<CRWWebViewProxy>
 
 // Used by CRWWebController to set the content view being managed.
diff --git a/ios/web/web_state/error_translation_util.mm b/ios/web/web_state/error_translation_util.mm
index c5fbb67..d939ee0 100644
--- a/ios/web/web_state/error_translation_util.mm
+++ b/ios/web/web_state/error_translation_util.mm
@@ -72,9 +72,9 @@
       *net_error_code = net::ERR_ABORTED;
       break;
     case kCFURLErrorUserAuthenticationRequired:
-      // TODO(kkhorimoto): ERR_SSL_RENEGOTIATION_REQUESTED is more specific than
-      // the kCFURLErrorUserAuthenticationRequired.  Consider adding a new net
-      // error for this scenario.
+      // TODO(crbug.com/546159): ERR_SSL_RENEGOTIATION_REQUESTED is more
+      // specific than the kCFURLErrorUserAuthenticationRequired.  Consider
+      // adding a new net error for this scenario.
       *net_error_code = net::ERR_SSL_RENEGOTIATION_REQUESTED;
       break;
     case kCFURLErrorZeroByteResource:
@@ -90,14 +90,14 @@
       *net_error_code = net::ERR_INVALID_RESPONSE;
       break;
     case kCFURLErrorInternationalRoamingOff:
-      // TODO(kkhorimoto): Create new net error for disabled intl roaming.
+      // TODO(crbug.com/546165): Create new net error for disabled intl roaming.
       *net_error_code = net::ERR_INTERNET_DISCONNECTED;
       break;
     case kCFURLErrorCallIsActive:
       *net_error_code = net::ERR_CONNECTION_FAILED;
       break;
     case kCFURLErrorDataNotAllowed:
-      // TODO(kkhorimoto): Create new net error for disabled data usage.
+      // TODO(crbug.com/546167): Create new net error for disabled data usage.
       *net_error_code = net::ERR_INTERNET_DISCONNECTED;
       break;
     case kCFURLErrorRequestBodyStreamExhausted:
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 14f76f50..c2ea6be 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -3327,7 +3327,7 @@
         scrollView.maximumZoomScale);
     displayState.zoom_state().set_zoom_scale(scrollView.zoomScale);
   } else {
-    // TODO(kkhorimoto): Handle native views.
+    // TODO(crbug.com/546146): Handle native views.
   }
   return displayState;
 }
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm
index 86211b60..4a119f9 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -161,11 +161,6 @@
 
 - (void)setNativeController:(id<CRWNativeContent>)nativeController {
   if (![_nativeController isEqual:nativeController]) {
-    // TODO(kkhorimoto): This line isn't strictly necessary since all native
-    // controllers currently inherit from NativeContentController, which removes
-    // its view upon deallocation.  Consider moving NativeContentController into
-    // web/ so this behavior can be depended upon from within web/ without
-    // making assumptions about chrome/ code.
     base::WeakNSProtocol<id> oldController(_nativeController);
     [[_nativeController view] removeFromSuperview];
     _nativeController.reset([nativeController retain]);
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index 7dcae774..315fe701 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -1529,11 +1529,11 @@
                           (void (^)(WKNavigationResponsePolicy))handler {
   if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
     // Create HTTP headers from the response.
-    // TODO(kkhorimoto): Due to the limited interface of NSHTTPURLResponse, some
-    // data in the HttpResponseHeaders generated here is inexact.  Once
-    // UIWebView is no longer supported, update WebState's implementation so
-    // that the Content-Language and the MIME type can be set without using this
-    // imperfect conversion.
+    // TODO(crbug.com/546157): Due to the limited interface of
+    // NSHTTPURLResponse, some data in the HttpResponseHeaders generated here is
+    // inexact.  Once UIWebView is no longer supported, update WebState's
+    // implementation so that the Content-Language and the MIME type can be set
+    // without using this imperfect conversion.
     scoped_refptr<net::HttpResponseHeaders> HTTPHeaders =
         net::CreateHeadersFromNSHTTPURLResponse(
             static_cast<NSHTTPURLResponse*>(navigationResponse.response));
diff --git a/ipc/mojo/scoped_ipc_support.cc b/ipc/mojo/scoped_ipc_support.cc
index 2465aa2..58ee518 100644
--- a/ipc/mojo/scoped_ipc_support.cc
+++ b/ipc/mojo/scoped_ipc_support.cc
@@ -104,8 +104,8 @@
     io_thread_task_runner_->PostTask(
         FROM_HERE, base::Bind(&WatchMessageLoopOnIOThread, observer_));
     mojo::embedder::InitIPCSupport(
-        mojo::embedder::ProcessType::NONE, io_thread_task_runner_, this,
-        io_thread_task_runner_, mojo::embedder::ScopedPlatformHandle());
+        mojo::embedder::ProcessType::NONE, this, io_thread_task_runner_,
+        mojo::embedder::ScopedPlatformHandle());
   }
 }
 
diff --git a/media/base/audio_renderer.h b/media/base/audio_renderer.h
index 586936a..aa59bf30 100644
--- a/media/base/audio_renderer.h
+++ b/media/base/audio_renderer.h
@@ -8,7 +8,7 @@
 #include "base/callback.h"
 #include "base/time/time.h"
 #include "media/base/buffering_state.h"
-#include "media/base/decryptor.h"
+#include "media/base/cdm_context.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 
@@ -28,8 +28,8 @@
   // completion. If initialization fails, only |init_cb| (not |error_cb|) will
   // be called.
   //
-  // |set_decryptor_ready_cb| is fired when a Decryptor is needed, i.e. when the
-  // |stream| is encrypted.
+  // |set_cdm_ready_cb| is fired when a CDM is needed, i.e. when the |stream| is
+  // encrypted.
   //
   // |statistics_cb| is executed periodically with audio rendering stats.
   //
@@ -45,7 +45,7 @@
   virtual void Initialize(
       DemuxerStream* stream,
       const PipelineStatusCB& init_cb,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const StatisticsCB& statistics_cb,
       const BufferingStateCB& buffering_state_cb,
       const base::Closure& ended_cb,
diff --git a/media/base/cdm_context.h b/media/base/cdm_context.h
index 7d89760..c64f276e 100644
--- a/media/base/cdm_context.h
+++ b/media/base/cdm_context.h
@@ -68,6 +68,19 @@
 // A dummy implementation of CdmAttachedCB.
 MEDIA_EXPORT void IgnoreCdmAttached(bool success);
 
+// Callback to notify that a CDM is ready. CdmAttachedCB is called when the CDM
+// has been completely attached to the media pipeline.
+typedef base::Callback<void(CdmContext*, const CdmAttachedCB&)> CdmReadyCB;
+
+// Callback to set/cancel a CdmReadyCB.
+// Calling this callback with a non-null callback registers CDM ready
+// notification. When the CDM is ready, notification will be sent
+// through the provided callback.
+// Calling this callback with a null callback cancels previously registered CDM
+// ready notification. Any previously provided callback will be fired
+// immediately with NULL.
+typedef base::Callback<void(const CdmReadyCB&)> SetCdmReadyCB;
+
 }  // namespace media
 
 #endif  // MEDIA_BASE_CDM_CONTEXT_H_
diff --git a/media/base/decryptor.h b/media/base/decryptor.h
index 47b4645..f0d8be8 100644
--- a/media/base/decryptor.h
+++ b/media/base/decryptor.h
@@ -163,24 +163,6 @@
   DISALLOW_COPY_AND_ASSIGN(Decryptor);
 };
 
-// Callback to notify that the decryptor has been completely attached into the
-// pipeline. Parameter indicates whether the operation succeeded.
-typedef base::Callback<void(bool)> DecryptorAttachedCB;
-
-// Callback to notify that a decryptor is ready. DecryptorAttachedCB is called
-// when the decryptor has been completely inserted into the pipeline.
-typedef base::Callback<void(Decryptor*, const DecryptorAttachedCB&)>
-    DecryptorReadyCB;
-
-// Callback to set/cancel a DecryptorReadyCB.
-// Calling this callback with a non-null callback registers decryptor ready
-// notification. When the decryptor is ready, notification will be sent
-// through the provided callback.
-// Calling this callback with a null callback cancels previously registered
-// decryptor ready notification. Any previously provided callback will be
-// fired immediately with NULL.
-typedef base::Callback<void(const DecryptorReadyCB&)> SetDecryptorReadyCB;
-
 }  // namespace media
 
 #endif  // MEDIA_BASE_DECRYPTOR_H_
diff --git a/media/base/mock_filters.cc b/media/base/mock_filters.cc
index f9fd4b5..98c23be9 100644
--- a/media/base/mock_filters.cc
+++ b/media/base/mock_filters.cc
@@ -108,4 +108,12 @@
 
 MockDecryptor::~MockDecryptor() {}
 
+MockCdmContext::MockCdmContext() {}
+
+MockCdmContext::~MockCdmContext() {}
+
+int MockCdmContext::GetCdmId() const {
+  return CdmContext::kInvalidCdmId;
+}
+
 }  // namespace media
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index dffbab0..5fb2a3e 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -8,9 +8,11 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/macros.h"
 #include "media/base/audio_decoder.h"
 #include "media/base/audio_decoder_config.h"
 #include "media/base/audio_renderer.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decryptor.h"
 #include "media/base/demuxer.h"
@@ -127,7 +129,7 @@
   MOCK_METHOD9(Initialize,
                void(DemuxerStream* stream,
                     const PipelineStatusCB& init_cb,
-                    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                    const SetCdmReadyCB& set_cdm_ready_cb,
                     const StatisticsCB& statistics_cb,
                     const BufferingStateCB& buffering_state_cb,
                     const base::Closure& ended_cb,
@@ -151,7 +153,7 @@
   MOCK_METHOD8(Initialize,
                void(DemuxerStream* stream,
                     const PipelineStatusCB& init_cb,
-                    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                    const SetCdmReadyCB& set_cdm_ready_cb,
                     const StatisticsCB& statistics_cb,
                     const BufferingStateCB& buffering_state_cb,
                     const base::Closure& ended_cb,
@@ -259,6 +261,18 @@
   DISALLOW_COPY_AND_ASSIGN(MockDecryptor);
 };
 
+class MockCdmContext : public CdmContext {
+ public:
+  MockCdmContext();
+  ~MockCdmContext() override;
+
+  MOCK_METHOD0(GetDecryptor, Decryptor*());
+  int GetCdmId() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockCdmContext);
+};
+
 }  // namespace media
 
 #endif  // MEDIA_BASE_MOCK_FILTERS_H_
diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h
index 454c66441..d85ec60c 100644
--- a/media/base/video_renderer.h
+++ b/media/base/video_renderer.h
@@ -9,7 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "media/base/buffering_state.h"
-#include "media/base/decryptor.h"
+#include "media/base/cdm_context.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 #include "media/base/time_source.h"
@@ -34,8 +34,8 @@
   // completion. If initialization fails, only |init_cb| (not |error_cb|) will
   // be called.
   //
-  // |set_decryptor_ready_cb| is fired when a Decryptor is needed, i.e. when the
-  // |stream| is encrypted.
+  // |set_cdm_ready_cb| is fired when a CDM is needed, i.e. when the |stream| is
+  // encrypted.
   //
   // |statistics_cb| is executed periodically with video rendering stats, such
   // as dropped frames.
@@ -55,7 +55,7 @@
   virtual void Initialize(
       DemuxerStream* stream,
       const PipelineStatusCB& init_cb,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const StatisticsCB& statistics_cb,
       const BufferingStateCB& buffering_state_cb,
       const base::Closure& ended_cb,
diff --git a/media/blink/run_all_unittests.cc b/media/blink/run_all_unittests.cc
index 787091b..cc8c0ed32 100644
--- a/media/blink/run_all_unittests.cc
+++ b/media/blink/run_all_unittests.cc
@@ -4,6 +4,7 @@
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "build/build_config.h"
@@ -82,6 +83,7 @@
 void TestBlinkPlatformSupport::cryptographicallyRandomValues(
     unsigned char* buffer,
     size_t length) {
+  base::RandBytes(buffer, length);
 }
 
 const unsigned char* TestBlinkPlatformSupport::getTraceCategoryEnabledFlag(
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 6e248fe..b2b8a8a 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -26,10 +26,10 @@
 // times across multiple test files. Sadly we can't use static for them.
 namespace {
 
-ACTION_P3(ExecuteCallbackWithVerifier, decryptor, done_cb, verifier) {
+ACTION_P3(ExecuteCallbackWithVerifier, cdm_context, done_cb, verifier) {
   // verifier must be called first since |done_cb| call will invoke it as well.
   verifier->RecordACalled();
-  arg0.Run(decryptor, done_cb);
+  arg0.Run(cdm_context, done_cb);
 }
 
 ACTION_P(ReportCallback, verifier) {
@@ -62,6 +62,7 @@
   AudioDecoderSelectorTest()
       : demuxer_stream_(
             new StrictMock<MockDemuxerStream>(DemuxerStream::AUDIO)),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new NiceMock<MockDecryptor>()),
         decoder_1_(new StrictMock<MockAudioDecoder>()),
         decoder_2_(new StrictMock<MockAudioDecoder>()) {
@@ -73,10 +74,10 @@
     message_loop_.RunUntilIdle();
   }
 
-  MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
+  MOCK_METHOD1(SetCdmReadyCallback, void(const CdmReadyCB&));
   MOCK_METHOD2(OnDecoderSelected,
                void(AudioDecoder*, DecryptingDemuxerStream*));
-  MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD1(CdmSet, void(bool));
 
   void MockOnDecoderSelected(scoped_ptr<AudioDecoder> decoder,
                              scoped_ptr<DecryptingDemuxerStream> stream) {
@@ -102,13 +103,15 @@
                                  int num_decoders) {
     if (decryptor_capability == kDecryptOnly ||
         decryptor_capability == kDecryptAndDecode) {
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
+      EXPECT_CALL(*cdm_context_, GetDecryptor())
+          .WillRepeatedly(Return(decryptor_.get()));
+
+      EXPECT_CALL(*this, SetCdmReadyCallback(_))
           .WillRepeatedly(ExecuteCallbackWithVerifier(
-              decryptor_.get(),
-              base::Bind(&AudioDecoderSelectorTest::DecryptorSet,
-                         base::Unretained(this)),
+              cdm_context_.get(), base::Bind(&AudioDecoderSelectorTest::CdmSet,
+                                             base::Unretained(this)),
               &verifier_));
-      EXPECT_CALL(*this, DecryptorSet(true))
+      EXPECT_CALL(*this, CdmSet(true))
           .WillRepeatedly(ReportCallback(&verifier_));
 
       if (decryptor_capability == kDecryptOnly) {
@@ -119,11 +122,10 @@
             .WillRepeatedly(RunCallback<1>(true));
       }
     } else if (decryptor_capability == kHoldSetDecryptor) {
-      // Set and cancel DecryptorReadyCB but the callback is never fired.
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
-          .Times(2);
+      // Set and cancel CdmReadyCB but the callback is never fired.
+      EXPECT_CALL(*this, SetCdmReadyCallback(_)).Times(2);
     } else if (decryptor_capability == kNoDecryptor) {
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
+      EXPECT_CALL(*this, SetCdmReadyCallback(_))
           .WillRepeatedly(
               RunCallback<0>(nullptr, base::Bind(&IgnoreCdmAttached)));
     }
@@ -140,7 +142,7 @@
   void SelectDecoder() {
     decoder_selector_->SelectDecoder(
         demuxer_stream_.get(),
-        base::Bind(&AudioDecoderSelectorTest::SetDecryptorReadyCallback,
+        base::Bind(&AudioDecoderSelectorTest::SetCdmReadyCallback,
                    base::Unretained(this)),
         base::Bind(&AudioDecoderSelectorTest::MockOnDecoderSelected,
                    base::Unretained(this)),
@@ -167,11 +169,12 @@
 
   // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since
   // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|.
-  scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
+  scoped_ptr<StrictMock<MockDemuxerStream>> demuxer_stream_;
 
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
   // Use NiceMock since we don't care about most of calls on the decryptor, e.g.
   // RegisterNewKeyCB().
-  scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
+  scoped_ptr<NiceMock<MockDecryptor>> decryptor_;
 
   scoped_ptr<AudioDecoderSelector> decoder_selector_;
 
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index 7fcc234..0f99e79 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -78,7 +78,7 @@
 template <DemuxerStream::Type StreamType>
 void DecoderSelector<StreamType>::SelectDecoder(
     DemuxerStream* stream,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const SelectDecoderCB& select_decoder_cb,
     const typename Decoder::OutputCB& output_cb,
     const base::Closure& waiting_for_decryption_key_cb) {
@@ -87,7 +87,7 @@
   DCHECK(stream);
   DCHECK(select_decoder_cb_.is_null());
 
-  set_decryptor_ready_cb_ = set_decryptor_ready_cb;
+  set_cdm_ready_cb_ = set_cdm_ready_cb;
   waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
   // Make sure |select_decoder_cb| runs on a different execution stack.
@@ -109,7 +109,7 @@
 
   // This could be null during fallback after decoder reinitialization failure.
   // See DecoderStream<StreamType>::OnDecoderReinitialized().
-  if (set_decryptor_ready_cb_.is_null()) {
+  if (set_cdm_ready_cb_.is_null()) {
     ReturnNullDecoder();
     return;
   }
@@ -125,7 +125,7 @@
 template <DemuxerStream::Type StreamType>
 void DecoderSelector<StreamType>::InitializeDecryptingDecoder() {
   decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
-      task_runner_, media_log_, set_decryptor_ready_cb_,
+      task_runner_, media_log_, set_cdm_ready_cb_,
       waiting_for_decryption_key_cb_));
 
   DecoderStreamTraits<StreamType>::InitializeDecoder(
@@ -156,9 +156,9 @@
 
 template <DemuxerStream::Type StreamType>
 void DecoderSelector<StreamType>::InitializeDecryptingDemuxerStream() {
-  decrypted_stream_.reset(new DecryptingDemuxerStream(
-      task_runner_, media_log_, set_decryptor_ready_cb_,
-      waiting_for_decryption_key_cb_));
+  decrypted_stream_.reset(
+      new DecryptingDemuxerStream(task_runner_, media_log_, set_cdm_ready_cb_,
+                                  waiting_for_decryption_key_cb_));
 
   decrypted_stream_->Initialize(
       input_stream_,
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h
index 6db6061a..c8a8ff9 100644
--- a/media/filters/decoder_selector.h
+++ b/media/filters/decoder_selector.h
@@ -9,7 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
-#include "media/base/decryptor.h"
+#include "media/base/cdm_context.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/pipeline_status.h"
 #include "media/filters/decoder_stream_traits.h"
@@ -22,7 +22,6 @@
 
 class DecoderBuffer;
 class DecryptingDemuxerStream;
-class Decryptor;
 class MediaLog;
 
 // DecoderSelector (creates if necessary and) initializes the proper
@@ -67,10 +66,10 @@
   // 1. This must not be called again before |select_decoder_cb| is run.
   // 2. Decoders that fail to initialize will be deleted. Future calls will
   //    select from the decoders following the decoder that was last returned.
-  // 3. |set_decryptor_ready_cb| is optional. If |set_decryptor_ready_cb| is
-  //    null, no decryptor will be available to perform decryption.
+  // 3. |set_cdm_ready_cb| is optional. If |set_cdm_ready_cb| is
+  //    null, no CDM will be available to perform decryption.
   void SelectDecoder(DemuxerStream* stream,
-                     const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                     const SetCdmReadyCB& set_cdm_ready_cb,
                      const SelectDecoderCB& select_decoder_cb,
                      const typename Decoder::OutputCB& output_cb,
                      const base::Closure& waiting_for_decryption_key_cb);
@@ -91,7 +90,7 @@
   scoped_refptr<MediaLog> media_log_;
 
   DemuxerStream* input_stream_;
-  SetDecryptorReadyCB set_decryptor_ready_cb_;
+  SetCdmReadyCB set_cdm_ready_cb_;
   SelectDecoderCB select_decoder_cb_;
   typename Decoder::OutputCB output_cb_;
   base::Closure waiting_for_decryption_key_cb_;
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index e601da4..91a5b1e1 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -89,7 +89,7 @@
 void DecoderStream<StreamType>::Initialize(
     DemuxerStream* stream,
     const InitCB& init_cb,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const StatisticsCB& statistics_cb,
     const base::Closure& waiting_for_decryption_key_cb) {
   FUNCTION_DVLOG(2);
@@ -104,7 +104,7 @@
   stream_ = stream;
 
   state_ = STATE_INITIALIZING;
-  SelectDecoder(set_decryptor_ready_cb);
+  SelectDecoder(set_cdm_ready_cb);
 }
 
 template <DemuxerStream::Type StreamType>
@@ -215,9 +215,9 @@
 
 template <DemuxerStream::Type StreamType>
 void DecoderStream<StreamType>::SelectDecoder(
-    const SetDecryptorReadyCB& set_decryptor_ready_cb) {
+    const SetCdmReadyCB& set_cdm_ready_cb) {
   decoder_selector_->SelectDecoder(
-      stream_, set_decryptor_ready_cb,
+      stream_, set_cdm_ready_cb,
       base::Bind(&DecoderStream<StreamType>::OnDecoderSelected,
                  weak_factory_.GetWeakPtr()),
       base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
@@ -542,7 +542,7 @@
     // once is safe.
     // For simplicity, don't attempt to fall back to a decryptor. Calling this
     // with a null callback ensures that one won't be selected.
-    SelectDecoder(SetDecryptorReadyCB());
+    SelectDecoder(SetCdmReadyCB());
   } else {
     CompleteDecoderReinitialization(true);
   }
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index d5205f3..94b6b7b 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -5,6 +5,8 @@
 #ifndef MEDIA_FILTERS_DECODER_STREAM_H_
 #define MEDIA_FILTERS_DECODER_STREAM_H_
 
+#include <list>
+
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -12,7 +14,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/audio_decoder.h"
-#include "media/base/decryptor.h"
+#include "media/base/cdm_context.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/media_export.h"
 #include "media/base/media_log.h"
@@ -65,7 +67,7 @@
   // through |init_cb|. Note that |init_cb| is always called asynchronously.
   void Initialize(DemuxerStream* stream,
                   const InitCB& init_cb,
-                  const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const StatisticsCB& statistics_cb,
                   const base::Closure& waiting_for_decryption_key_cb);
 
@@ -129,7 +131,7 @@
     STATE_ERROR
   };
 
-  void SelectDecoder(const SetDecryptorReadyCB& set_decryptor_ready_cb);
+  void SelectDecoder(const SetCdmReadyCB& set_cdm_ready_cb);
 
   // Called when |decoder_selector| selected the |selected_decoder|.
   // |decrypting_demuxer_stream| was also populated if a DecryptingDemuxerStream
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 52a85f1..1c620a7 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -34,17 +34,16 @@
 DecryptingAudioDecoder::DecryptingAudioDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
-      set_decryptor_ready_cb_(set_decryptor_ready_cb),
+      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
-      weak_factory_(this) {
-}
+      weak_factory_(this) {}
 
 std::string DecryptingAudioDecoder::GetDisplayName() const {
   return "DecryptingAudioDecoder";
@@ -78,8 +77,8 @@
 
   if (state_ == kUninitialized) {
     state_ = kDecryptorRequested;
-    set_decryptor_ready_cb_.Run(BindToCurrentLoop(
-        base::Bind(&DecryptingAudioDecoder::SetDecryptor, weak_this_)));
+    set_cdm_ready_cb_.Run(BindToCurrentLoop(
+        base::Bind(&DecryptingAudioDecoder::SetCdm, weak_this_)));
     return;
   }
 
@@ -161,8 +160,8 @@
     decryptor_->DeinitializeDecoder(Decryptor::kAudio);
     decryptor_ = NULL;
   }
-  if (!set_decryptor_ready_cb_.is_null())
-    base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
+  if (!set_cdm_ready_cb_.is_null())
+    base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB());
   pending_buffer_to_decode_ = NULL;
   if (!init_cb_.is_null())
     base::ResetAndReturn(&init_cb_).Run(false);
@@ -172,29 +171,28 @@
     base::ResetAndReturn(&reset_cb_).Run();
 }
 
-void DecryptingAudioDecoder::SetDecryptor(
-    Decryptor* decryptor,
-    const DecryptorAttachedCB& decryptor_attached_cb) {
-  DVLOG(2) << "SetDecryptor()";
+void DecryptingAudioDecoder::SetCdm(CdmContext* cdm_context,
+                                    const CdmAttachedCB& cdm_attached_cb) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kDecryptorRequested) << state_;
   DCHECK(!init_cb_.is_null());
-  DCHECK(!set_decryptor_ready_cb_.is_null());
+  DCHECK(!set_cdm_ready_cb_.is_null());
 
-  set_decryptor_ready_cb_.Reset();
+  set_cdm_ready_cb_.Reset();
 
-  if (!decryptor) {
+  if (!cdm_context || !cdm_context->GetDecryptor()) {
     MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no decryptor set";
     base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
-    decryptor_attached_cb.Run(false);
+    cdm_attached_cb.Run(false);
     return;
   }
 
-  decryptor_ = decryptor;
+  decryptor_ = cdm_context->GetDecryptor();
 
   InitializeDecoder();
-  decryptor_attached_cb.Run(true);
+  cdm_attached_cb.Run(true);
 }
 
 void DecryptingAudioDecoder::InitializeDecoder() {
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h
index 7919172..b566fdd 100644
--- a/media/filters/decrypting_audio_decoder.h
+++ b/media/filters/decrypting_audio_decoder.h
@@ -11,6 +11,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "media/base/audio_decoder.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decryptor.h"
 #include "media/base/demuxer_stream.h"
 
@@ -34,7 +35,7 @@
   DecryptingAudioDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingAudioDecoder() override;
 
@@ -63,10 +64,9 @@
     kError
   };
 
-  // Callback for DecryptorHost::RequestDecryptor(). |decryptor_attached_cb| is
-  // called when the decryptor has been completely attached to the pipeline.
-  void SetDecryptor(Decryptor* decryptor,
-                    const DecryptorAttachedCB& decryptor_attached_cb);
+  // Callback to set CDM. |cdm_attached_cb| is called when the decryptor in the
+  // CDM has been completely attached to the pipeline.
+  void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
 
   // Initializes the audio decoder on the |decryptor_| with |config_|.
   void InitializeDecoder();
@@ -106,8 +106,8 @@
   // The current decoder configuration.
   AudioDecoderConfig config_;
 
-  // Callback to request/cancel decryptor creation notification.
-  SetDecryptorReadyCB set_decryptor_ready_cb_;
+  // Callback to request/cancel CDM ready notification.
+  SetCdmReadyCB set_cdm_ready_cb_;
 
   Decryptor* decryptor_;
 
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index 4f749cea..016e09a4c 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -21,6 +21,7 @@
 
 using ::testing::_;
 using ::testing::AtMost;
+using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::StrictMock;
 
@@ -63,11 +64,11 @@
       : decoder_(new DecryptingAudioDecoder(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(
-                &DecryptingAudioDecoderTest::RequestDecryptorNotification,
-                base::Unretained(this)),
+            base::Bind(&DecryptingAudioDecoderTest::RequestCdmNotification,
+                       base::Unretained(this)),
             base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new StrictMock<MockDecryptor>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
@@ -76,8 +77,7 @@
         decoded_frame_list_() {}
 
   virtual ~DecryptingAudioDecoderTest() {
-    EXPECT_CALL(*this, RequestDecryptorNotification(_))
-        .Times(testing::AnyNumber());
+    EXPECT_CALL(*this, RequestCdmNotification(_)).Times(testing::AnyNumber());
     Destroy();
   }
 
@@ -102,19 +102,30 @@
     message_loop_.RunUntilIdle();
   }
 
-  void ExpectDecryptorNotification(Decryptor* decryptor, bool expected_result) {
-    EXPECT_CALL(*this, RequestDecryptorNotification(_)).WillOnce(
-        RunCallback<0>(decryptor,
-                       base::Bind(&DecryptingAudioDecoderTest::DecryptorSet,
-                                  base::Unretained(this))));
-    EXPECT_CALL(*this, DecryptorSet(expected_result));
+  enum CdmType { NO_CDM, CDM_WITHOUT_DECRYPTOR, CDM_WITH_DECRYPTOR };
+
+  void SetCdmType(CdmType cdm_type) {
+    const bool has_cdm = cdm_type != NO_CDM;
+    const bool has_decryptor = cdm_type == CDM_WITH_DECRYPTOR;
+
+    EXPECT_CALL(*this, RequestCdmNotification(_))
+        .WillOnce(RunCallback<0>(has_cdm ? cdm_context_.get() : nullptr,
+                                 base::Bind(&DecryptingAudioDecoderTest::CdmSet,
+                                            base::Unretained(this))));
+
+    if (has_cdm) {
+      EXPECT_CALL(*cdm_context_, GetDecryptor())
+          .WillRepeatedly(Return(has_decryptor ? decryptor_.get() : nullptr));
+    }
+
+    EXPECT_CALL(*this, CdmSet(has_decryptor));
   }
 
   void Initialize() {
+    SetCdmType(CDM_WITH_DECRYPTOR);
     EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
         .Times(AtMost(1))
         .WillOnce(RunCallback<1>(true));
-    ExpectDecryptorNotification(decryptor_.get(), true);
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
@@ -250,18 +261,19 @@
     message_loop_.RunUntilIdle();
   }
 
-  MOCK_METHOD1(RequestDecryptorNotification, void(const DecryptorReadyCB&));
+  MOCK_METHOD1(RequestCdmNotification, void(const CdmReadyCB&));
 
   MOCK_METHOD1(FrameReady, void(const scoped_refptr<AudioBuffer>&));
   MOCK_METHOD1(DecodeDone, void(AudioDecoder::Status));
 
-  MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD1(CdmSet, void(bool));
 
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingAudioDecoder> decoder_;
-  scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
+  scoped_ptr<StrictMock<MockDecryptor>> decryptor_;
   AudioDecoderConfig config_;
 
   // Variables to help the |decryptor_| to simulate decoding delay and flushing.
@@ -304,9 +316,9 @@
 
 // Ensure decoder handles unsupported audio configs without crashing.
 TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
+  SetCdmType(CDM_WITH_DECRYPTOR);
   EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
       .WillOnce(RunCallback<1>(false));
-  ExpectDecryptorNotification(decryptor_.get(), true);
 
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
                             CHANNEL_LAYOUT_STEREO, kSampleRate,
@@ -314,8 +326,16 @@
   InitializeAndExpectResult(config, false);
 }
 
-TEST_F(DecryptingAudioDecoderTest, Initialize_NullDecryptor) {
-  ExpectDecryptorNotification(NULL, false);
+TEST_F(DecryptingAudioDecoderTest, Initialize_NoCdm) {
+  SetCdmType(NO_CDM);
+  AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+                            CHANNEL_LAYOUT_STEREO, kSampleRate,
+                            EmptyExtraData(), true);
+  InitializeAndExpectResult(config, false);
+}
+
+TEST_F(DecryptingAudioDecoderTest, Initialize_CdmWithoutDecryptor) {
+  SetCdmType(CDM_WITHOUT_DECRYPTOR);
   AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
                             CHANNEL_LAYOUT_STEREO, kSampleRate,
                             EmptyExtraData(), true);
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 3e67a29c..2189545 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -28,18 +28,17 @@
 DecryptingDemuxerStream::DecryptingDemuxerStream(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       demuxer_stream_(NULL),
-      set_decryptor_ready_cb_(set_decryptor_ready_cb),
+      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decrypt_pending_(false),
-      weak_factory_(this) {
-}
+      weak_factory_(this) {}
 
 std::string DecryptingDemuxerStream::GetDisplayName() const {
   return "DecryptingDemuxerStream";
@@ -59,8 +58,8 @@
   InitializeDecoderConfig();
 
   state_ = kDecryptorRequested;
-  set_decryptor_ready_cb_.Run(BindToCurrentLoop(
-      base::Bind(&DecryptingDemuxerStream::SetDecryptor, weak_this_)));
+  set_cdm_ready_cb_.Run(BindToCurrentLoop(
+      base::Bind(&DecryptingDemuxerStream::SetCdm, weak_this_)));
 }
 
 void DecryptingDemuxerStream::Read(const ReadCB& read_cb) {
@@ -88,7 +87,7 @@
   // condition and clean up related tests.
   if (state_ == kDecryptorRequested) {
     DCHECK(!init_cb_.is_null());
-    set_decryptor_ready_cb_.Run(DecryptorReadyCB());
+    set_cdm_ready_cb_.Run(CdmReadyCB());
     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
     DoReset();
     return;
@@ -160,8 +159,8 @@
     decryptor_->CancelDecrypt(GetDecryptorStreamType());
     decryptor_ = NULL;
   }
-  if (!set_decryptor_ready_cb_.is_null())
-    base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
+  if (!set_cdm_ready_cb_.is_null())
+    base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB());
   if (!init_cb_.is_null())
     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
   if (!read_cb_.is_null())
@@ -171,26 +170,25 @@
   pending_buffer_to_decrypt_ = NULL;
 }
 
-void DecryptingDemuxerStream::SetDecryptor(
-    Decryptor* decryptor,
-    const DecryptorAttachedCB& decryptor_attached_cb) {
+void DecryptingDemuxerStream::SetCdm(CdmContext* cdm_context,
+                                     const CdmAttachedCB& cdm_attached_cb) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kDecryptorRequested) << state_;
   DCHECK(!init_cb_.is_null());
-  DCHECK(!set_decryptor_ready_cb_.is_null());
+  DCHECK(!set_cdm_ready_cb_.is_null());
 
-  set_decryptor_ready_cb_.Reset();
+  set_cdm_ready_cb_.Reset();
 
-  if (!decryptor) {
+  if (!cdm_context || !cdm_context->GetDecryptor()) {
     MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": decryptor not set";
     state_ = kUninitialized;
     base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
-    decryptor_attached_cb.Run(false);
+    cdm_attached_cb.Run(false);
     return;
   }
 
-  decryptor_ = decryptor;
+  decryptor_ = cdm_context->GetDecryptor();
 
   decryptor_->RegisterNewKeyCB(
       GetDecryptorStreamType(),
@@ -199,7 +197,7 @@
 
   state_ = kIdle;
   base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
-  decryptor_attached_cb.Run(true);
+  cdm_attached_cb.Run(true);
 }
 
 void DecryptingDemuxerStream::DecryptBuffer(
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index a04709e..88f86a2 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decryptor.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/pipeline_status.h"
@@ -32,14 +33,13 @@
   DecryptingDemuxerStream(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
 
   // Cancels all pending operations immediately and fires all pending callbacks.
   ~DecryptingDemuxerStream() override;
 
-  void Initialize(DemuxerStream* stream,
-                  const PipelineStatusCB& status_cb);
+  void Initialize(DemuxerStream* stream, const PipelineStatusCB& status_cb);
 
   // Cancels all pending operations and fires all pending callbacks. If in
   // kPendingDemuxerRead or kPendingDecrypt state, waits for the pending
@@ -74,10 +74,9 @@
     kWaitingForKey
   };
 
-  // Callback for DecryptorHost::RequestDecryptor(). |decryptor_attached_cb| is
-  // called when the decryptor has been completely attached to the pipeline.
-  void SetDecryptor(Decryptor* decryptor,
-                    const DecryptorAttachedCB& decryptor_attached_cb);
+  // Callback to set CDM. |cdm_attached_cb| is called when the decryptor in the
+  // CDM has been completely attached to the pipeline.
+  void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
 
   // Callback for DemuxerStream::Read().
   void DecryptBuffer(DemuxerStream::Status status,
@@ -120,8 +119,8 @@
   AudioDecoderConfig audio_config_;
   VideoDecoderConfig video_config_;
 
-  // Callback to request/cancel decryptor creation notification.
-  SetDecryptorReadyCB set_decryptor_ready_cb_;
+  // Callback to request/cancel CDM ready notification.
+  SetCdmReadyCB set_cdm_ready_cb_;
 
   Decryptor* decryptor_;
 
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index c679b56..7275029 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -51,20 +51,6 @@
   arg0.Run(buffer.get() ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
 }
 
-// Sets the |decryptor| if the DecryptorReadyCB (arg0) is not null. Sets
-// |is_decryptor_set| to true if a non-NULL |decryptor| has been set through the
-// callback.
-ACTION_P3(SetDecryptorIfNotNull, decryptor, done_cb, is_decryptor_set) {
-  if (!arg0.is_null())
-    arg0.Run(decryptor, done_cb);
-
-  *is_decryptor_set = !arg0.is_null() && decryptor;
-}
-
-ACTION_P2(ResetAndRunCallback, callback, param) {
-  base::ResetAndReturn(callback).Run(param);
-}
-
 MATCHER(IsEndOfStream, "end of stream") {
   return arg->end_of_stream();
 }
@@ -77,13 +63,13 @@
       : demuxer_stream_(new DecryptingDemuxerStream(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(
-                &DecryptingDemuxerStreamTest::RequestDecryptorNotification,
-                base::Unretained(this)),
+            base::Bind(&DecryptingDemuxerStreamTest::RequestCdmNotification,
+                       base::Unretained(this)),
             base::Bind(&DecryptingDemuxerStreamTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new StrictMock<MockDecryptor>()),
-        is_decryptor_set_(false),
+        is_cdm_set_(false),
         input_audio_stream_(
             new StrictMock<MockDemuxerStream>(DemuxerStream::AUDIO)),
         input_video_stream_(
@@ -93,7 +79,7 @@
         decrypted_buffer_(new DecoderBuffer(kFakeBufferSize)) {}
 
   virtual ~DecryptingDemuxerStreamTest() {
-    if (is_decryptor_set_)
+    if (is_cdm_set_)
       EXPECT_CALL(*decryptor_, CancelDecrypt(_));
     demuxer_stream_.reset();
     message_loop_.RunUntilIdle();
@@ -115,14 +101,25 @@
     message_loop_.RunUntilIdle();
   }
 
-  void ExpectDecryptorNotification(Decryptor* decryptor, bool expected_result) {
-    EXPECT_CALL(*this, RequestDecryptorNotification(_))
-        .WillOnce(SetDecryptorIfNotNull(
-            decryptor,
-            base::Bind(&DecryptingDemuxerStreamTest::DecryptorSet,
-                       base::Unretained(this)),
-            &is_decryptor_set_));
-    EXPECT_CALL(*this, DecryptorSet(expected_result));
+  enum CdmType { NO_CDM, CDM_WITHOUT_DECRYPTOR, CDM_WITH_DECRYPTOR };
+
+  void SetCdmType(CdmType cdm_type) {
+    const bool has_cdm = cdm_type != NO_CDM;
+    const bool has_decryptor = cdm_type == CDM_WITH_DECRYPTOR;
+
+    EXPECT_CALL(*this, RequestCdmNotification(_))
+        .WillOnce(
+            RunCallback<0>(has_cdm ? cdm_context_.get() : nullptr,
+                           base::Bind(&DecryptingDemuxerStreamTest::CdmSet,
+                                      base::Unretained(this))));
+
+    if (has_cdm) {
+      EXPECT_CALL(*cdm_context_, GetDecryptor())
+          .WillRepeatedly(Return(has_decryptor ? decryptor_.get() : nullptr));
+    }
+
+    EXPECT_CALL(*this, CdmSet(has_decryptor))
+        .WillOnce(SaveArg<0>(&is_cdm_set_));
   }
 
   // The following functions are used to test stream-type-neutral logic in
@@ -131,7 +128,7 @@
   // demuxer stream.
 
   void Initialize() {
-    ExpectDecryptorNotification(decryptor_.get(), true);
+    SetCdmType(CDM_WITH_DECRYPTOR);
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
         .WillOnce(SaveArg<1>(&key_added_cb_));
 
@@ -247,7 +244,7 @@
   }
 
   void Reset() {
-    if (is_decryptor_set_) {
+    if (is_cdm_set_) {
       EXPECT_CALL(*decryptor_, CancelDecrypt(Decryptor::kAudio))
           .WillRepeatedly(InvokeWithoutArgs(
               this, &DecryptingDemuxerStreamTest::AbortPendingDecryptCB));
@@ -257,20 +254,18 @@
     message_loop_.RunUntilIdle();
   }
 
-  MOCK_METHOD1(RequestDecryptorNotification, void(const DecryptorReadyCB&));
-
+  MOCK_METHOD1(RequestCdmNotification, void(const CdmReadyCB&));
   MOCK_METHOD2(BufferReady, void(DemuxerStream::Status,
                                  const scoped_refptr<DecoderBuffer>&));
-
-  MOCK_METHOD1(DecryptorSet, void(bool));
-
+  MOCK_METHOD1(CdmSet, void(bool));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingDemuxerStream> demuxer_stream_;
-  scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
+  scoped_ptr<StrictMock<MockDecryptor>> decryptor_;
   // Whether a valid Decryptor has been set in the |demuxer_stream_|.
-  bool is_decryptor_set_;
+  bool is_cdm_set_;
   scoped_ptr<StrictMock<MockDemuxerStream> > input_audio_stream_;
   scoped_ptr<StrictMock<MockDemuxerStream> > input_video_stream_;
 
@@ -293,7 +288,7 @@
 }
 
 TEST_F(DecryptingDemuxerStreamTest, Initialize_NormalVideo) {
-  ExpectDecryptorNotification(decryptor_.get(), true);
+  SetCdmType(CDM_WITH_DECRYPTOR);
   EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
       .WillOnce(SaveArg<1>(&key_added_cb_));
 
@@ -313,8 +308,16 @@
   ASSERT_EQ(input_config.extra_data(), output_config.extra_data());
 }
 
-TEST_F(DecryptingDemuxerStreamTest, Initialize_NullDecryptor) {
-  ExpectDecryptorNotification(NULL, false);
+TEST_F(DecryptingDemuxerStreamTest, Initialize_NoCdm) {
+  SetCdmType(NO_CDM);
+  AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+                                  CHANNEL_LAYOUT_STEREO, 44100,
+                                  EmptyExtraData(), true);
+  InitializeAudioAndExpectStatus(input_config, DECODER_ERROR_NOT_SUPPORTED);
+}
+
+TEST_F(DecryptingDemuxerStreamTest, Initialize_CdmWithoutDecryptor) {
+  SetCdmType(CDM_WITHOUT_DECRYPTOR);
   AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
                                   CHANNEL_LAYOUT_STEREO, 44100,
                                   EmptyExtraData(), true);
@@ -389,8 +392,7 @@
 // Test resetting in kDecryptorRequested state.
 TEST_F(DecryptingDemuxerStreamTest, Reset_DuringDecryptorRequested) {
   // One for decryptor request, one for canceling request during Reset().
-  EXPECT_CALL(*this, RequestDecryptorNotification(_))
-      .Times(2);
+  EXPECT_CALL(*this, RequestCdmNotification(_)).Times(2);
   AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
                                   CHANNEL_LAYOUT_STEREO, 44100,
                                   EmptyExtraData(), true);
@@ -510,8 +512,7 @@
 // Test destruction in kDecryptorRequested state.
 TEST_F(DecryptingDemuxerStreamTest, Destroy_DuringDecryptorRequested) {
   // One for decryptor request, one for canceling request during Reset().
-  EXPECT_CALL(*this, RequestDecryptorNotification(_))
-      .Times(2);
+  EXPECT_CALL(*this, RequestCdmNotification(_)).Times(2);
   AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
                                   CHANNEL_LAYOUT_STEREO, 44100,
                                   EmptyExtraData(), true);
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index 19e62b3..ac6a244 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -23,18 +23,17 @@
 DecryptingVideoDecoder::DecryptingVideoDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
-      set_decryptor_ready_cb_(set_decryptor_ready_cb),
+      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
       trace_id_(0),
-      weak_factory_(this) {
-}
+      weak_factory_(this) {}
 
 std::string DecryptingVideoDecoder::GetDisplayName() const {
   return kDecoderName;
@@ -61,8 +60,8 @@
 
   if (state_ == kUninitialized) {
     state_ = kDecryptorRequested;
-    set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind(
-        &DecryptingVideoDecoder::SetDecryptor, weak_this_)));
+    set_cdm_ready_cb_.Run(BindToCurrentLoop(
+        base::Bind(&DecryptingVideoDecoder::SetCdm, weak_this_)));
     return;
   }
 
@@ -145,8 +144,8 @@
     decryptor_->DeinitializeDecoder(Decryptor::kVideo);
     decryptor_ = NULL;
   }
-  if (!set_decryptor_ready_cb_.is_null())
-    base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB());
+  if (!set_cdm_ready_cb_.is_null())
+    base::ResetAndReturn(&set_cdm_ready_cb_).Run(CdmReadyCB());
   pending_buffer_to_decode_ = NULL;
   if (!init_cb_.is_null())
     base::ResetAndReturn(&init_cb_).Run(false);
@@ -156,32 +155,31 @@
     base::ResetAndReturn(&reset_cb_).Run();
 }
 
-void DecryptingVideoDecoder::SetDecryptor(
-    Decryptor* decryptor,
-    const DecryptorAttachedCB& decryptor_attached_cb) {
-  DVLOG(2) << "SetDecryptor()";
+void DecryptingVideoDecoder::SetCdm(CdmContext* cdm_context,
+                                    const CdmAttachedCB& cdm_attached_cb) {
+  DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kDecryptorRequested) << state_;
   DCHECK(!init_cb_.is_null());
-  DCHECK(!set_decryptor_ready_cb_.is_null());
-  set_decryptor_ready_cb_.Reset();
+  DCHECK(!set_cdm_ready_cb_.is_null());
+  set_cdm_ready_cb_.Reset();
 
-  if (!decryptor) {
+  if (!cdm_context || !cdm_context->GetDecryptor()) {
     MEDIA_LOG(DEBUG, media_log_) << GetDisplayName() << ": no decryptor set";
     base::ResetAndReturn(&init_cb_).Run(false);
     state_ = kError;
-    decryptor_attached_cb.Run(false);
+    cdm_attached_cb.Run(false);
     return;
   }
 
-  decryptor_ = decryptor;
+  decryptor_ = cdm_context->GetDecryptor();
 
   state_ = kPendingDecoderInit;
   decryptor_->InitializeVideoDecoder(
       config_,
       BindToCurrentLoop(base::Bind(
           &DecryptingVideoDecoder::FinishInitialization, weak_this_)));
-  decryptor_attached_cb.Run(true);
+  cdm_attached_cb.Run(true);
 }
 
 void DecryptingVideoDecoder::FinishInitialization(bool success) {
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index 80b3b81..1ac97b81 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decryptor.h"
 #include "media/base/video_decoder.h"
 #include "media/base/video_decoder_config.h"
@@ -30,7 +31,7 @@
   DecryptingVideoDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingVideoDecoder() override;
 
@@ -61,10 +62,9 @@
     kError
   };
 
-  // Callback for DecryptorHost::RequestDecryptor(). |decryptor_attached_cb| is
-  // called when the decryptor has been completely attached to the pipeline.
-  void SetDecryptor(Decryptor* decryptor,
-                    const DecryptorAttachedCB& decryptor_attached_cb);
+  // Callback to set CDM. |cdm_attached_cb| is called when the decryptor in the
+  // CDM has been completely attached to the pipeline.
+  void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
 
   // Callback for Decryptor::InitializeVideoDecoder() during initialization.
   void FinishInitialization(bool success);
@@ -97,8 +97,8 @@
 
   VideoDecoderConfig config_;
 
-  // Callback to request/cancel decryptor creation notification.
-  SetDecryptorReadyCB set_decryptor_ready_cb_;
+  // Callback to request/cancel CDM ready notification.
+  SetCdmReadyCB set_cdm_ready_cb_;
 
   Decryptor* decryptor_;
 
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 5b8cf5c..dba3e2e8 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -19,6 +19,7 @@
 
 using ::testing::_;
 using ::testing::Invoke;
+using ::testing::Return;
 using ::testing::SaveArg;
 using ::testing::StrictMock;
 
@@ -56,11 +57,11 @@
       : decoder_(new DecryptingVideoDecoder(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(
-                &DecryptingVideoDecoderTest::RequestDecryptorNotification,
-                base::Unretained(this)),
+            base::Bind(&DecryptingVideoDecoderTest::RequestCdmNotification,
+                       base::Unretained(this)),
             base::Bind(&DecryptingVideoDecoderTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new StrictMock<MockDecryptor>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
@@ -73,12 +74,23 @@
     Destroy();
   }
 
-  void ExpectDecryptorNotification(Decryptor* decryptor, bool expected_result) {
-    EXPECT_CALL(*this, RequestDecryptorNotification(_)).WillOnce(
-        RunCallback<0>(decryptor,
-                       base::Bind(&DecryptingVideoDecoderTest::DecryptorSet,
-                                  base::Unretained(this))));
-    EXPECT_CALL(*this, DecryptorSet(expected_result));
+  enum CdmType { NO_CDM, CDM_WITHOUT_DECRYPTOR, CDM_WITH_DECRYPTOR };
+
+  void SetCdmType(CdmType cdm_type) {
+    const bool has_cdm = cdm_type != NO_CDM;
+    const bool has_decryptor = cdm_type == CDM_WITH_DECRYPTOR;
+
+    EXPECT_CALL(*this, RequestCdmNotification(_))
+        .WillOnce(RunCallback<0>(has_cdm ? cdm_context_.get() : nullptr,
+                                 base::Bind(&DecryptingVideoDecoderTest::CdmSet,
+                                            base::Unretained(this))));
+
+    if (has_cdm) {
+      EXPECT_CALL(*cdm_context_, GetDecryptor())
+          .WillRepeatedly(Return(has_decryptor ? decryptor_.get() : nullptr));
+    }
+
+    EXPECT_CALL(*this, CdmSet(has_decryptor));
   }
 
   // Initializes the |decoder_| and expects |success|. Note the initialization
@@ -93,7 +105,7 @@
 
   // Initialize the |decoder_| and expects it to succeed.
   void Initialize() {
-    ExpectDecryptorNotification(decryptor_.get(), true);
+    SetCdmType(CDM_WITH_DECRYPTOR);
     EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
         .WillOnce(RunCallback<1>(true));
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
@@ -223,18 +235,19 @@
     message_loop_.RunUntilIdle();
   }
 
-  MOCK_METHOD1(RequestDecryptorNotification, void(const DecryptorReadyCB&));
+  MOCK_METHOD1(RequestCdmNotification, void(const CdmReadyCB&));
 
   MOCK_METHOD1(FrameReady, void(const scoped_refptr<VideoFrame>&));
   MOCK_METHOD1(DecodeDone, void(VideoDecoder::Status));
 
-  MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD1(CdmSet, void(bool));
 
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingVideoDecoder> decoder_;
-  scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
+  scoped_ptr<StrictMock<MockDecryptor>> decryptor_;
 
   // Variables to help the |decryptor_| to simulate decoding delay and flushing.
   int num_decrypt_and_decode_calls_;
@@ -257,8 +270,13 @@
   Initialize();
 }
 
-TEST_F(DecryptingVideoDecoderTest, Initialize_NullDecryptor) {
-  ExpectDecryptorNotification(NULL, false);
+TEST_F(DecryptingVideoDecoderTest, Initialize_NoCdm) {
+  SetCdmType(NO_CDM);
+  InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
+}
+
+TEST_F(DecryptingVideoDecoderTest, Initialize_CdmWithoutDecryptor) {
+  SetCdmType(CDM_WITHOUT_DECRYPTOR);
   InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
 }
 
@@ -267,7 +285,7 @@
       .WillRepeatedly(RunCallback<1>(false));
   EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
       .WillRepeatedly(SaveArg<1>(&key_added_cb_));
-  EXPECT_CALL(*this, RequestDecryptorNotification(_)).Times(2);
+  EXPECT_CALL(*this, RequestCdmNotification(_)).Times(2);
 
   InitializeAndExpectResult(TestVideoConfig::NormalEncrypted(), false);
 }
@@ -407,31 +425,31 @@
 
 // Test destruction when the decoder is in kDecryptorRequested state.
 TEST_F(DecryptingVideoDecoderTest, Destroy_DuringDecryptorRequested) {
-  DecryptorReadyCB decryptor_ready_cb;
-  EXPECT_CALL(*this, RequestDecryptorNotification(_))
-      .WillOnce(SaveArg<0>(&decryptor_ready_cb));
+  CdmReadyCB cdm_ready_cb;
+  EXPECT_CALL(*this, RequestCdmNotification(_))
+      .WillOnce(SaveArg<0>(&cdm_ready_cb));
   decoder_->Initialize(TestVideoConfig::NormalEncrypted(), false,
                        NewExpectedBoolCB(false),
                        base::Bind(&DecryptingVideoDecoderTest::FrameReady,
                                   base::Unretained(this)));
   message_loop_.RunUntilIdle();
-  // |decryptor_ready_cb| is saved but not called here.
-  EXPECT_FALSE(decryptor_ready_cb.is_null());
+  // |cdm_ready_cb| is saved but not called here.
+  EXPECT_FALSE(cdm_ready_cb.is_null());
 
-  // During destruction, RequestDecryptorNotification() should be called with a
-  // NULL callback to cancel the |decryptor_ready_cb|.
-  EXPECT_CALL(*this, RequestDecryptorNotification(IsNullCallback())).WillOnce(
-      ResetAndRunCallback(&decryptor_ready_cb,
-                          reinterpret_cast<Decryptor*>(NULL),
-                          base::Bind(&DecryptingVideoDecoderTest::DecryptorSet,
-                                     base::Unretained(this))));
-  EXPECT_CALL(*this, DecryptorSet(_)).Times(0);
+  // During destruction, RequestCdmNotification() should be called with a
+  // NULL callback to cancel the |cdm_ready_cb|.
+  EXPECT_CALL(*this, RequestCdmNotification(IsNullCallback()))
+      .WillOnce(
+          ResetAndRunCallback(&cdm_ready_cb, nullptr,
+                              base::Bind(&DecryptingVideoDecoderTest::CdmSet,
+                                         base::Unretained(this))));
+  EXPECT_CALL(*this, CdmSet(_)).Times(0);
   Destroy();
 }
 
 // Test destruction when the decoder is in kPendingDecoderInit state.
 TEST_F(DecryptingVideoDecoderTest, Destroy_DuringPendingDecoderInit) {
-  ExpectDecryptorNotification(decryptor_.get(), true);
+  SetCdmType(CDM_WITH_DECRYPTOR);
   EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
       .WillOnce(SaveArg<1>(&pending_init_cb_));
 
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index a0a889c..087661df 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -24,10 +24,10 @@
 // times across multiple test files. Sadly we can't use static for them.
 namespace {
 
-ACTION_P3(ExecuteCallbackWithVerifier, decryptor, done_cb, verifier) {
+ACTION_P3(ExecuteCallbackWithVerifier, cdm_context, done_cb, verifier) {
   // verifier must be called first since |done_cb| call will invoke it as well.
   verifier->RecordACalled();
-  arg0.Run(decryptor, done_cb);
+  arg0.Run(cdm_context, done_cb);
 }
 
 ACTION_P(ReportCallback, verifier) {
@@ -60,21 +60,25 @@
   VideoDecoderSelectorTest()
       : demuxer_stream_(
             new StrictMock<MockDemuxerStream>(DemuxerStream::VIDEO)),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new NiceMock<MockDecryptor>()),
         decoder_1_(new StrictMock<MockVideoDecoder>()),
         decoder_2_(new StrictMock<MockVideoDecoder>()) {
     all_decoders_.push_back(decoder_1_);
     all_decoders_.push_back(decoder_2_);
+
+    EXPECT_CALL(*cdm_context_, GetDecryptor())
+        .WillRepeatedly(Return(decryptor_.get()));
   }
 
   ~VideoDecoderSelectorTest() {
     message_loop_.RunUntilIdle();
   }
 
-  MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
+  MOCK_METHOD1(SetCdmReadyCallback, void(const media::CdmReadyCB&));
   MOCK_METHOD2(OnDecoderSelected,
                void(VideoDecoder*, DecryptingDemuxerStream*));
-  MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD1(CdmSet, void(bool));
 
   void MockOnDecoderSelected(
       scoped_ptr<VideoDecoder> decoder,
@@ -96,13 +100,12 @@
                                  int num_decoders) {
     if (decryptor_capability == kDecryptOnly ||
         decryptor_capability == kDecryptAndDecode) {
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
+      EXPECT_CALL(*this, SetCdmReadyCallback(_))
           .WillRepeatedly(ExecuteCallbackWithVerifier(
-              decryptor_.get(),
-              base::Bind(&VideoDecoderSelectorTest::DecryptorSet,
-                         base::Unretained(this)),
+              cdm_context_.get(), base::Bind(&VideoDecoderSelectorTest::CdmSet,
+                                             base::Unretained(this)),
               &verifier_));
-      EXPECT_CALL(*this, DecryptorSet(true))
+      EXPECT_CALL(*this, CdmSet(true))
           .WillRepeatedly(ReportCallback(&verifier_));
 
       if (decryptor_capability == kDecryptOnly) {
@@ -113,11 +116,10 @@
             .WillRepeatedly(RunCallback<1>(true));
       }
     } else if (decryptor_capability == kHoldSetDecryptor) {
-      // Set and cancel DecryptorReadyCB but the callback is never fired.
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
-          .Times(2);
+      // Set and cancel CdmReadyCB but the callback is never fired.
+      EXPECT_CALL(*this, SetCdmReadyCallback(_)).Times(2);
     } else if (decryptor_capability == kNoDecryptor) {
-      EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
+      EXPECT_CALL(*this, SetCdmReadyCallback(_))
           .WillRepeatedly(
               RunCallback<0>(nullptr, base::Bind(&IgnoreCdmAttached)));
     }
@@ -134,7 +136,7 @@
   void SelectDecoder() {
     decoder_selector_->SelectDecoder(
         demuxer_stream_.get(),
-        base::Bind(&VideoDecoderSelectorTest::SetDecryptorReadyCallback,
+        base::Bind(&VideoDecoderSelectorTest::SetCdmReadyCallback,
                    base::Unretained(this)),
         base::Bind(&VideoDecoderSelectorTest::MockOnDecoderSelected,
                    base::Unretained(this)),
@@ -163,11 +165,13 @@
 
   // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since
   // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|.
-  scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
+  scoped_ptr<StrictMock<MockDemuxerStream>> demuxer_stream_;
+
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
 
   // Use NiceMock since we don't care about most of calls on the decryptor, e.g.
   // RegisterNewKeyCB().
-  scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
+  scoped_ptr<NiceMock<MockDecryptor>> decryptor_;
 
   scoped_ptr<VideoDecoderSelector> decoder_selector_;
 
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index d195565..c9e9f0aa 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -22,6 +22,7 @@
 using ::testing::NiceMock;
 using ::testing::Return;
 using ::testing::SaveArg;
+using ::testing::StrictMock;
 
 static const int kNumConfigs = 4;
 static const int kNumBuffersInOneConfig = 5;
@@ -30,10 +31,10 @@
 // times across multiple test files. Sadly we can't use static for them.
 namespace {
 
-ACTION_P3(ExecuteCallbackWithVerifier, decryptor, done_cb, verifier) {
+ACTION_P3(ExecuteCallbackWithVerifier, cdm_context, done_cb, verifier) {
   // verifier must be called first since |done_cb| call will invoke it as well.
   verifier->RecordACalled();
-  arg0.Run(decryptor, done_cb);
+  arg0.Run(cdm_context, done_cb);
 }
 
 ACTION_P(ReportCallback, verifier) {
@@ -65,23 +66,26 @@
       : demuxer_stream_(new FakeDemuxerStream(kNumConfigs,
                                               kNumBuffersInOneConfig,
                                               GetParam().is_encrypted)),
+        cdm_context_(new StrictMock<MockCdmContext>()),
         decryptor_(new NiceMock<MockDecryptor>()),
-        decoder1_(new FakeVideoDecoder(
-            GetParam().decoding_delay,
-            GetParam().parallel_decoding,
-            base::Bind(&VideoFrameStreamTest::OnBytesDecoded,
-                       base::Unretained(this)))),
-        decoder2_(new FakeVideoDecoder(
-            GetParam().decoding_delay,
-            GetParam().parallel_decoding,
-            base::Bind(&VideoFrameStreamTest::OnBytesDecoded,
-                       base::Unretained(this)))),
-        decoder3_(new FakeVideoDecoder(
-            GetParam().decoding_delay,
-            GetParam().parallel_decoding,
-            base::Bind(&VideoFrameStreamTest::OnBytesDecoded,
-                       base::Unretained(this)))),
-
+        decoder1_(
+            new FakeVideoDecoder(GetParam().decoding_delay,
+                                 GetParam().parallel_decoding,
+                                 base::Bind(
+                                     &VideoFrameStreamTest::OnBytesDecoded,
+                                     base::Unretained(this)))),
+        decoder2_(
+            new FakeVideoDecoder(GetParam().decoding_delay,
+                                 GetParam().parallel_decoding,
+                                 base::Bind(
+                                     &VideoFrameStreamTest::OnBytesDecoded,
+                                     base::Unretained(this)))),
+        decoder3_(
+            new FakeVideoDecoder(GetParam().decoding_delay,
+                                 GetParam().parallel_decoding,
+                                 base::Bind(
+                                     &VideoFrameStreamTest::OnBytesDecoded,
+                                     base::Unretained(this)))),
         is_initialized_(false),
         num_decoded_frames_(0),
         pending_initialize_(false),
@@ -98,6 +102,9 @@
     video_frame_stream_.reset(new VideoFrameStream(
         message_loop_.task_runner(), decoders.Pass(), new MediaLog()));
 
+    EXPECT_CALL(*cdm_context_, GetDecryptor())
+        .WillRepeatedly(Return(decryptor_.get()));
+
     // Decryptor can only decrypt (not decrypt-and-decode) so that
     // DecryptingDemuxerStream will be used.
     EXPECT_CALL(*decryptor_, InitializeVideoDecoder(_, _))
@@ -124,8 +131,8 @@
   }
 
   MOCK_METHOD1(OnNewSpliceBuffer, void(base::TimeDelta));
-  MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
-  MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD1(SetCdmReadyCallback, void(const media::CdmReadyCB&));
+  MOCK_METHOD1(CdmSet, void(bool));
   MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   void OnStatistics(const PipelineStatistics& statistics) {
@@ -155,7 +162,7 @@
     video_frame_stream_->Initialize(
         demuxer_stream_.get(), base::Bind(&VideoFrameStreamTest::OnInitialized,
                                           base::Unretained(this)),
-        base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback,
+        base::Bind(&VideoFrameStreamTest::SetCdmReadyCallback,
                    base::Unretained(this)),
         base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)),
         base::Bind(&VideoFrameStreamTest::OnWaitingForDecryptionKey,
@@ -246,15 +253,13 @@
     DECODER_RESET
   };
 
-  void ExpectDecryptorNotification() {
-    EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
+  void ExpectCdmNotification() {
+    EXPECT_CALL(*this, SetCdmReadyCallback(_))
         .WillRepeatedly(ExecuteCallbackWithVerifier(
-            decryptor_.get(),
-            base::Bind(&VideoFrameStreamTest::DecryptorSet,
-                       base::Unretained(this)),
+            cdm_context_.get(),
+            base::Bind(&VideoFrameStreamTest::CdmSet, base::Unretained(this)),
             &verifier_));
-    EXPECT_CALL(*this, DecryptorSet(true))
-        .WillRepeatedly(ReportCallback(&verifier_));
+    EXPECT_CALL(*this, CdmSet(true)).WillRepeatedly(ReportCallback(&verifier_));
   }
 
   void EnterPendingState(PendingState state) {
@@ -275,9 +280,8 @@
         break;
 
       case SET_DECRYPTOR:
-        // Hold DecryptorReadyCB.
-        EXPECT_CALL(*this, SetDecryptorReadyCallback(_))
-            .Times(2);
+        // Hold CdmReadyCB.
+        EXPECT_CALL(*this, SetCdmReadyCallback(_)).Times(2);
         // Initialize will fail because no decryptor is available.
         InitializeVideoFrameStream();
         break;
@@ -285,13 +289,13 @@
       case DECRYPTOR_NO_KEY:
         if (GetParam().is_encrypted)
           EXPECT_CALL(*this, OnWaitingForDecryptionKey());
-        ExpectDecryptorNotification();
+        ExpectCdmNotification();
         has_no_key_ = true;
         ReadOneFrame();
         break;
 
       case DECODER_INIT:
-        ExpectDecryptorNotification();
+        ExpectCdmNotification();
         decoder->HoldNextInit();
         InitializeVideoFrameStream();
         break;
@@ -387,9 +391,11 @@
 
   scoped_ptr<VideoFrameStream> video_frame_stream_;
   scoped_ptr<FakeDemuxerStream> demuxer_stream_;
+  scoped_ptr<StrictMock<MockCdmContext>> cdm_context_;
+
   // Use NiceMock since we don't care about most of calls on the decryptor,
   // e.g. RegisterNewKeyCB().
-  scoped_ptr<NiceMock<MockDecryptor> > decryptor_;
+  scoped_ptr<NiceMock<MockDecryptor>> decryptor_;
   // Three decoders are needed to test that decoder fallback can occur more than
   // once on a config change. They are owned by |video_frame_stream_|.
   FakeVideoDecoder* decoder1_;
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index deb8dfe2..9a0cdf95 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -308,7 +308,7 @@
 void AudioRendererImpl::Initialize(
     DemuxerStream* stream,
     const PipelineStatusCB& init_cb,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const StatisticsCB& statistics_cb,
     const BufferingStateCB& buffering_state_cb,
     const base::Closure& ended_cb,
@@ -367,7 +367,7 @@
   audio_buffer_stream_->Initialize(
       stream, base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
                          weak_factory_.GetWeakPtr()),
-      set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
+      set_cdm_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
 }
 
 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 0d3418d..de0cbdab 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -78,7 +78,7 @@
   // AudioRenderer implementation.
   void Initialize(DemuxerStream* stream,
                   const PipelineStatusCB& init_cb,
-                  const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const StatisticsCB& statistics_cb,
                   const BufferingStateCB& buffering_state_cb,
                   const base::Closure& ended_cb,
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index d26c0d8..0dd3969 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -124,7 +124,7 @@
   void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) {
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
-        &demuxer_stream_, pipeline_status_cb, SetDecryptorReadyCB(),
+        &demuxer_stream_, pipeline_status_cb, SetCdmReadyCB(),
         base::Bind(&AudioRendererImplTest::OnStatistics,
                    base::Unretained(this)),
         base::Bind(&AudioRendererImplTest::OnBufferingStateChange,
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index 63c4a5f..a7bd113 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -121,13 +121,12 @@
 
   cdm_context_ = cdm_context;
 
-  if (decryptor_ready_cb_.is_null()) {
+  if (cdm_ready_cb_.is_null()) {
     cdm_attached_cb.Run(true);
     return;
   }
 
-  base::ResetAndReturn(&decryptor_ready_cb_)
-      .Run(cdm_context->GetDecryptor(), cdm_attached_cb);
+  base::ResetAndReturn(&cdm_ready_cb_).Run(cdm_context, cdm_attached_cb);
 }
 
 void RendererImpl::Flush(const base::Closure& flush_cb) {
@@ -253,27 +252,25 @@
   return time_source_->GetWallClockTimes(media_timestamps, wall_clock_times);
 }
 
-void RendererImpl::SetDecryptorReadyCallback(
-    const DecryptorReadyCB& decryptor_ready_cb) {
-  // Cancels the previous decryptor request.
-  if (decryptor_ready_cb.is_null()) {
-    if (!decryptor_ready_cb_.is_null()) {
-      base::ResetAndReturn(&decryptor_ready_cb_)
+void RendererImpl::SetCdmReadyCallback(const CdmReadyCB& cdm_ready_cb) {
+  // Cancels the previous CDM request.
+  if (cdm_ready_cb.is_null()) {
+    if (!cdm_ready_cb_.is_null()) {
+      base::ResetAndReturn(&cdm_ready_cb_)
           .Run(nullptr, base::Bind(IgnoreCdmAttached));
     }
     return;
   }
 
   // We initialize audio and video decoders in sequence.
-  DCHECK(decryptor_ready_cb_.is_null());
+  DCHECK(cdm_ready_cb_.is_null());
 
   if (cdm_context_) {
-    decryptor_ready_cb.Run(cdm_context_->GetDecryptor(),
-                           base::Bind(IgnoreCdmAttached));
+    cdm_ready_cb.Run(cdm_context_, base::Bind(IgnoreCdmAttached));
     return;
   }
 
-  decryptor_ready_cb_ = decryptor_ready_cb;
+  cdm_ready_cb_ = cdm_ready_cb;
 }
 
 void RendererImpl::InitializeAudioRenderer() {
@@ -295,7 +292,7 @@
   // happen at any time and all future calls must guard against STATE_ERROR.
   audio_renderer_->Initialize(
       demuxer_stream_provider_->GetStream(DemuxerStream::AUDIO), done_cb,
-      base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
+      base::Bind(&RendererImpl::SetCdmReadyCallback, weak_this_),
       base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
       base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
                  &audio_buffering_state_),
@@ -342,7 +339,7 @@
 
   video_renderer_->Initialize(
       demuxer_stream_provider_->GetStream(DemuxerStream::VIDEO), done_cb,
-      base::Bind(&RendererImpl::SetDecryptorReadyCallback, weak_this_),
+      base::Bind(&RendererImpl::SetCdmReadyCallback, weak_this_),
       base::Bind(&RendererImpl::OnUpdateStatistics, weak_this_),
       base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
                  &video_buffering_state_),
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h
index 56887c2..ccaabbe 100644
--- a/media/renderers/renderer_impl.h
+++ b/media/renderers/renderer_impl.h
@@ -85,11 +85,11 @@
   bool GetWallClockTimes(const std::vector<base::TimeDelta>& media_timestamps,
                          std::vector<base::TimeTicks>* wall_clock_times);
 
-  // Requests that this object notifies when a decryptor is ready through the
-  // |decryptor_ready_cb| provided.
-  // If |decryptor_ready_cb| is null, the existing callback will be fired with
+  // Requests that this object notifies when a CDM is ready through the
+  // |cdm_ready_cb| provided.
+  // If |cdm_ready_cb| is null, the existing callback will be fired with
   // nullptr immediately and reset.
-  void SetDecryptorReadyCallback(const DecryptorReadyCB& decryptor_ready_cb);
+  void SetCdmReadyCallback(const CdmReadyCB& cdm_ready_cb);
 
   // Helper functions and callbacks for Initialize().
   void InitializeAudioRenderer();
@@ -170,12 +170,12 @@
   CdmContext* cdm_context_;
 
   // Callback registered by filters (decoder or demuxer) to be informed of a
-  // Decryptor.
+  // CDM.
   // Note: We could have multiple filters registering this callback. One
   // callback is okay because:
   // 1, We always initialize filters in sequence.
   // 2, Filter initialization will not finish until this callback is satisfied.
-  DecryptorReadyCB decryptor_ready_cb_;
+  CdmReadyCB cdm_ready_cb_;
 
   bool underflow_disabled_for_testing_;
   bool clockless_video_playback_enabled_for_testing_;
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index fe724cb..e54e827 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -120,7 +120,7 @@
 void VideoRendererImpl::Initialize(
     DemuxerStream* stream,
     const PipelineStatusCB& init_cb,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const StatisticsCB& statistics_cb,
     const BufferingStateCB& buffering_state_cb,
     const base::Closure& ended_cb,
@@ -165,7 +165,7 @@
   video_frame_stream_->Initialize(
       stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
                          weak_factory_.GetWeakPtr()),
-      set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
+      set_cdm_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
 }
 
 scoped_refptr<VideoFrame> VideoRendererImpl::Render(
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h
index 75a8d03..974da42 100644
--- a/media/renderers/video_renderer_impl.h
+++ b/media/renderers/video_renderer_impl.h
@@ -62,7 +62,7 @@
   // VideoRenderer implementation.
   void Initialize(DemuxerStream* stream,
                   const PipelineStatusCB& init_cb,
-                  const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const StatisticsCB& statistics_cb,
                   const BufferingStateCB& buffering_state_cb,
                   const base::Closure& ended_cb,
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index f7dcb10..74d9a1e 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -119,7 +119,7 @@
             DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(expect_to_success)));
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
-        &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
+        &demuxer_stream_, status_cb, SetCdmReadyCB(),
         base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
                    base::Unretained(this)),
         base::Bind(&StrictMock<MockCB>::BufferingStateChange,
diff --git a/mojo/common/BUILD.gn b/mojo/common/BUILD.gn
index 51599b4..eb12b65 100644
--- a/mojo/common/BUILD.gn
+++ b/mojo/common/BUILD.gn
@@ -98,3 +98,19 @@
     "common_type_converters_unittest.cc",
   ]
 }
+
+test("mojo_common_perftests") {
+  deps = [
+    ":common",
+    "//base",
+    "//mojo/environment:chromium",
+    "//mojo/message_pump",
+    "//testing/gtest",
+    "//third_party/mojo/src/mojo/edk/test:run_all_perftests",
+    "//third_party/mojo/src/mojo/public/cpp/test_support:test_utils",
+  ]
+
+  sources = [
+    "../message_pump/handle_watcher_perftest.cc",
+  ]
+}
diff --git a/mojo/edk/embedder/embedder.cc b/mojo/edk/embedder/embedder.cc
index fe5202c..dd79184 100644
--- a/mojo/edk/embedder/embedder.cc
+++ b/mojo/edk/embedder/embedder.cc
@@ -10,6 +10,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/task_runner.h"
 #include "mojo/edk/embedder/embedder_internal.h"
 #include "mojo/edk/embedder/process_delegate.h"
@@ -26,6 +27,7 @@
 // temporarily.
 int g_channel_count = 0;
 bool g_wait_for_no_more_channels = false;
+base::TaskRunner* g_delegate_task_runner = nullptr;  // Used at shutdown.
 
 namespace {
 
@@ -36,9 +38,10 @@
     return;
   }
 
-  internal::g_delegate_thread_task_runner->PostTask(
+  g_delegate_task_runner->PostTask(
       FROM_HERE, base::Bind(&ProcessDelegate::OnShutdownComplete,
                             base::Unretained(internal::g_process_delegate)));
+  g_delegate_task_runner = nullptr;
 }
 
 }  // namespace
@@ -49,7 +52,6 @@
 PlatformSupport* g_platform_support = nullptr;
 Core* g_core = nullptr;
 
-base::TaskRunner* g_delegate_thread_task_runner;
 ProcessDelegate* g_process_delegate;
 base::TaskRunner* g_io_thread_task_runner = nullptr;
 
@@ -134,12 +136,10 @@
   return MOJO_RESULT_OK;
 }
 
-void InitIPCSupport(scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
-                    ProcessDelegate* process_delegate,
+void InitIPCSupport(ProcessDelegate* process_delegate,
                     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
   // |Init()| must have already been called.
   DCHECK(internal::g_core);
-  internal::g_delegate_thread_task_runner = delegate_thread_task_runner.get();
   internal::g_process_delegate = process_delegate;
   internal::g_io_thread_task_runner = io_thread_task_runner.get();
 }
@@ -148,11 +148,13 @@
 }
 
 void ShutdownIPCSupport() {
+  g_delegate_task_runner = base::MessageLoop::current()->task_runner().get();
   internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&ShutdownIPCSupportHelper, false));
 }
 
 void ShutdownIPCSupportAndWaitForNoChannels() {
+  g_delegate_task_runner = base::MessageLoop::current()->task_runner().get();
   internal::g_io_thread_task_runner->PostTask(
       FROM_HERE, base::Bind(&ShutdownIPCSupportHelper, true));
 }
diff --git a/mojo/edk/embedder/embedder.h b/mojo/edk/embedder/embedder.h
index 36016d3..3c0dddf 100644
--- a/mojo/edk/embedder/embedder.h
+++ b/mojo/edk/embedder/embedder.h
@@ -74,14 +74,12 @@
 
 // Initializes a process of the given type; to be called after |Init()|.
 //   - |process_delegate| must be a process delegate of the appropriate type
-//     corresponding to |process_type|; its methods will be called on
-//     |delegate_thread_task_runner|.
-//   - |delegate_thread_task_runner|, |process_delegate|, and
-//     |io_thread_task_runner| should live at least until
-//     |ShutdownIPCSupport()|'s callback has been run or
+//     corresponding to |process_type|; its methods will be called on the same
+//     thread as Shutdown.
+//   - |process_delegate|, and |io_thread_task_runner| should live at least
+//     until |ShutdownIPCSupport()|'s callback has been run or
 //     |ShutdownIPCSupportOnIOThread()| has completed.
 MOJO_SYSTEM_IMPL_EXPORT void InitIPCSupport(
-    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
     ProcessDelegate* process_delegate,
     scoped_refptr<base::TaskRunner> io_thread_task_runner);
 
diff --git a/mojo/message_pump/handle_watcher.cc b/mojo/message_pump/handle_watcher.cc
index 1397dee..a8d007a 100644
--- a/mojo/message_pump/handle_watcher.cc
+++ b/mojo/message_pump/handle_watcher.cc
@@ -14,6 +14,7 @@
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
 #include "base/synchronization/waitable_event.h"
@@ -262,6 +263,11 @@
     }
   }
 
+  // TODO(amistry): Remove ScopedTracker below once http://crbug.com/554761 is
+  // fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "554761 WatcherThreadManager::StopWatching"));
   base::ThreadRestrictions::ScopedAllowWait allow_wait;
   base::WaitableEvent event(true, false);
   RequestData request_data;
diff --git a/mojo/message_pump/handle_watcher_perftest.cc b/mojo/message_pump/handle_watcher_perftest.cc
new file mode 100644
index 0000000..afdbb9f
--- /dev/null
+++ b/mojo/message_pump/handle_watcher_perftest.cc
@@ -0,0 +1,201 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mojo/message_pump/handle_watcher.h"
+
+#include <string>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/memory/scoped_vector.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "mojo/message_pump/message_pump_mojo.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/mojo/src/mojo/public/cpp/test_support/test_support.h"
+#include "third_party/mojo/src/mojo/public/cpp/test_support/test_utils.h"
+
+namespace mojo {
+namespace common {
+namespace test {
+
+enum MessageLoopConfig {
+  MESSAGE_LOOP_CONFIG_DEFAULT = 0,
+  MESSAGE_LOOP_CONFIG_MOJO = 1
+};
+
+scoped_ptr<base::MessageLoop> CreateMessageLoop(MessageLoopConfig config) {
+  scoped_ptr<base::MessageLoop> loop;
+  if (config == MESSAGE_LOOP_CONFIG_DEFAULT)
+    loop.reset(new base::MessageLoop());
+  else
+    loop.reset(new base::MessageLoop(MessagePumpMojo::Create()));
+  return loop.Pass();
+}
+
+void OnWatcherSignaled(const base::Closure& callback, MojoResult /* result */) {
+  callback.Run();
+}
+
+class ScopedPerfTimer {
+ public:
+  ScopedPerfTimer(const std::string& test_name,
+                  const std::string& sub_test_name,
+                  uint64_t iterations)
+      : test_name_(test_name),
+        sub_test_name_(sub_test_name),
+        iterations_(iterations),
+        start_time_(base::TimeTicks::Now()) {}
+  ~ScopedPerfTimer() {
+    base::TimeTicks end_time = base::TimeTicks::Now();
+    mojo::test::LogPerfResult(
+        test_name_.c_str(), sub_test_name_.c_str(),
+        iterations_ / (end_time - start_time_).InSecondsF(),
+        "iterations/second");
+  }
+
+ private:
+  const std::string test_name_;
+  const std::string sub_test_name_;
+  const uint64_t iterations_;
+  base::TimeTicks start_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPerfTimer);
+};
+
+class HandleWatcherPerftest : public testing::TestWithParam<MessageLoopConfig> {
+ public:
+  HandleWatcherPerftest() : message_loop_(CreateMessageLoop(GetParam())) {}
+
+ protected:
+  std::string GetMessageLoopName() const {
+    return (GetParam() == MESSAGE_LOOP_CONFIG_DEFAULT) ? "DefaultMessageLoop"
+                                                       : "MojoMessageLoop";
+  }
+
+ private:
+  scoped_ptr<base::MessageLoop> message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(HandleWatcherPerftest);
+};
+
+INSTANTIATE_TEST_CASE_P(MultipleMessageLoopConfigs,
+                        HandleWatcherPerftest,
+                        testing::Values(MESSAGE_LOOP_CONFIG_DEFAULT,
+                                        MESSAGE_LOOP_CONFIG_MOJO));
+
+void NeverReached(MojoResult result) {
+  FAIL() << "Callback should never be invoked " << result;
+}
+
+TEST_P(HandleWatcherPerftest, StartStop) {
+  const uint64_t kIterations = 1000;
+  MessagePipe pipe;
+  HandleWatcher watcher;
+
+  ScopedPerfTimer timer("StartStop", GetMessageLoopName(), kIterations);
+  for (uint64_t i = 0; i < kIterations; i++) {
+    watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                  MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
+    watcher.Stop();
+  }
+}
+
+TEST_P(HandleWatcherPerftest, StartAllThenStop_1000Handles) {
+  const uint64_t kIterations = 1000;
+
+  struct TestData {
+    MessagePipe pipe;
+    HandleWatcher watcher;
+  };
+  ScopedVector<TestData> data_vector;
+  // Create separately from the start/stop loops to avoid affecting the
+  // benchmark.
+  for (uint64_t i = 0; i < kIterations; i++) {
+    scoped_ptr<TestData> test_data(new TestData);
+    ASSERT_TRUE(test_data->pipe.handle0.is_valid());
+    data_vector.push_back(test_data.Pass());
+  }
+
+  ScopedPerfTimer timer("StartAllThenStop_1000Handles", GetMessageLoopName(),
+                        kIterations);
+  for (uint64_t i = 0; i < kIterations; i++) {
+    TestData* test_data = data_vector[i];
+    test_data->watcher.Start(
+        test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+        MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
+  }
+  for (uint64_t i = 0; i < kIterations; i++) {
+    TestData* test_data = data_vector[i];
+    test_data->watcher.Stop();
+  }
+}
+
+TEST_P(HandleWatcherPerftest, StartAndSignal) {
+  const uint64_t kIterations = 1000;
+  const std::string kMessage = "hello";
+  MessagePipe pipe;
+  HandleWatcher watcher;
+  std::string received_message;
+
+  ScopedPerfTimer timer("StartAndSignal", GetMessageLoopName(), kIterations);
+  for (uint64_t i = 0; i < kIterations; i++) {
+    base::RunLoop run_loop;
+    watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                  MOJO_DEADLINE_INDEFINITE,
+                  base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
+    ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
+    run_loop.Run();
+    watcher.Stop();
+
+    ASSERT_TRUE(
+        mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
+    EXPECT_EQ(kMessage, received_message);
+    received_message.clear();
+  }
+}
+
+TEST_P(HandleWatcherPerftest, StartAndSignal_1000Waiting) {
+  const uint64_t kIterations = 1000;
+  const uint64_t kWaitingHandles = 1000;
+  const std::string kMessage = "hello";
+  MessagePipe pipe;
+  HandleWatcher watcher;
+  std::string received_message;
+
+  struct TestData {
+    MessagePipe pipe;
+    HandleWatcher watcher;
+  };
+  ScopedVector<TestData> data_vector;
+  for (uint64_t i = 0; i < kWaitingHandles; i++) {
+    scoped_ptr<TestData> test_data(new TestData);
+    ASSERT_TRUE(test_data->pipe.handle0.is_valid());
+    test_data->watcher.Start(
+        test_data->pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+        MOJO_DEADLINE_INDEFINITE, base::Bind(&NeverReached));
+    data_vector.push_back(test_data.Pass());
+  }
+
+  ScopedPerfTimer timer("StartAndSignal_1000Waiting", GetMessageLoopName(),
+                        kIterations);
+  for (uint64_t i = 0; i < kIterations; i++) {
+    base::RunLoop run_loop;
+    watcher.Start(pipe.handle0.get(), MOJO_HANDLE_SIGNAL_READABLE,
+                  MOJO_DEADLINE_INDEFINITE,
+                  base::Bind(&OnWatcherSignaled, run_loop.QuitClosure()));
+    ASSERT_TRUE(mojo::test::WriteTextMessage(pipe.handle1.get(), kMessage));
+    run_loop.Run();
+    watcher.Stop();
+
+    ASSERT_TRUE(
+        mojo::test::ReadTextMessage(pipe.handle0.get(), &received_message));
+    EXPECT_EQ(kMessage, received_message);
+    received_message.clear();
+  }
+}
+
+}  // namespace test
+}  // namespace common
+}  // namespace mojo
diff --git a/mojo/runner/child/native_apptest_target.cc b/mojo/runner/child/native_apptest_target.cc
index a4b2301..36da1b3 100644
--- a/mojo/runner/child/native_apptest_target.cc
+++ b/mojo/runner/child/native_apptest_target.cc
@@ -99,9 +99,8 @@
     CHECK(io_thread.StartWithOptions(io_thread_options));
 
     mojo::embedder::InitIPCSupport(
-        mojo::embedder::ProcessType::NONE, io_thread.task_runner().get(),
-        &process_delegate, io_thread.task_runner().get(),
-        mojo::embedder::ScopedPlatformHandle());
+        mojo::embedder::ProcessType::NONE, &process_delegate,
+        io_thread.task_runner().get(), mojo::embedder::ScopedPlatformHandle());
 
     mojo::InterfaceRequest<mojo::Application> application_request;
     scoped_ptr<mojo::runner::RunnerConnection> connection(
diff --git a/mojo/runner/context.cc b/mojo/runner/context.cc
index 58279f89..014a66a 100644
--- a/mojo/runner/context.cc
+++ b/mojo/runner/context.cc
@@ -203,9 +203,9 @@
       new TaskRunners(base::MessageLoop::current()->task_runner()));
 
   // TODO(vtl): This should be MASTER, not NONE.
-  embedder::InitIPCSupport(
-      embedder::ProcessType::NONE, task_runners_->shell_runner(), this,
-      task_runners_->io_runner(), embedder::ScopedPlatformHandle());
+  embedder::InitIPCSupport(embedder::ProcessType::NONE, this,
+                           task_runners_->io_runner(),
+                           embedder::ScopedPlatformHandle());
 
   package_manager_ = new package_manager::PackageManagerImpl(
       shell_file_root, task_runners_->blocking_pool());
diff --git a/mojo/runner/host/child_process.cc b/mojo/runner/host/child_process.cc
index 0bb20b1..d90358f 100644
--- a/mojo/runner/host/child_process.cc
+++ b/mojo/runner/host/child_process.cc
@@ -109,6 +109,12 @@
     io_runner_ = io_thread_.task_runner().get();
     CHECK(io_runner_.get());
 
+    // TODO(vtl): This should be SLAVE, not NONE.
+    // This must be created before controller_thread_ since MessagePumpMojo will
+    // create a message pipe which requires this code to be run first.
+    embedder::InitIPCSupport(embedder::ProcessType::NONE, this, io_runner_,
+                             embedder::ScopedPlatformHandle());
+
     // Create and start our controller thread.
     base::Thread::Options controller_thread_options;
     controller_thread_options.message_loop_type =
@@ -118,11 +124,6 @@
     CHECK(controller_thread_.StartWithOptions(controller_thread_options));
     controller_runner_ = controller_thread_.task_runner().get();
     CHECK(controller_runner_.get());
-
-    // TODO(vtl): This should be SLAVE, not NONE.
-    embedder::InitIPCSupport(embedder::ProcessType::NONE, controller_runner_,
-                             this, io_runner_,
-                             embedder::ScopedPlatformHandle());
   }
 
   void Shutdown() {
@@ -333,7 +334,6 @@
 
   AppContext app_context;
   app_context.Init();
-
   Blocker blocker;
   app_context.controller_runner()->PostTask(
       FROM_HERE,
diff --git a/mojo/runner/host/child_process_host_unittest.cc b/mojo/runner/host/child_process_host_unittest.cc
index cded872..0ca49c7 100644
--- a/mojo/runner/host/child_process_host_unittest.cc
+++ b/mojo/runner/host/child_process_host_unittest.cc
@@ -69,8 +69,8 @@
 
   ProcessDelegate delegate;
   embedder::InitIPCSupport(
-      embedder::ProcessType::NONE, base::MessageLoop::current()->task_runner(),
-      &delegate, io_thread.task_runner(), embedder::ScopedPlatformHandle());
+      embedder::ProcessType::NONE, &delegate, io_thread.task_runner(),
+      embedder::ScopedPlatformHandle());
 
   TestChildProcessHost child_process_host(blocking_pool.get());
   child_process_host.Start();
diff --git a/mojo/tools/mopy/gtest.py b/mojo/tools/mopy/gtest.py
index 19c9c32..95b5d004 100644
--- a/mojo/tools/mopy/gtest.py
+++ b/mojo/tools/mopy/gtest.py
@@ -44,7 +44,7 @@
     return _run_apptest_with_retry(config, shell, args, apptest)
 
   fixtures = _get_fixtures(config, shell, args, apptest)
-  fixtures = [f for f in fixtures if not f.startswith('DISABLED_')]
+  fixtures = [f for f in fixtures if not '.DISABLED_' in f]
   failed = []
   for fixture in fixtures:
     arguments = args + ['--gtest_filter=%s' % fixture]
@@ -89,6 +89,7 @@
   # Find all fixtures begun from gtest's '[ RUN      ] <Suite.Fixture>' output.
   tests = [x for x in out.split('\n') if x.find('[ RUN      ] ') != -1]
   tests = [x.strip(' \t\n\r')[x.find('[ RUN      ] ') + 13:] for x in tests]
+  tests = tests or [apptest]
 
   # Fail on output with gtest's '[  FAILED  ]' or a lack of '[       OK ]'.
   # The latter check ensures failure on broken command lines, hung output, etc.
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 56f3bb3..b5c4c9b 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -92,6 +92,19 @@
 
 namespace {
 
+enum TestCase {
+  // Test using the SPDY/3.1 protocol.
+  kTestCaseSPDY31,
+
+  // Test using the HTTP/2 protocol, without specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2NoPriorityDependencies,
+
+  // Test using the HTTP/2 protocol, specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2PriorityDependencies
+};
+
 const base::string16 kBar(ASCIIToUTF16("bar"));
 const base::string16 kBar2(ASCIIToUTF16("bar2"));
 const base::string16 kBar3(ASCIIToUTF16("bar3"));
@@ -241,7 +254,7 @@
 
 class HttpNetworkTransactionTest
     : public PlatformTest,
-      public ::testing::WithParamInterface<NextProto> {
+      public ::testing::WithParamInterface<TestCase> {
  public:
   virtual ~HttpNetworkTransactionTest() {
     // Important to restore the per-pool limit first, since the pool limit must
@@ -250,16 +263,19 @@
         HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_);
     ClientSocketPoolManager::set_max_sockets_per_group(
         HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_);
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
   }
 
  protected:
   HttpNetworkTransactionTest()
-      : spdy_util_(GetParam()),
-        session_deps_(GetParam()),
+      : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
+        session_deps_(GetProtocol()),
         old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
             HttpNetworkSession::NORMAL_SOCKET_POOL)),
         old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
             HttpNetworkSession::NORMAL_SOCKET_POOL)) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetDependenciesFromPriority());
   }
 
   struct SimpleGetHelperResult {
@@ -288,9 +304,17 @@
     base::MessageLoop::current()->RunUntilIdle();
   }
 
+  NextProto GetProtocol() const {
+    return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
+  }
+
+  bool GetDependenciesFromPriority() const {
+    return GetParam() == kTestCaseHTTP2PriorityDependencies;
+  }
+
   const char* GetAlternateProtocolFromParam() {
-    return
-        AlternateProtocolToString(AlternateProtocolFromNextProto(GetParam()));
+    return AlternateProtocolToString(
+        AlternateProtocolFromNextProto(GetProtocol()));
   }
 
   std::string GetAlternativeServiceHttpHeader() {
@@ -446,10 +470,11 @@
   int old_max_pool_sockets_;
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         HttpNetworkTransactionTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 namespace {
 
@@ -1400,8 +1425,8 @@
   SSLSocketDataProvider ssl1(ASYNC, OK);
   SSLSocketDataProvider ssl2(ASYNC, OK);
   if (use_spdy) {
-    ssl1.SetNextProto(GetParam());
-    ssl2.SetNextProto(GetParam());
+    ssl1.SetNextProto(GetProtocol());
+    ssl2.SetNextProto(GetProtocol());
   }
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
@@ -4053,7 +4078,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback1;
@@ -4113,7 +4138,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback1;
@@ -4170,6 +4195,7 @@
   // GET with a Proxy-Authorization header.
   scoped_ptr<SpdyFrame> req_get(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, false));
+  spdy_util_.UpdateWithStreamDestruction(1);
   const char* const kExtraAuthorizationHeaders[] = {
     "proxy-authorization", "Basic Zm9vOmJhcg=="
   };
@@ -4213,7 +4239,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback1;
@@ -4310,7 +4336,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
@@ -4339,6 +4365,8 @@
 
 // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server.
 TEST_P(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
+  SpdyTestUtil spdy_util_wrapped(GetProtocol(), GetDependenciesFromPriority());
+
   HttpRequestInfo request;
   request.method = "GET";
   request.url = GURL("https://www.example.org/");
@@ -4359,16 +4387,16 @@
   // fetch https://www.example.org/ via SPDY
   const char kMyUrl[] = "https://www.example.org/";
   scoped_ptr<SpdyFrame> get(
-      spdy_util_.ConstructSpdyGet(kMyUrl, false, 1, LOWEST));
+      spdy_util_wrapped.ConstructSpdyGet(kMyUrl, false, 1, LOWEST));
   scoped_ptr<SpdyFrame> wrapped_get(
       spdy_util_.ConstructWrappedSpdyFrame(get, 1));
   scoped_ptr<SpdyFrame> conn_resp(
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> get_resp(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+      spdy_util_wrapped.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> wrapped_get_resp(
       spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1));
-  scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  scoped_ptr<SpdyFrame> body(spdy_util_wrapped.ConstructSpdyBodyFrame(1, true));
   scoped_ptr<SpdyFrame> wrapped_body(
       spdy_util_.ConstructWrappedSpdyFrame(body, 1));
   scoped_ptr<SpdyFrame> window_update_get_resp(
@@ -4396,10 +4424,10 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
 
   TestCompletionCallback callback1;
@@ -4465,10 +4493,10 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
 
   TestCompletionCallback callback1;
@@ -4529,7 +4557,7 @@
   SpdyHeaderBlock connect2_block;
   spdy_util_.MaybeAddVersionHeader(&connect2_block);
   connect2_block[spdy_util_.GetMethodKey()] = "CONNECT";
-  if (GetParam() == kProtoHTTP2) {
+  if (GetProtocol() == kProtoHTTP2) {
     connect2_block[spdy_util_.GetHostKey()] = "mail.example.org:443";
   } else {
     connect2_block[spdy_util_.GetHostKey()] = "mail.example.org";
@@ -4577,7 +4605,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
@@ -4701,7 +4729,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   SSLSocketDataProvider ssl2(ASYNC, OK);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
@@ -4777,6 +4805,7 @@
       spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body1(
       spdy_util_.ConstructSpdyBodyFrame(1, "1", 1, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   // http://mail.example.org/
   scoped_ptr<SpdyHeaderBlock> headers2(
@@ -4806,7 +4835,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   TestCompletionCallback callback;
@@ -7249,7 +7278,7 @@
   SequencedSocketData data(data_reads, arraysize(data_reads), data_writes,
                            arraysize(data_writes));
   SSLSocketDataProvider proxy_ssl(ASYNC, OK);  // SSL to the proxy
-  proxy_ssl.SetNextProto(GetParam());
+  proxy_ssl.SetNextProto(GetProtocol());
 
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
@@ -7358,7 +7387,7 @@
   SequencedSocketData data(data_reads, arraysize(data_reads), data_writes,
                            arraysize(data_writes));
   SSLSocketDataProvider proxy_ssl(ASYNC, OK);  // SSL to the proxy
-  proxy_ssl.SetNextProto(GetParam());
+  proxy_ssl.SetNextProto(GetProtocol());
 
   session_deps_.socket_factory->AddSocketDataProvider(&data);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
@@ -7399,6 +7428,7 @@
       NULL, 0, 1, LOWEST, HostPortPair("www.example.org", 443)));
   scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   // After calling trans->RestartWithAuth(), this is the request we should
   // be issuing -- the final header line contains the credentials.
@@ -7454,7 +7484,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
   // Negotiate SPDY to the proxy
   SSLSocketDataProvider proxy(ASYNC, OK);
-  proxy.SetNextProto(GetParam());
+  proxy.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
   // Vanilla SSL to the server
   SSLSocketDataProvider server(ASYNC, OK);
@@ -7576,7 +7606,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
   // Negotiate SPDY to the proxy
   SSLSocketDataProvider proxy(ASYNC, OK);
-  proxy.SetNextProto(GetParam());
+  proxy.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
 
   scoped_ptr<HttpTransaction> trans(
@@ -7687,7 +7717,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
   // Negotiate SPDY to the proxy
   SSLSocketDataProvider proxy(ASYNC, OK);
-  proxy.SetNextProto(GetParam());
+  proxy.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
 
   scoped_ptr<HttpTransaction> trans(
@@ -8614,7 +8644,7 @@
     session_deps_.proxy_service =
         ProxyService::CreateFixed(tests[i].proxy_server);
     scoped_ptr<HttpNetworkSession> session(
-        SetupSessionForGroupNameTests(GetParam(), &session_deps_));
+        SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
 
     HttpNetworkSessionPeer peer(session.get());
     CaptureGroupNameTransportSocketPool* transport_conn_pool =
@@ -8676,7 +8706,7 @@
     session_deps_.proxy_service =
         ProxyService::CreateFixed(tests[i].proxy_server);
     scoped_ptr<HttpNetworkSession> session(
-        SetupSessionForGroupNameTests(GetParam(), &session_deps_));
+        SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
 
     HttpNetworkSessionPeer peer(session.get());
 
@@ -8746,7 +8776,7 @@
     session_deps_.proxy_service =
         ProxyService::CreateFixed(tests[i].proxy_server);
     scoped_ptr<HttpNetworkSession> session(
-        SetupSessionForGroupNameTests(GetParam(), &session_deps_));
+        SetupSessionForGroupNameTests(GetProtocol(), &session_deps_));
 
     HttpNetworkSessionPeer peer(session.get());
 
@@ -9456,7 +9486,7 @@
   alternative_service_vector =
       http_server_properties.GetAlternativeServices(http_host_port_pair);
   ASSERT_EQ(1u, alternative_service_vector.size());
-  EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()),
+  EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
             alternative_service_vector[0].protocol);
   EXPECT_EQ("www.example.com", alternative_service_vector[0].host);
   EXPECT_EQ(443, alternative_service_vector[0].port);
@@ -9634,7 +9664,7 @@
   alternative_service_vector =
       http_server_properties.GetAlternativeServices(http_host_port_pair);
   ASSERT_EQ(2u, alternative_service_vector.size());
-  EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()),
+  EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
             alternative_service_vector[0].protocol);
   EXPECT_EQ("www.example.com", alternative_service_vector[0].host);
   EXPECT_EQ(443, alternative_service_vector[0].port);
@@ -9702,7 +9732,7 @@
       http_server_properties.GetAlternativeServices(http_host_port_pair);
   ASSERT_EQ(1u, alternative_service_vector.size());
   EXPECT_EQ(443, alternative_service_vector[0].port);
-  EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()),
+  EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
             alternative_service_vector[0].protocol);
 }
 
@@ -9825,7 +9855,7 @@
   alternative_service_vector =
       http_server_properties.GetAlternativeServices(http_host_port_pair);
   ASSERT_EQ(1u, alternative_service_vector.size());
-  EXPECT_EQ(AlternateProtocolFromNextProto(GetParam()),
+  EXPECT_EQ(AlternateProtocolFromNextProto(GetProtocol()),
             alternative_service_vector[0].protocol);
   EXPECT_EQ("www.example.com", alternative_service_vector[0].host);
   EXPECT_EQ(443, alternative_service_vector[0].port);
@@ -9859,7 +9889,8 @@
   base::WeakPtr<HttpServerProperties> http_server_properties =
       session->http_server_properties();
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "different.example.org", 80);
+      AlternateProtocolFromNextProto(GetProtocol()), "different.example.org",
+      80);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
       HostPortPair::FromURL(request.url), alternative_service, 1.0, expiration);
@@ -9906,7 +9937,7 @@
   // Port must be < 1024, or the header will be ignored (since initial port was
   // port 80 (another restricted port).
   const AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       666);  // Port is ignored by MockConnect anyway.
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -9970,7 +10001,7 @@
       session->http_server_properties();
   const int kUnrestrictedAlternatePort = 1024;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kUnrestrictedAlternatePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10022,7 +10053,7 @@
       session->http_server_properties();
   const int kUnrestrictedAlternatePort = 1024;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kUnrestrictedAlternatePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10073,7 +10104,7 @@
       session->http_server_properties();
   const int kRestrictedAlternatePort = 80;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kRestrictedAlternatePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10125,7 +10156,7 @@
       session->http_server_properties();
   const int kRestrictedAlternatePort = 80;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kRestrictedAlternatePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10176,7 +10207,7 @@
       session->http_server_properties();
   const int kUnrestrictedAlternatePort = 1025;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kUnrestrictedAlternatePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10222,7 +10253,7 @@
       session->http_server_properties();
   const int kUnsafePort = 7;
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), "www.example.org",
+      AlternateProtocolFromNextProto(GetProtocol()), "www.example.org",
       kUnsafePort);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(
@@ -10272,7 +10303,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
   ASSERT_TRUE(ssl.cert.get());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
@@ -10371,7 +10402,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
   ASSERT_TRUE(ssl.cert.get());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
@@ -10478,7 +10509,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
@@ -10618,7 +10649,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
   ASSERT_TRUE(ssl.cert.get());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
@@ -10730,7 +10761,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
   ASSERT_TRUE(ssl.cert.get());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
@@ -11477,7 +11508,7 @@
   request.load_flags = 0;
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   scoped_ptr<SpdyFrame> req(
@@ -11633,7 +11664,7 @@
                              data_writes_2, arraysize(data_writes_2));
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   ssl.cert = ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
   ASSERT_TRUE(ssl.cert.get());
 
@@ -11992,7 +12023,7 @@
   session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
@@ -12392,11 +12423,12 @@
   pool_peer.DisableDomainAuthenticationVerification();
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   scoped_ptr<SpdyFrame> host1_req(
       spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> host2_req(
       spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST));
   MockWrite spdy_writes[] = {
@@ -12491,11 +12523,12 @@
   pool_peer.DisableDomainAuthenticationVerification();
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   scoped_ptr<SpdyFrame> host1_req(
       spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> host2_req(
       spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST));
   MockWrite spdy_writes[] = {
@@ -12621,11 +12654,12 @@
   pool_peer.DisableDomainAuthenticationVerification();
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
   scoped_ptr<SpdyFrame> host1_req(
       spdy_util_.ConstructSpdyGet("https://www.example.org", false, 1, LOWEST));
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> host2_req(
       spdy_util_.ConstructSpdyGet("https://www.gmail.com", false, 3, LOWEST));
   MockWrite spdy_writes[] = {
@@ -12751,7 +12785,7 @@
                             arraysize(writes2));
 
   SSLSocketDataProvider ssl(ASYNC, OK);
-  ssl.SetNextProto(GetParam());
+  ssl.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
@@ -12804,7 +12838,7 @@
     EXPECT_TRUE(
         cert->VerifyNameMatch(alternative.host(), &common_name_fallback_used));
     SSLSocketDataProvider ssl(ASYNC, OK);
-    ssl.SetNextProto(GetParam());
+    ssl.SetNextProto(GetProtocol());
     ssl.cert = cert;
     session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
 
@@ -12828,6 +12862,7 @@
 
     if (pooling) {
       req0.reset(spdy_util_.ConstructSpdyGet(url0.c_str(), false, 1, LOWEST));
+      spdy_util_.UpdateWithStreamDestruction(1);
       req1.reset(spdy_util_.ConstructSpdyGet(url1.c_str(), false, 3, LOWEST));
 
       writes.push_back(CreateMockWrite(*req0, 0));
@@ -12872,7 +12907,7 @@
     base::WeakPtr<HttpServerProperties> http_server_properties =
         session->http_server_properties();
     AlternativeService alternative_service(
-        AlternateProtocolFromNextProto(GetParam()), alternative);
+        AlternateProtocolFromNextProto(GetProtocol()), alternative);
     base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
     http_server_properties->SetAlternativeService(origin, alternative_service,
                                                   1.0, expiration);
@@ -12921,10 +12956,11 @@
   }
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         AltSvcCertificateVerificationTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 // The alternative service host must exhibit a certificate that is valid for the
 // origin host.  Test that this is enforced when pooling to an existing
@@ -12976,7 +13012,7 @@
   base::WeakPtr<HttpServerProperties> http_server_properties =
       session->http_server_properties();
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), alternative);
+      AlternateProtocolFromNextProto(GetProtocol()), alternative);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(origin, alternative_service,
                                                 1.0, expiration);
@@ -13049,7 +13085,7 @@
   base::WeakPtr<HttpServerProperties> http_server_properties =
       session->http_server_properties();
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), alternative);
+      AlternateProtocolFromNextProto(GetProtocol()), alternative);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(origin, alternative_service,
                                                 1.0, expiration);
@@ -13158,7 +13194,7 @@
   base::WeakPtr<HttpServerProperties> http_server_properties =
       session->http_server_properties();
   AlternativeService alternative_service(
-      AlternateProtocolFromNextProto(GetParam()), alternative);
+      AlternateProtocolFromNextProto(GetProtocol()), alternative);
   base::Time expiration = base::Time::Now() + base::TimeDelta::FromDays(1);
   http_server_properties->SetAlternativeService(origin, alternative_service,
                                                 1.0, expiration);
@@ -13227,12 +13263,15 @@
   const std::string https_url = "https://www.example.org:8080/";
   const std::string http_url = "http://www.example.org:8080/";
 
+  // Separate SPDY util instance for naked and wrapped requests.
+  SpdyTestUtil spdy_util_wrapped(GetProtocol(), GetDependenciesFromPriority());
+
   // SPDY GET for HTTPS URL (through CONNECT tunnel)
   const HostPortPair host_port_pair("www.example.org", 8080);
   scoped_ptr<SpdyFrame> connect(
       spdy_util_.ConstructSpdyConnect(NULL, 0, 1, LOWEST, host_port_pair));
   scoped_ptr<SpdyFrame> req1(
-      spdy_util_.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST));
+      spdy_util_wrapped.ConstructSpdyGet(https_url.c_str(), false, 1, LOWEST));
   scoped_ptr<SpdyFrame> wrapped_req1(
       spdy_util_.ConstructWrappedSpdyFrame(req1, 1));
 
@@ -13257,9 +13296,9 @@
   scoped_ptr<SpdyFrame> resp1(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body1(spdy_util_.ConstructSpdyBodyFrame(1, true));
   scoped_ptr<SpdyFrame> wrapped_resp1(
-      spdy_util_.ConstructWrappedSpdyFrame(resp1, 1));
+      spdy_util_wrapped.ConstructWrappedSpdyFrame(resp1, 1));
   scoped_ptr<SpdyFrame> wrapped_body1(
-      spdy_util_.ConstructWrappedSpdyFrame(body1, 1));
+      spdy_util_wrapped.ConstructWrappedSpdyFrame(body1, 1));
   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, true));
   MockRead reads1[] = {
@@ -13281,10 +13320,10 @@
   TestNetLog log;
   session_deps_.net_log = &log;
   SSLSocketDataProvider ssl1(ASYNC, OK);  // to the proxy
-  ssl1.SetNextProto(GetParam());
+  ssl1.SetNextProto(GetProtocol());
   session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl1);
   SSLSocketDataProvider ssl2(ASYNC, OK);  // to the server
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2);
   session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data1);
 
@@ -13344,6 +13383,9 @@
   const std::string url2 = "https://news.example.org/";
   const std::string ip_addr = "1.2.3.4";
 
+  // Second SpdyTestUtil instance for the second socket.
+  SpdyTestUtil spdy_util_secure(GetProtocol(), GetDependenciesFromPriority());
+
   // SPDY GET for HTTP URL (through SPDY proxy)
   scoped_ptr<SpdyHeaderBlock> headers(
       spdy_util_.ConstructGetHeaderBlockForProxy("http://www.example.org/"));
@@ -13373,14 +13415,15 @@
 
   // SPDY GET for HTTPS URL (direct)
   scoped_ptr<SpdyFrame> req2(
-      spdy_util_.ConstructSpdyGet(url2.c_str(), false, 1, MEDIUM));
+      spdy_util_secure.ConstructSpdyGet(url2.c_str(), false, 1, MEDIUM));
 
   MockWrite writes2[] = {
     CreateMockWrite(*req2, 0),
   };
 
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  scoped_ptr<SpdyFrame> resp2(
+      spdy_util_secure.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> body2(spdy_util_secure.ConstructSpdyBodyFrame(1, true));
   MockRead reads2[] = {
       CreateMockRead(*resp2, 1),
       CreateMockRead(*body2, 2),
@@ -13402,7 +13445,7 @@
       NULL));
 
   SSLSocketDataProvider ssl1(ASYNC, OK);  // to the proxy
-  ssl1.SetNextProto(GetParam());
+  ssl1.SetNextProto(GetProtocol());
   // Load a valid cert.  Note, that this does not need to
   // be valid for proxy because the MockSSLClientSocket does
   // not actually verify it.  But SpdySession will use this
@@ -13414,7 +13457,7 @@
       data1.get());
 
   SSLSocketDataProvider ssl2(ASYNC, OK);  // to the server
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl2);
   session_deps_.deterministic_socket_factory->AddSocketDataProvider(
       data2.get());
@@ -13489,12 +13532,12 @@
                             arraysize(writes2));
 
   SSLSocketDataProvider ssl1(ASYNC, OK);
-  ssl1.SetNextProto(GetParam());
+  ssl1.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
 
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
 
@@ -13540,9 +13583,9 @@
   scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
   SSLSocketDataProvider ssl1(ASYNC, OK);
-  ssl1.SetNextProto(GetParam());
+  ssl1.SetNextProto(GetProtocol());
   SSLSocketDataProvider ssl2(ASYNC, OK);
-  ssl2.SetNextProto(GetParam());
+  ssl2.SetNextProto(GetProtocol());
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
   session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
 
@@ -13561,20 +13604,23 @@
       MockRead(ASYNC, ERR_IO_PENDING, 3),
   };
 
+  // Use a separate test instance for the separate SpdySession that will be
+  // created.
+  SpdyTestUtil spdy_util_2(GetProtocol(), GetDependenciesFromPriority());
   scoped_ptr<SequencedSocketData> spdy1_data(
       new SequencedSocketData(spdy1_reads, arraysize(spdy1_reads), spdy1_writes,
                               arraysize(spdy1_writes)));
   session_deps_.socket_factory->AddSocketDataProvider(spdy1_data.get());
 
-  scoped_ptr<SpdyFrame> host2_req(spdy_util_.ConstructSpdyGet(
+  scoped_ptr<SpdyFrame> host2_req(spdy_util_2.ConstructSpdyGet(
       "https://www.b.com", false, 1, DEFAULT_PRIORITY));
   MockWrite spdy2_writes[] = {
       CreateMockWrite(*host2_req, 0),
   };
   scoped_ptr<SpdyFrame> host2_resp(
-      spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+      spdy_util_2.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> host2_resp_body(
-      spdy_util_.ConstructSpdyBodyFrame(1, true));
+      spdy_util_2.ConstructSpdyBodyFrame(1, true));
   MockRead spdy2_reads[] = {
       CreateMockRead(*host2_resp, 1),
       CreateMockRead(*host2_resp_body, 2),
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index bcc6299..f2f0419 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -41,16 +41,19 @@
 struct HttpProxyClientSocketPoolTestParams {
   HttpProxyClientSocketPoolTestParams()
       : proxy_type(HTTP),
-        protocol(kProtoSPDY31) {}
+        protocol(kProtoSPDY31),
+        priority_to_dependency(false) {}
 
-  HttpProxyClientSocketPoolTestParams(
-      HttpProxyType proxy_type,
-      NextProto protocol)
+  HttpProxyClientSocketPoolTestParams(HttpProxyType proxy_type,
+                                      NextProto protocol,
+                                      bool priority_to_dependency)
       : proxy_type(proxy_type),
-        protocol(protocol) {}
+        protocol(protocol),
+        priority_to_dependency(priority_to_dependency) {}
 
   HttpProxyType proxy_type;
   NextProto protocol;
+  bool priority_to_dependency;
 };
 
 typedef ::testing::TestWithParam<HttpProxyType> TestWithHttpParam;
@@ -149,6 +152,7 @@
   std::string on_tunnel_headers_received_status_line_;
 };
 
+}  // namespace
 
 class HttpProxyClientSocketPoolTest
     : public ::testing::TestWithParam<HttpProxyClientSocketPoolTestParams> {
@@ -173,14 +177,18 @@
                          session_deps_.ssl_config_service.get(),
                          BoundNetLog().net_log()),
         session_(CreateNetworkSession()),
-        spdy_util_(GetParam().protocol),
+        spdy_util_(GetParam().protocol, GetParam().priority_to_dependency),
         pool_(kMaxSockets,
               kMaxSocketsPerGroup,
               &transport_socket_pool_,
               &ssl_socket_pool_,
-              NULL) {}
+              NULL) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetParam().priority_to_dependency);
+  }
 
   virtual ~HttpProxyClientSocketPoolTest() {
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
   }
 
   void AddAuthToCache() {
@@ -323,12 +331,16 @@
 INSTANTIATE_TEST_CASE_P(
     HttpProxyClientSocketPoolTests,
     HttpProxyClientSocketPoolTest,
-    ::testing::Values(HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
-                      HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
-                      HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
-                      HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2),
-                      HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2),
-                      HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2)));
+    ::testing::Values(
+        HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31, false),
+        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31, false),
+        HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31, false),
+        HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2, false),
+        HttpProxyClientSocketPoolTestParams(HTTP, kProtoHTTP2, true),
+        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2, false),
+        HttpProxyClientSocketPoolTestParams(HTTPS, kProtoHTTP2, true),
+        HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2, false),
+        HttpProxyClientSocketPoolTestParams(SPDY, kProtoHTTP2, true)));
 
 TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
   Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
@@ -812,6 +824,4 @@
 
 // It would be nice to also test the timeouts in HttpProxyClientSocketPool.
 
-}  // namespace
-
 }  // namespace net
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index fc2989a..3e869737 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -34,6 +34,19 @@
 
 namespace {
 
+enum TestCase {
+  // Test using the SPDY/3.1 protocol.
+  kTestCaseSPDY31,
+
+  // Test using the HTTP/2 protocol, without specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2NoPriorityDependencies,
+
+  // Test using the HTTP/2 protocol, specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2PriorityDependencies
+};
+
 // Tests the load timing of a stream that's connected and is not the first
 // request sent on a connection.
 void TestLoadTimingReused(const HttpStream& stream) {
@@ -64,15 +77,29 @@
 }  // namespace
 
 class SpdyHttpStreamTest : public testing::Test,
-                           public testing::WithParamInterface<NextProto> {
+                           public testing::WithParamInterface<TestCase> {
  public:
   SpdyHttpStreamTest()
-      : spdy_util_(GetParam()),
-        session_deps_(GetParam()) {
+      : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
+        session_deps_(GetProtocol()) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetDependenciesFromPriority());
     session_deps_.net_log = &net_log_;
   }
 
+  ~SpdyHttpStreamTest() {
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
+  }
+
  protected:
+  NextProto GetProtocol() const {
+    return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
+  }
+
+  bool GetDependenciesFromPriority() const {
+    return GetParam() == kTestCaseHTTP2PriorityDependencies;
+  }
+
   void TearDown() override {
     crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
     base::MessageLoop::current()->RunUntilIdle();
@@ -110,10 +137,11 @@
   MockECSignatureCreatorFactory ec_signature_creator_factory_;
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         SpdyHttpStreamTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 // SpdyHttpStream::GetUploadProgress() should still work even before the
 // stream is initialized.
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index bb63d96..ad10078 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -65,11 +65,16 @@
 
 struct SpdyNetworkTransactionTestParams {
   SpdyNetworkTransactionTestParams()
-      : protocol(kProtoSPDY31), ssl_type(HTTPS_SPDY_VIA_NPN) {}
+      : protocol(kProtoSPDY31),
+        ssl_type(HTTPS_SPDY_VIA_NPN),
+        priority_to_dependency(false) {}
 
   SpdyNetworkTransactionTestParams(NextProto protocol,
-                                   SpdyNetworkTransactionTestSSLType ssl_type)
-      : protocol(protocol), ssl_type(ssl_type) {}
+                                   SpdyNetworkTransactionTestSSLType ssl_type,
+                                   bool priority_to_dependency)
+      : protocol(protocol),
+        ssl_type(ssl_type),
+        priority_to_dependency(priority_to_dependency) {}
 
   friend std::ostream& operator<<(std::ostream& os,
                                   const SpdyNetworkTransactionTestParams& p) {
@@ -83,12 +88,14 @@
         break;
     }
     os << "{ protocol: " << SSLClientSocket::NextProtoToString(p.protocol)
-       << ", ssl_type: " << type_str << " }";
+       << ", ssl_type: " << type_str
+       << ", priority_to_dependency: " << p.priority_to_dependency << " }";
     return os;
   }
 
   NextProto protocol;
   SpdyNetworkTransactionTestSSLType ssl_type;
+  bool priority_to_dependency;
 };
 
 void UpdateSpdySessionDependencies(SpdyNetworkTransactionTestParams test_params,
@@ -127,7 +134,10 @@
 class SpdyNetworkTransactionTest
     : public ::testing::TestWithParam<SpdyNetworkTransactionTestParams> {
  protected:
-  SpdyNetworkTransactionTest() : spdy_util_(GetParam().protocol) {
+  SpdyNetworkTransactionTest()
+      : spdy_util_(GetParam().protocol, GetParam().priority_to_dependency) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetParam().priority_to_dependency);
     spdy_util_.set_default_url(GURL(GetDefaultUrl()));
   }
 
@@ -136,6 +146,7 @@
     // destruction.
     upload_data_stream_.reset();
     base::RunLoop().RunUntilIdle();
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
   }
 
   void SetUp() override {
@@ -712,10 +723,22 @@
     Spdy,
     SpdyNetworkTransactionTest,
     ::testing::Values(
-        SpdyNetworkTransactionTestParams(kProtoSPDY31, HTTPS_SPDY_VIA_NPN),
-        SpdyNetworkTransactionTestParams(kProtoSPDY31, HTTP_SPDY_VIA_ALT_SVC),
-        SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTPS_SPDY_VIA_NPN),
-        SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTP_SPDY_VIA_ALT_SVC)));
+        SpdyNetworkTransactionTestParams(kProtoSPDY31,
+                                         HTTPS_SPDY_VIA_NPN,
+                                         false),
+        SpdyNetworkTransactionTestParams(kProtoSPDY31,
+                                         HTTP_SPDY_VIA_ALT_SVC,
+                                         false),
+        SpdyNetworkTransactionTestParams(kProtoHTTP2,
+                                         HTTPS_SPDY_VIA_NPN,
+                                         false),
+        SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTPS_SPDY_VIA_NPN, true),
+        SpdyNetworkTransactionTestParams(kProtoHTTP2,
+                                         HTTP_SPDY_VIA_ALT_SVC,
+                                         false),
+        SpdyNetworkTransactionTestParams(kProtoHTTP2,
+                                         HTTP_SPDY_VIA_ALT_SVC,
+                                         true)));
 
 // Verify HttpNetworkTransaction constructor.
 TEST_P(SpdyNetworkTransactionTest, Constructor) {
@@ -757,6 +780,7 @@
     // Construct the request.
     scoped_ptr<SpdyFrame> req(
         spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, p, true));
+    spdy_util_.UpdateWithStreamDestruction(1);
     MockWrite writes[] = {CreateMockWrite(*req, 0)};
 
     SpdyPriority spdy_prio = 0;
@@ -1122,17 +1146,20 @@
 // second transaction completes, so we can assert on read_index().
 TEST_P(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
   // Construct the request.
+  // Each request fully completes before the next starts.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
   scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
   scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
+  spdy_util_.UpdateWithStreamDestruction(3);
 
   scoped_ptr<SpdyFrame> req3(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, LOWEST, true));
@@ -1255,17 +1282,20 @@
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
   scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
   scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 3));
   scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(3, false));
   scoped_ptr<SpdyFrame> fbody2(spdy_util_.ConstructSpdyBodyFrame(3, true));
+  spdy_util_.UpdateWithStreamDestruction(3);
 
   scoped_ptr<SpdyFrame> req4(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, HIGHEST, true));
   scoped_ptr<SpdyFrame> resp4(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 5));
   scoped_ptr<SpdyFrame> fbody4(spdy_util_.ConstructSpdyBodyFrame(5, true));
+  spdy_util_.UpdateWithStreamDestruction(5);
 
   scoped_ptr<SpdyFrame> req3(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 7, LOWEST, true));
@@ -1404,6 +1434,7 @@
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
   scoped_ptr<SpdyFrame> fbody(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
@@ -1535,6 +1566,7 @@
   scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
   scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false));
   scoped_ptr<SpdyFrame> fin_body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
 
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
@@ -3086,6 +3118,7 @@
                                  test_cases[i].num_headers,
                                  1));
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+    spdy_util_.UpdateWithStreamDestruction(1);
     MockRead reads[] = {
         CreateMockRead(*resp, 1),
         CreateMockRead(*body, 2),
@@ -3183,6 +3216,7 @@
         spdy_util_.ConstructSpdyReply(1, reply_headers));
 
     scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+    spdy_util_.UpdateWithStreamDestruction(1);
     MockRead reads[] = {
         CreateMockRead(*frame_reply, 1),
         CreateMockRead(*body, 2),
@@ -3260,6 +3294,7 @@
         spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
     scoped_ptr<SpdyFrame> rst(
       spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_PROTOCOL_ERROR));
+    spdy_util_.UpdateWithStreamDestruction(1);
     MockWrite writes[] = {
         CreateMockWrite(*req, 0), CreateMockWrite(*rst, 2),
     };
@@ -4668,16 +4703,21 @@
       PRIVACY_MODE_DISABLED);
   EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
 
+  // New SpdyTestUtil instance for the session that will be used for the
+  // proxy connection.
+  SpdyTestUtil spdy_util_2(GetParam().protocol,
+                           GetParam().priority_to_dependency);
+
   // Set up data for the proxy connection.
   const char kConnect443[] = {
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org\r\n"
       "Proxy-Connection: keep-alive\r\n\r\n"};
   const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
-  scoped_ptr<SpdyFrame> req2(spdy_util_.ConstructSpdyGet(
+  scoped_ptr<SpdyFrame> req2(spdy_util_2.ConstructSpdyGet(
       GetDefaultUrlWithPath("/foo.dat").c_str(), false, 1, LOWEST));
-  scoped_ptr<SpdyFrame> resp2(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
-  scoped_ptr<SpdyFrame> body2(spdy_util_.ConstructSpdyBodyFrame(1, true));
+  scoped_ptr<SpdyFrame> resp2(spdy_util_2.ConstructSpdyGetSynReply(NULL, 0, 1));
+  scoped_ptr<SpdyFrame> body2(spdy_util_2.ConstructSpdyBodyFrame(1, true));
 
   MockWrite writes2[] = {
       MockWrite(SYNCHRONOUS, kConnect443, arraysize(kConnect443) - 1, 0),
@@ -4755,6 +4795,9 @@
 
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  // In all cases the connection will be reset before req3 can be
+  // dispatched, destroying both streams.
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> req3(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
   MockWrite writes1[] = {CreateMockWrite(*req, 0), CreateMockWrite(*req3, 5)};
@@ -4882,6 +4925,8 @@
   // GET with an Authorization header.
   scoped_ptr<SpdyFrame> req_get(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  // Will be refused for lack of auth.
+  spdy_util_.UpdateWithStreamDestruction(1);
   const char* const kExtraAuthorizationHeaders[] = {
     "authorization", "Basic Zm9vOmJhcg=="
   };
@@ -5510,6 +5555,7 @@
         spdy_util_.ConstructSpdyGet(url_to_fetch, false, 1, LOWEST));
     scoped_ptr<SpdyFrame> stream1_body(
         spdy_util_.ConstructSpdyBodyFrame(1, true));
+    spdy_util_.UpdateWithStreamDestruction(1);
     scoped_ptr<SpdyFrame> push_rst(
         spdy_util_.ConstructSpdyRstStream(2, RST_STREAM_REFUSED_STREAM));
     MockWrite writes[] = {
@@ -5591,6 +5637,8 @@
   // Construct the request.
   scoped_ptr<SpdyFrame> req(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
+  // Will be destroyed by the RST before stream 3 starts.
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, LOWEST, true));
   MockWrite writes[] = {
@@ -5641,10 +5689,22 @@
   // (HIGHEST priority) request in such a way that the third will actually
   // start before the second, causing the second to be numbered differently
   // than the order they were created.
+  //
+  // Note that the requests and responses created below are expectations
+  // of what the above will produce on the wire, and hence are in the
+  // initial->HIGHEST->LOWEST priority.
+  //
+  // Frames are created by SpdySession just before the write associated
+  // with the frame is attempted, so stream dependencies will be based
+  // on the streams alive at the point of the request write attempt.  Thus
+  // req1 is alive when req2 is attempted (during but not after the
+  // |data.RunFor(2);| statement below) but not when req3 is attempted.
+  // The call to spdy_util_.UpdateWithStreamDestruction() reflects this.
   scoped_ptr<SpdyFrame> req1(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 3, HIGHEST, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> req3(
       spdy_util_.ConstructSpdyGet(NULL, 0, false, 5, MEDIUM, true));
   MockWrite writes[] = {
@@ -6532,7 +6592,8 @@
     Spdy,
     SpdyNetworkTransactionNoTLSUsageCheckTest,
     ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY31,
-                                                       HTTPS_SPDY_VIA_NPN)));
+                                                       HTTPS_SPDY_VIA_NPN,
+                                                       false)));
 
 TEST_P(SpdyNetworkTransactionNoTLSUsageCheckTest, TLSVersionTooOld) {
   scoped_ptr<SSLSocketDataProvider> ssl_provider(
@@ -6575,8 +6636,12 @@
 INSTANTIATE_TEST_CASE_P(
     Spdy,
     SpdyNetworkTransactionTLSUsageCheckTest,
-    ::testing::Values(
-        SpdyNetworkTransactionTestParams(kProtoHTTP2, HTTPS_SPDY_VIA_NPN)));
+    ::testing::Values(SpdyNetworkTransactionTestParams(kProtoHTTP2,
+                                                       HTTPS_SPDY_VIA_NPN,
+                                                       false),
+                      SpdyNetworkTransactionTestParams(kProtoHTTP2,
+                                                       HTTPS_SPDY_VIA_NPN,
+                                                       true)));
 
 TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
   scoped_ptr<SSLSocketDataProvider> ssl_provider(
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 0a2ae8e..67fbf3a 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -33,6 +33,19 @@
 
 namespace {
 
+enum TestCase {
+  // Test using the SPDY/3.1 protocol.
+  kTestCaseSPDY31,
+
+  // Test using the HTTP/2 protocol, without specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2NoPriorityDependencies,
+
+  // Test using the HTTP/2 protocol, specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2PriorityDependencies
+};
+
 static const char kRequestUrl[] = "https://www.google.com/";
 static const char kOriginHost[] = "www.google.com";
 static const int kOriginPort = 443;
@@ -61,15 +74,18 @@
 
 namespace net {
 
-class SpdyProxyClientSocketTest
-    : public PlatformTest,
-      public testing::WithParamInterface<NextProto> {
+class SpdyProxyClientSocketTest : public PlatformTest,
+                                  public testing::WithParamInterface<TestCase> {
  public:
   SpdyProxyClientSocketTest();
+  ~SpdyProxyClientSocketTest();
 
   void TearDown() override;
 
  protected:
+  NextProto GetProtocol() const;
+  bool GetDependenciesFromPriority() const;
+
   void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes,
                   size_t writes_count);
   void PopulateConnectRequestIR(SpdyHeaderBlock* syn_ir);
@@ -140,15 +156,16 @@
   DISALLOW_COPY_AND_ASSIGN(SpdyProxyClientSocketTest);
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         SpdyProxyClientSocketTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
-    : spdy_util_(GetParam()),
+    : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
       read_buf_(NULL),
-      session_deps_(GetParam()),
+      session_deps_(GetProtocol()),
       connect_data_(SYNCHRONOUS, OK),
       framer_(spdy_util_.spdy_version(), false),
       user_agent_(kUserAgent),
@@ -160,6 +177,12 @@
                                  proxy_,
                                  PRIVACY_MODE_DISABLED) {
   session_deps_.net_log = net_log_.bound().net_log();
+  SpdySession::SetPriorityDependencyDefaultForTesting(
+      GetDependenciesFromPriority());
+}
+
+SpdyProxyClientSocketTest::~SpdyProxyClientSocketTest() {
+  SpdySession::SetPriorityDependencyDefaultForTesting(false);
 }
 
 void SpdyProxyClientSocketTest::TearDown() {
@@ -171,6 +194,14 @@
   PlatformTest::TearDown();
 }
 
+NextProto SpdyProxyClientSocketTest::GetProtocol() const {
+  return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
+}
+
+bool SpdyProxyClientSocketTest::GetDependenciesFromPriority() const {
+  return GetParam() == kTestCaseHTTP2PriorityDependencies;
+}
+
 void SpdyProxyClientSocketTest::Initialize(MockRead* reads,
                                                 size_t reads_count,
                                                 MockWrite* writes,
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 80e24c6..28bab83 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -59,6 +59,14 @@
 // Minimum seconds that unclaimed pushed streams will be kept in memory.
 const int kMinPushedStreamLifetimeSeconds = 300;
 
+// Field trial constants
+const char kSpdyDependenciesFieldTrial[] = "SpdyEnableDependencies";
+const char kSpdyDepencenciesFieldTrialEnable[] = "Enable";
+
+// Whether the creation of SPDY dependencies based on priority is
+// enabled by default.
+static bool priority_dependency_enabled_default = false;
+
 scoped_ptr<base::ListValue> SpdyHeaderBlockToListValue(
     const SpdyHeaderBlock& headers,
     NetLogCaptureMode capture_mode) {
@@ -691,6 +699,7 @@
       hung_interval_(base::TimeDelta::FromSeconds(kHungIntervalSeconds)),
       trusted_spdy_proxy_(trusted_spdy_proxy),
       time_func_(time_func),
+      send_priority_dependency_(priority_dependency_enabled_default),
       weak_factory_(this) {
   DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
   DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
@@ -700,6 +709,10 @@
       base::Bind(&NetLogSpdySessionCallback, &host_port_proxy_pair()));
   next_unclaimed_push_stream_sweep_time_ = time_func_() +
       base::TimeDelta::FromSeconds(kMinPushedStreamLifetimeSeconds);
+  if (base::FieldTrialList::FindFullName(kSpdyDependenciesFieldTrial) ==
+      kSpdyDepencenciesFieldTrialEnable) {
+    send_priority_dependency_ = true;
+  }
   // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
 }
 
@@ -1045,6 +1058,11 @@
   return false;
 }
 
+// static
+void SpdySession::SetPriorityDependencyDefaultForTesting(bool enable) {
+  priority_dependency_enabled_default = enable;
+}
+
 void SpdySession::EnqueueStreamWrite(
     const base::WeakPtr<SpdyStream>& stream,
     SpdyFrameType frame_type,
@@ -1085,6 +1103,41 @@
     SpdyHeadersIR headers(stream_id);
     headers.set_priority(spdy_priority);
     headers.set_has_priority(true);
+
+    if (send_priority_dependency_) {
+      // Set dependencies to reflect request priority.  A newly created
+      // stream should be dependent on the most recent previously created
+      // stream of the same priority level.  The newly created stream
+      // should also have all streams of a lower priority level dependent
+      // on it, which is guaranteed by setting the exclusive bit.
+      //
+      // Note that this depends on stream ids being allocated in a monotonically
+      // increasing fashion, and on all streams in
+      // active_streams_{,by_priority_} having stream ids set.
+      for (int i = priority; i >= IDLE; --i) {
+        if (active_streams_by_priority_[i].empty())
+          continue;
+
+        auto candidate_it = active_streams_by_priority_[i].rbegin();
+
+        // |active_streams_by_priority_| is updated before the
+        // SYN stream frame is created, so the current streams
+        // id is already on the list.  Skip over it, skipping this
+        // priority level if it's singular.
+        if (candidate_it->second->stream_id() == stream_id)
+          ++candidate_it;
+        if (candidate_it == active_streams_by_priority_[i].rend())
+          continue;
+
+        headers.set_parent_stream_id(candidate_it->second->stream_id());
+        break;
+      }
+
+      // If there are no streams of priority <= the current stream, the
+      // current stream will default to a child of the idle node (0).
+      headers.set_exclusive(true);
+    }
+
     headers.set_fin((flags & CONTROL_FLAG_FIN) != 0);
     headers.set_header_block(block);
     syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers));
@@ -1291,6 +1344,8 @@
 
   scoped_ptr<SpdyStream> owned_stream(it->second.stream);
   active_streams_.erase(it);
+  active_streams_by_priority_[owned_stream->priority()].erase(
+      owned_stream->stream_id());
 
   // TODO(akalin): When SpdyStream was ref-counted (and
   // |unclaimed_pushed_streams_| held scoped_refptr<SpdyStream>), this
@@ -1952,6 +2007,8 @@
   std::pair<ActiveStreamMap::iterator, bool> result =
       active_streams_.insert(
           std::make_pair(stream_id, ActiveStreamInfo(stream.get())));
+  active_streams_by_priority_[stream->priority()].insert(
+      std::make_pair(stream_id, stream.get()));
   CHECK(result.second);
   ignore_result(stream.release());
 }
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 3ad5d27..1acfe1b 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -39,6 +39,10 @@
 
 namespace net {
 
+namespace test {
+class SpdyStreamTest;
+}
+
 // This is somewhat arbitrary and not really fixed, but it will always work
 // reasonably with ethernet. Chop the world into 2-packet chunks.  This is
 // somewhat arbitrary, but is reasonably small and ensures that we elicit
@@ -517,9 +521,15 @@
   bool CloseOneIdleConnection() override;
 
  private:
+  friend class test::SpdyStreamTest;
   friend class base::RefCounted<SpdySession>;
-  friend class SpdyStreamRequest;
+  friend class HttpNetworkTransactionTest;
+  friend class HttpProxyClientSocketPoolTest;
+  friend class SpdyHttpStreamTest;
+  friend class SpdyNetworkTransactionTest;
+  friend class SpdyProxyClientSocketTest;
   friend class SpdySessionTest;
+  friend class SpdyStreamRequest;
 
   // Allow tests to access our innards for testing purposes.
   FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, ClientPing);
@@ -548,6 +558,7 @@
   FRIEND_TEST_ALL_PREFIXES(SpdySessionTest,
                            CancelReservedStreamOnHeadersReceived);
   FRIEND_TEST_ALL_PREFIXES(SpdySessionTest, RejectInvalidUnknownFrames);
+  FRIEND_TEST_ALL_PREFIXES(SpdySessionPoolTest, IPAddressChanged);
 
   typedef std::deque<base::WeakPtr<SpdyStreamRequest> >
       PendingStreamRequestQueue;
@@ -958,6 +969,10 @@
 
   size_t max_concurrent_streams() const { return max_concurrent_streams_; }
 
+  // Set whether priority->dependency conversion is enabled
+  // by default for all future SpdySessions.
+  static void SetPriorityDependencyDefaultForTesting(bool enable);
+
   // Whether Do{Read,Write}Loop() is in the call stack. Useful for
   // making sure we don't destroy ourselves prematurely in that case.
   bool in_io_loop_;
@@ -1004,6 +1019,14 @@
   // them?
   ActiveStreamMap active_streams_;
 
+  // Per-priority map from stream id to all active streams.  This map will
+  // contain the same set of streams as |active_streams_|.  It is used for
+  // setting dependencies to match incoming requests RequestPriority.
+  //
+  // |active_streams_by_priority_| does *not* own its SpdyStream objects.
+  std::map<SpdyStreamId, SpdyStream*>
+      active_streams_by_priority_[NUM_PRIORITIES];
+
   // (Bijective) map from the URL to the ID of the streams that have
   // already started to be pushed by the server, but do not have
   // consumers yet. Contains a subset of |active_streams_|.
@@ -1182,6 +1205,10 @@
 
   TimeFunc time_func_;
 
+  // Should priority-based dependency information be sent in stream header
+  // frames.
+  bool send_priority_dependency_;
+
   // Used for posting asynchronous IO tasks.  We use this even though
   // SpdySession is refcounted because we don't need to keep the SpdySession
   // alive if the last reference is within a RunnableMethod.  Just revoke the
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 86b3b4a..55432456 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -20,8 +20,6 @@
 
 namespace net {
 
-namespace {
-
 class SpdySessionPoolTest : public ::testing::Test,
                             public ::testing::WithParamInterface<NextProto> {
  protected:
@@ -510,7 +508,13 @@
 TEST_P(SpdySessionPoolTest, IPAddressChanged) {
   MockConnect connect_data(SYNCHRONOUS, OK);
   session_deps_.host_resolver->set_synchronous_mode(true);
-  SpdyTestUtil spdy_util(GetParam());
+
+  // This isn't testing anything having to do with SPDY frames; we
+  // can ignore issues of how dependencies are set.  We default to
+  // setting them (when doing the appropriate protocol) since that's
+  // where we're eventually headed for all HTTP/2 connections.
+  SpdyTestUtil spdy_util(GetParam(), true);
+  SpdySession::SetPriorityDependencyDefaultForTesting(true);
 
   MockRead reads[] = {
       MockRead(SYNCHRONOUS, ERR_IO_PENDING)  // Stall forever.
@@ -613,8 +617,7 @@
   EXPECT_TRUE(delegateB.StreamIsClosed());
   EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
 #endif  // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
+  SpdySession::SetPriorityDependencyDefaultForTesting(false);
 }
 
-}  // namespace
-
 }  // namespace net
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 98a6c2d5..629a14c 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -35,6 +35,19 @@
 
 namespace {
 
+enum TestCase {
+  // Test using the SPDY/3.1 protocol.
+  kTestCaseSPDY31,
+
+  // Test using the HTTP/2 protocol, without specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2NoPriorityDependencies,
+
+  // Test using the HTTP/2 protocol, specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2PriorityDependencies
+};
+
 const char kBodyData[] = "Body data";
 const size_t kBodyDataSize = arraysize(kBodyData);
 const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize);
@@ -59,7 +72,7 @@
 }  // namespace
 
 class SpdySessionTest : public PlatformTest,
-                        public ::testing::WithParamInterface<NextProto> {
+                        public ::testing::WithParamInterface<TestCase> {
  public:
   // Functions used with RunResumeAfterUnstallTest().
 
@@ -96,19 +109,30 @@
   }
 
  protected:
+  NextProto GetProtocol() const {
+    return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
+  }
+
+  bool GetDependenciesFromPriority() const {
+    return GetParam() == kTestCaseHTTP2PriorityDependencies;
+  }
+
   SpdySessionTest()
       : old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
             HttpNetworkSession::NORMAL_SOCKET_POOL)),
         old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
             HttpNetworkSession::NORMAL_SOCKET_POOL)),
-        spdy_util_(GetParam()),
-        session_deps_(GetParam()),
+        spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
+        session_deps_(GetProtocol()),
         spdy_session_pool_(nullptr),
         test_url_(kDefaultURL),
         test_host_port_pair_(HostPortPair::FromURL(test_url_)),
         key_(test_host_port_pair_,
              ProxyServer::Direct(),
-             PRIVACY_MODE_DISABLED) {}
+             PRIVACY_MODE_DISABLED) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetDependenciesFromPriority());
+  }
 
   virtual ~SpdySessionTest() {
     // Important to restore the per-pool limit first, since the pool limit must
@@ -117,6 +141,7 @@
         HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_);
     ClientSocketPoolManager::set_max_sockets_per_group(
         HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_);
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
   }
 
   void SetUp() override {
@@ -183,10 +208,11 @@
   BoundTestNetLog log_;
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         SpdySessionTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 // Try to create a SPDY session that will fail during
 // initialization. Nothing should blow up.
@@ -1218,9 +1244,9 @@
   if (session_->flow_control_state_ ==
       SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
     // Unclaimed push body consumed bytes from the session window.
-    EXPECT_EQ(
-        SpdySession::GetDefaultInitialWindowSize(GetParam()) - kUploadDataSize,
-        session_->session_recv_window_size_);
+    EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()) -
+                  kUploadDataSize,
+              session_->session_recv_window_size_);
     EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
   }
 
@@ -1239,7 +1265,7 @@
   if (session_->flow_control_state_ ==
       SpdySession::FLOW_CONTROL_STREAM_AND_SESSION) {
     // Verify that the session window reclaimed the evicted stream body.
-    EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+    EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
               session_->session_recv_window_size_);
     EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_);
   }
@@ -1315,7 +1341,7 @@
   int seq = 0;
   std::vector<MockWrite> writes;
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
-  if (GetParam() == kProtoHTTP2) {
+  if (GetProtocol() == kProtoHTTP2) {
     writes.push_back(CreateMockWrite(*settings_ack, ++seq));
   }
 
@@ -1512,7 +1538,7 @@
   scoped_ptr<SpdyFrame> settings_frame(
       spdy_util_.ConstructSpdySettings(settings));
   std::vector<MockWrite> writes;
-  if (GetParam() == kProtoHTTP2) {
+  if (GetProtocol() == kProtoHTTP2) {
     writes.push_back(
         MockWrite(ASYNC,
                   kHttp2ConnectionHeaderPrefix,
@@ -1527,7 +1553,7 @@
                             initial_max_concurrent_streams);
   scoped_ptr<SpdyFrame> server_settings_frame(
       spdy_util_.ConstructSpdySettings(server_settings));
-  if (GetParam() <= kProtoSPDY31) {
+  if (GetProtocol() <= kProtoSPDY31) {
     writes.push_back(CreateMockWrite(*server_settings_frame));
   }
 
@@ -1632,7 +1658,7 @@
   log_.GetEntries(&entries);
   EXPECT_LT(0u, entries.size());
 
-  if (GetParam() == kProtoHTTP2) {
+  if (GetProtocol() == kProtoHTTP2) {
     int pos = ExpectLogContainsSomewhere(
         entries, 0, NetLog::TYPE_HTTP2_SESSION_GOAWAY, NetLog::PHASE_NONE);
     TestNetLogEntry entry = entries[pos];
@@ -2316,8 +2342,10 @@
   scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
   scoped_ptr<SpdyFrame> req1(
       spdy_util_.ConstructSpdyGet(nullptr, 0, false, 1, LOWEST, true));
+  spdy_util_.UpdateWithStreamDestruction(1);
   scoped_ptr<SpdyFrame> req2(
       spdy_util_.ConstructSpdyGet(nullptr, 0, false, 3, LOWEST, true));
+  spdy_util_.UpdateWithStreamDestruction(3);
   scoped_ptr<SpdyFrame> req3(
       spdy_util_.ConstructSpdyGet(nullptr, 0, false, 5, LOWEST, true));
   MockWrite writes[] = {
@@ -3019,9 +3047,9 @@
             session_->buffered_spdy_framer_->protocol_version());
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
             session_->flow_control_state());
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_send_window_size_);
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_recv_window_size_);
   EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
 }
@@ -3422,7 +3450,7 @@
   session_deps_.host_resolver->set_synchronous_mode(true);
 
   const int32 initial_window_size =
-      SpdySession::GetDefaultInitialWindowSize(GetParam());
+      SpdySession::GetDefaultInitialWindowSize(GetProtocol());
   const int32 delta_window_size = 100;
 
   MockRead reads[] = {
@@ -3489,7 +3517,7 @@
             session_->flow_control_state());
 
   const int32 initial_window_size =
-      SpdySession::GetDefaultInitialWindowSize(GetParam());
+      SpdySession::GetDefaultInitialWindowSize(GetProtocol());
   const int32 delta_window_size = 100;
 
   EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
@@ -3522,13 +3550,13 @@
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
             session_->flow_control_state());
 
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_recv_window_size_);
   EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
 
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_recv_window_size_);
   EXPECT_EQ(kUploadDataSize, session_->session_unacked_recv_window_bytes_);
 
@@ -3542,7 +3570,7 @@
 // (including optional pad length and padding) is.
 TEST_P(SpdySessionTest, SessionFlowControlPadding) {
   // Padding only exists in HTTP/2.
-  if (GetParam() < kProtoHTTP2)
+  if (GetProtocol() < kProtoHTTP2)
     return;
 
   session_deps_.host_resolver->set_synchronous_mode(true);
@@ -3563,13 +3591,13 @@
   EXPECT_EQ(SpdySession::FLOW_CONTROL_STREAM_AND_SESSION,
             session_->flow_control_state());
 
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_recv_window_size_);
   EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
 
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetParam()),
+  EXPECT_EQ(SpdySession::GetDefaultInitialWindowSize(GetProtocol()),
             session_->session_recv_window_size_);
   EXPECT_EQ(kUploadDataSize + padding_length,
             session_->session_unacked_recv_window_bytes_);
@@ -3864,7 +3892,7 @@
   EXPECT_TRUE(stream->HasUrlFromHeaders());
 
   const int32 initial_window_size =
-      SpdySession::GetDefaultInitialWindowSize(GetParam());
+      SpdySession::GetDefaultInitialWindowSize(GetProtocol());
   EXPECT_EQ(initial_window_size, session_->session_recv_window_size_);
   EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
 
@@ -3930,7 +3958,7 @@
   EXPECT_TRUE(stream->HasUrlFromHeaders());
 
   const int32 initial_window_size =
-      SpdySession::GetDefaultInitialWindowSize(GetParam());
+      SpdySession::GetDefaultInitialWindowSize(GetProtocol());
   EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
 
   // Write request.
@@ -4017,7 +4045,7 @@
   EXPECT_TRUE(stream->HasUrlFromHeaders());
 
   const int32 initial_window_size =
-      SpdySession::GetDefaultInitialWindowSize(GetParam());
+      SpdySession::GetDefaultInitialWindowSize(GetProtocol());
   EXPECT_EQ(initial_window_size, session_->session_send_window_size_);
   EXPECT_EQ(initial_window_size, session_->session_recv_window_size_);
   EXPECT_EQ(0, session_->session_unacked_recv_window_bytes_);
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index e4fd077..b1fa330 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -34,13 +34,28 @@
 
 namespace {
 
+enum TestCase {
+  // Test using the SPDY/3.1 protocol.
+  kTestCaseSPDY31,
+
+  // Test using the HTTP/2 protocol, without specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2NoPriorityDependencies,
+
+  // Test using the HTTP/2 protocol, specifying a stream
+  // dependency based on the RequestPriority.
+  kTestCaseHTTP2PriorityDependencies
+};
+
 const char kStreamUrl[] = "http://www.example.org/";
 const char kPostBody[] = "\0hello!\xff";
 const size_t kPostBodyLength = arraysize(kPostBody);
 const base::StringPiece kPostBodyStringPiece(kPostBody, kPostBodyLength);
 
+}  // namespace
+
 class SpdyStreamTest : public ::testing::Test,
-                       public ::testing::WithParamInterface<NextProto> {
+                       public ::testing::WithParamInterface<TestCase> {
  protected:
   // A function that takes a SpdyStream and the number of bytes which
   // will unstall the next frame completely.
@@ -48,9 +63,16 @@
       UnstallFunction;
 
   SpdyStreamTest()
-      : spdy_util_(GetParam()),
-        session_deps_(GetParam()),
-        offset_(0) {}
+      : spdy_util_(GetProtocol(), GetDependenciesFromPriority()),
+        session_deps_(GetProtocol()),
+        offset_(0) {
+    SpdySession::SetPriorityDependencyDefaultForTesting(
+        GetDependenciesFromPriority());
+  }
+
+  ~SpdyStreamTest() {
+    SpdySession::SetPriorityDependencyDefaultForTesting(false);
+  }
 
   base::WeakPtr<SpdySession> CreateDefaultSpdySession() {
     SpdySessionKey key(HostPortPair("www.example.org", 80),
@@ -60,6 +82,14 @@
 
   void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
 
+  NextProto GetProtocol() const {
+    return GetParam() == kTestCaseSPDY31 ? kProtoSPDY31 : kProtoHTTP2;
+  }
+
+  bool GetDependenciesFromPriority() const {
+    return GetParam() == kTestCaseHTTP2PriorityDependencies;
+  }
+
   void RunResumeAfterUnstallRequestResponseTest(
       const UnstallFunction& unstall_function);
 
@@ -108,10 +138,11 @@
   int offset_;
 };
 
-INSTANTIATE_TEST_CASE_P(NextProto,
+INSTANTIATE_TEST_CASE_P(ProtoPlusDepend,
                         SpdyStreamTest,
-                        testing::Values(kProtoSPDY31,
-                                        kProtoHTTP2));
+                        testing::Values(kTestCaseSPDY31,
+                                        kTestCaseHTTP2NoPriorityDependencies,
+                                        kTestCaseHTTP2PriorityDependencies));
 
 TEST_P(SpdyStreamTest, SendDataAfterOpen) {
   GURL url(kStreamUrl);
@@ -1127,8 +1158,6 @@
   EXPECT_EQ(ERR_CONNECTION_CLOSED, delegate.WaitForClose());
 }
 
-}  // namespace
-
 }  // namespace test
 
 }  // namespace net
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index c874e0ae..b697f22 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -736,13 +736,16 @@
   pool_->stream_max_recv_window_size_ = window;
 }
 
-SpdyTestUtil::SpdyTestUtil(NextProto protocol)
+SpdyTestUtil::SpdyTestUtil(NextProto protocol, bool dependency_priorities)
     : protocol_(protocol),
       spdy_version_(NextProtoToSpdyMajorVersion(protocol)),
-      default_url_(GURL(kDefaultURL)) {
+      default_url_(GURL(kDefaultURL)),
+      dependency_priorities_(dependency_priorities) {
   DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
 }
 
+SpdyTestUtil::~SpdyTestUtil() {}
+
 void SpdyTestUtil::AddUrlToHeaderBlock(base::StringPiece url,
                                        SpdyHeaderBlock* headers) const {
   std::string scheme, host, path;
@@ -963,11 +966,10 @@
   return CreateFramer(false)->SerializeRstStream(rst_ir);
 }
 
-SpdyFrame* SpdyTestUtil::ConstructSpdyGet(
-    const char* const url,
-    bool compressed,
-    SpdyStreamId stream_id,
-    RequestPriority request_priority) const {
+SpdyFrame* SpdyTestUtil::ConstructSpdyGet(const char* const url,
+                                          bool compressed,
+                                          SpdyStreamId stream_id,
+                                          RequestPriority request_priority) {
   scoped_ptr<SpdyHeaderBlock> block(ConstructGetHeaderBlock(url));
   return ConstructSpdySyn(
       stream_id, *block, request_priority, compressed, true);
@@ -978,7 +980,7 @@
                                           bool compressed,
                                           int stream_id,
                                           RequestPriority request_priority,
-                                          bool direct) const {
+                                          bool direct) {
   SpdyHeaderBlock block;
   MaybeAddVersionHeader(&block);
   block[GetMethodKey()] = "GET";
@@ -992,7 +994,7 @@
     int extra_header_count,
     int stream_id,
     RequestPriority priority,
-    const HostPortPair& host_port_pair) const {
+    const HostPortPair& host_port_pair) {
   SpdyHeaderBlock block;
   MaybeAddVersionHeader(&block);
   block[GetMethodKey()] = "CONNECT";
@@ -1136,7 +1138,20 @@
                                           const SpdyHeaderBlock& block,
                                           RequestPriority priority,
                                           bool compressed,
-                                          bool fin) const {
+                                          bool fin) {
+  // Get the stream id of the next highest priority request
+  // (most recent request of the same priority, or last request of
+  // an earlier priority).
+  int parent_stream_id = 0;
+  for (int q = priority; q >= IDLE; --q) {
+    if (!priority_to_stream_id_list_[q].empty()) {
+      parent_stream_id = priority_to_stream_id_list_[q].back();
+      break;
+    }
+  }
+
+  priority_to_stream_id_list_[priority].push_back(stream_id);
+
   if (protocol_ < kProtoHTTP2) {
     SpdySynStreamIR syn_stream(stream_id);
     syn_stream.set_header_block(block);
@@ -1150,6 +1165,10 @@
     headers.set_has_priority(true);
     headers.set_priority(
         ConvertRequestPriorityToSpdyPriority(priority, spdy_version()));
+    if (dependency_priorities_) {
+      headers.set_parent_stream_id(parent_stream_id);
+      headers.set_exclusive(true);
+    }
     headers.set_fin(fin);
     return CreateFramer(compressed)->SerializeFrame(headers);
   }
@@ -1274,6 +1293,20 @@
                                 frame->size(), false);
 }
 
+void SpdyTestUtil::UpdateWithStreamDestruction(int stream_id) {
+  for (auto priority_it = priority_to_stream_id_list_.begin();
+       priority_it != priority_to_stream_id_list_.end(); ++priority_it) {
+    for (auto stream_it = priority_it->second.begin();
+         stream_it != priority_it->second.end(); ++stream_it) {
+      if (*stream_it == stream_id) {
+        priority_it->second.erase(stream_it);
+        return;
+      }
+    }
+  }
+  NOTREACHED();
+}
+
 const SpdyHeaderInfo SpdyTestUtil::MakeSpdyHeader(SpdyFrameType type) {
   const SpdyHeaderInfo kHeader = {
     type,
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index a73a413..b997c6ac 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -300,7 +300,8 @@
 
 class SpdyTestUtil {
  public:
-  explicit SpdyTestUtil(NextProto protocol);
+  explicit SpdyTestUtil(NextProto protocol, bool dependency_priorities);
+  ~SpdyTestUtil();
 
   // Add the appropriate headers to put |url| into |block|.
   void AddUrlToHeaderBlock(base::StringPiece url,
@@ -415,7 +416,7 @@
   SpdyFrame* ConstructSpdyGet(const char* const url,
                               bool compressed,
                               SpdyStreamId stream_id,
-                              RequestPriority request_priority) const;
+                              RequestPriority request_priority);
 
   SpdyFrame* ConstructSpdyGetForProxy(const char* const url,
                                       bool compressed,
@@ -432,14 +433,14 @@
                               bool compressed,
                               int stream_id,
                               RequestPriority request_priority,
-                              bool direct) const;
+                              bool direct);
 
   // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request.
   SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[],
                                   int extra_header_count,
                                   int stream_id,
                                   RequestPriority priority,
-                                  const HostPortPair& host_port_pair) const;
+                                  const HostPortPair& host_port_pair);
 
   // Constructs a standard SPDY push SYN frame.
   // |extra_headers| are the extra header-value pairs, which typically
@@ -476,7 +477,7 @@
                               const SpdyHeaderBlock& headers,
                               RequestPriority priority,
                               bool compressed,
-                              bool fin) const;
+                              bool fin);
 
   // Construct a SPDY reply (HEADERS or SYN_REPLY, depending on protocol
   // version) carrying exactly the given headers, and the default priority
@@ -554,6 +555,11 @@
   SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame,
                                        int stream_id);
 
+  // Called when necessary (when it will affect stream dependency specification
+  // when setting dependencies based on priorioties) to notify the utility
+  // class of stream destruction.
+  void UpdateWithStreamDestruction(int stream_id);
+
   const SpdyHeaderInfo MakeSpdyHeader(SpdyFrameType type);
 
   // For versions below SPDY4, adds the version HTTP/1.1 header.
@@ -589,6 +595,10 @@
   const NextProto protocol_;
   const SpdyMajorVersion spdy_version_;
   GURL default_url_;
+  bool dependency_priorities_;
+
+  // Track a FIFO list of the stream_id of all created requests by priority.
+  std::map<int, std::vector<int>> priority_to_stream_id_list_;
 };
 
 }  // namespace net
diff --git a/net/tools/quic/quic_server_bin.cc b/net/tools/quic/quic_server_bin.cc
index 7678eeb..93e0fe21 100644
--- a/net/tools/quic/quic_server_bin.cc
+++ b/net/tools/quic/quic_server_bin.cc
@@ -67,6 +67,16 @@
     }
   }
 
+  if (!line->HasSwitch("certificate_file")) {
+    LOG(ERROR) << "missing --certificate_file";
+    return 1;
+  }
+
+  if (!line->HasSwitch("key_file")) {
+    LOG(ERROR) << "missing --key_file";
+    return 1;
+  }
+
   net::IPAddressNumber ip;
   CHECK(net::ParseIPLiteralToNumber("::", &ip));
 
@@ -76,14 +86,6 @@
                         line->GetSwitchValuePath("key_file")),
       config, net::QuicSupportedVersions());
   server.SetStrikeRegisterNoStartupPeriod();
-  if (!line->HasSwitch("certificate_file")) {
-    LOG(ERROR) << "missing --certificate_file";
-    return 1;
-  }
-  if (!line->HasSwitch("key_file")) {
-    LOG(ERROR) << "missing --key_file";
-    return 1;
-  }
 
   int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port));
   if (rc < 0) {
diff --git a/net/tools/quic/quic_simple_server_bin.cc b/net/tools/quic/quic_simple_server_bin.cc
index e6dc518..d6f0c640 100644
--- a/net/tools/quic/quic_simple_server_bin.cc
+++ b/net/tools/quic/quic_simple_server_bin.cc
@@ -67,6 +67,16 @@
     }
   }
 
+  if (!line->HasSwitch("certificate_file")) {
+    LOG(ERROR) << "missing --certificate_file";
+    return 1;
+  }
+
+  if (!line->HasSwitch("key_file")) {
+    LOG(ERROR) << "missing --key_file";
+    return 1;
+  }
+
   net::IPAddressNumber ip;
   CHECK(net::ParseIPLiteralToNumber("::", &ip));
 
@@ -76,14 +86,6 @@
                         line->GetSwitchValuePath("key_file")),
       config, net::QuicSupportedVersions());
   server.SetStrikeRegisterNoStartupPeriod();
-  if (!line->HasSwitch("certificate_file")) {
-    LOG(ERROR) << "missing --certificate_file";
-    return 1;
-  }
-  if (!line->HasSwitch("key_file")) {
-    LOG(ERROR) << "missing --key_file";
-    return 1;
-  }
 
   int rc = server.Listen(net::IPEndPoint(ip, FLAGS_port));
   if (rc < 0) {
diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc
index 3a276f1..9d5a6ad 100644
--- a/sandbox/linux/services/syscall_wrappers.cc
+++ b/sandbox/linux/services/syscall_wrappers.cc
@@ -33,10 +33,10 @@
 }
 
 long sys_clone(unsigned long flags,
-               decltype(nullptr) child_stack,
+               std::nullptr_t child_stack,
                pid_t* ptid,
                pid_t* ctid,
-               decltype(nullptr) tls) {
+               std::nullptr_t tls) {
   const bool clone_tls_used = flags & CLONE_SETTLS;
   const bool invalid_ctid =
       (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid;
@@ -139,7 +139,7 @@
   return syscall(__NR_unshare, flags);
 }
 
-int sys_sigprocmask(int how, const sigset_t* set, decltype(nullptr) oldset) {
+int sys_sigprocmask(int how, const sigset_t* set, std::nullptr_t oldset) {
   // In some toolchain (in particular Android and PNaCl toolchain),
   // sigset_t is 32 bits, but the Linux ABI uses more.
   LinuxSigSet linux_value;
diff --git a/sandbox/linux/services/syscall_wrappers.h b/sandbox/linux/services/syscall_wrappers.h
index 581425a..057e4c8 100644
--- a/sandbox/linux/services/syscall_wrappers.h
+++ b/sandbox/linux/services/syscall_wrappers.h
@@ -9,6 +9,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <cstddef>
+
 #include "sandbox/sandbox_export.h"
 
 struct sock_fprog;
@@ -32,10 +34,10 @@
 // nullptr, since otherwise this function cannot safely return. As a
 // consequence, this function does not support CLONE_VM.
 SANDBOX_EXPORT long sys_clone(unsigned long flags,
-                              decltype(nullptr) child_stack,
+                              std::nullptr_t child_stack,
                               pid_t* ptid,
                               pid_t* ctid,
-                              decltype(nullptr) regs);
+                              std::nullptr_t regs);
 
 SANDBOX_EXPORT void sys_exit_group(int status);
 
@@ -71,7 +73,7 @@
 // because of some ABI gap between toolchain's and Linux's.
 SANDBOX_EXPORT int sys_sigprocmask(int how,
                                    const sigset_t* set,
-                                   decltype(nullptr) oldset);
+                                   std::nullptr_t oldset);
 
 // Some libcs do not expose a sigaction().
 SANDBOX_EXPORT int sys_sigaction(int signum,
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index ce6535a..61f7c8e 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -478,11 +478,8 @@
 <td>
 <code>alignas</code> specifier,
 <code>alignof</code> operator,
-<code>std::alignment_of&lt;T&gt;</code>,
-<code>std::aligned_union&lt;Size, ...Types&gt;</code> and
-<code>std::max_align_t</code></td>
 <td>Object alignment</td>
-<td><a href="http://en.cppreference.com/w/cpp/types/alignment_of">std::alignment_of</a></td>
+<td><a href="http://en.cppreference.com/w/cpp/language/alignof">alignof</a></td>
 <td></td>
 </tr>
 
@@ -586,11 +583,15 @@
 
 <tr>
 <td>Aligned Storage</td>
-<td><code>std::aligned_storage&lt;Size, Align&gt;::type</code></td>
-<td>Declare uninitialized storage having a specified alignment.</td>
+<td><code>std::aligned_storage&lt;Size, Align&gt;::type</code>
+<code>std::alignment_of&lt;T&gt;</code>,
+<code>std::aligned_union&lt;Size, ...Types&gt;</code> and
+<code>std::max_align_t</code></td>
+<td>Declare uninitialized storage having a specified alignment, or determine alignments.</td>
 <td><a href="http://en.cppreference.com/w/cpp/types/aligned_storage">std::aligned_storage</a></td>
-<td>Note: <code>std::aligned_storage</code> is allowed, but some other C++11
-alignment features are still disallowed.</td>
+<td><code>std::aligned_storage</code> and <code>std::aligned_union</code> are
+disallowed in google3 over concerns about compatibility with internal cross-compiling
+toolchains.</td>
 </tr>
 
 <tr>
@@ -641,10 +642,11 @@
 
 <tr>
 <td>C Floating-Point Environment</td>
-<td><code>&lt;cfenv&gt;</code></td>
+<td><code>&lt;cfenv&gt;</code>, <code>&lt;fenv.h&gt;</code></td>
 <td>Provides floating point status flags and control modes for C-compatible code</td>
 <td><a href="http://en.cppreference.com/w/cpp/header/cfenv">Standard library header &lt;cfenv&gt;</a></td>
-<td>Compilers do not support use</td>
+<td>Compilers do not support use. This is banned in google style guide over
+compilers not supporting these reliably.</td>
 </tr>
 
 <tr>
@@ -832,8 +834,10 @@
 <td>Ratio Template Class</td>
 <td><code>std::ratio&lt;<i>numerator</i>, <i>denominator</i>&gt;</code></td>
 <td>Provides compile-time rational numbers</td>
-<td>TODO: documentation link</td>
-<td></td>
+<td><a href="http://en.cppreference.com/w/cpp/numeric/ratio/ratio">std::ratio
+</a></td>
+<td>Note: These are banned in the google style guide over concerns that they are
+tied to a more template-heavy interface style.</td>
 </tr>
 
 <tr>
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
index b227f22..cef541e 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerDelegate.java
@@ -18,9 +18,10 @@
  */
 public interface AccountManagerDelegate {
     /**
-     * Use the asynchronous getAccountsByType(String, Callback<Account[]>) instead.
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
-    @Deprecated
     Account[] getAccountsByType(String type);
 
     void getAccountsByType(String type, Callback<Account[]> callback);
diff --git a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
index 761447e8d..dc3cd94 100644
--- a/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
+++ b/sync/android/java/src/org/chromium/sync/signin/AccountManagerHelper.java
@@ -151,8 +151,9 @@
     }
 
     /**
-     * Use the asynchronous version below instead. See http://crbug.com/517697.
-     * @deprecated
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public List<String> getGoogleAccountNames() {
         List<String> accountNames = new ArrayList<String>();
@@ -179,8 +180,9 @@
     }
 
     /**
-     * Use the asynchronous version below instead. See http://crbug.com/517697.
-     * @deprecated
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public Account[] getGoogleAccounts() {
         return mAccountManager.getAccountsByType(GOOGLE_ACCOUNT_TYPE);
@@ -194,8 +196,9 @@
     }
 
     /**
-     * Use the asynchronous version below instead. See http://crbug.com/517697.
-     * @deprecated
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public boolean hasGoogleAccounts() {
         return getGoogleAccounts().length > 0;
@@ -227,8 +230,9 @@
     }
 
     /**
-     * Use the asynchronous version below instead. See http://crbug.com/517697.
-     * @deprecated
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public Account getAccountFromName(String accountName) {
         String canonicalName = canonicalizeName(accountName);
@@ -262,8 +266,9 @@
     }
 
     /**
-     * Use the asynchronous version below instead. See http://crbug.com/517697.
-     * @deprecated
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public boolean hasAccountForName(String accountName) {
         return getAccountFromName(accountName) != null;
@@ -282,7 +287,9 @@
     }
 
     /**
-     * @return Whether or not there is an account authenticator for Google accounts.
+     * This method is deprecated; please use the asynchronous version below instead.
+     *
+     * See http://crbug.com/517697 for details.
      */
     public boolean hasGoogleAccountAuthenticator() {
         AuthenticatorDescription[] descs = mAccountManager.getAuthenticatorTypes();
diff --git a/sync/android/javatests/src/org/chromium/sync/AndroidSyncSettingsTest.java b/sync/android/javatests/src/org/chromium/sync/AndroidSyncSettingsTest.java
index cabdced..ef26ce2 100644
--- a/sync/android/javatests/src/org/chromium/sync/AndroidSyncSettingsTest.java
+++ b/sync/android/javatests/src/org/chromium/sync/AndroidSyncSettingsTest.java
@@ -357,8 +357,10 @@
                 mSyncSettingsObserver.receivedNotification());
     }
 
-    @SmallTest
-    @Feature({"Sync"})
+    /*@SmallTest
+    @Feature({"Sync"})*/
+    // http://crbug.com/527856
+    @DisabledTest
     public void testIsSyncableOnSigninAndNotOnSignout() throws InterruptedException {
         assertTrue(mSyncContentResolverDelegate.getIsSyncable(mAccount, mAuthority) == 1);
         AndroidSyncSettings.updateAccount(mContext, null);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 8c11511..2ff3ca62 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -39,6 +39,7 @@
       "net_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "remoting_unittests",
       "sandbox_linux_unittests",
       "skia_unittests",
@@ -98,6 +99,7 @@
       "net_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "remoting_unittests",
       "sandbox_linux_unittests",
       "skia_unittests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index b5a7ade0..406bb09 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -306,13 +306,15 @@
     "additional_compile_targets": [
       "blimp",
       "components/mus/example:all",
-      "mandoline:all"
+      "mandoline:all",
+      "remoting_all"
     ]
   },
   "Linux Builder (dbg)": {
     "additional_compile_targets": [
       "blimp",
-      "mandoline:all"
+      "mandoline:all",
+      "remoting_all"
     ]
   },
   "Linux Tests": {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 7fe981c4..afc8c09 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -33,6 +33,7 @@
       "mojo_system_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "skia_unittests",
       "sql_unittests",
       "sync_unit_tests",
@@ -148,6 +149,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
@@ -437,6 +444,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
@@ -726,6 +739,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
@@ -1015,6 +1034,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
@@ -1304,6 +1329,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gn_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 6fe68af..f4e68fa4 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -757,6 +757,7 @@
       "message_center_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "sbox_integration_tests",
       "sbox_unittests",
       "sbox_validation_tests",
@@ -1543,6 +1544,7 @@
       "message_center_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "sbox_integration_tests",
       "sbox_unittests",
       "sbox_validation_tests",
@@ -1615,60 +1617,6 @@
       }
     ]
   },
-  "Win8 GN": {
-    "additional_compile_targets": [
-      "accessibility_unittests",
-      "app_list_unittests",
-      "app_shell_unittests",
-      "ash_unittests",
-      "aura_unittests",
-      "cacheinvalidation_unittests",
-      "cast_unittests",
-      "cc_unittests",
-      "chrome",
-      "chrome_elf_unittests",
-      "chromedriver_unittests",
-      "components_browsertests",
-      "components_unittests",
-      "components/mus/example:all",
-      "compositor_unittests",
-      "content_browsertests",
-      "content_unittests",
-      "courgette_unittests",
-      "crypto_unittests",
-      "device_unittests",
-      "events_unittests",
-      "extensions_browsertests",
-      "extensions_unittests",
-      "gcm_unit_tests",
-      "gfx_unittests",
-      "google_apis_unittests",
-      "gpu_unittests",
-      "interactive_ui_tests",
-      "ipc_mojo_unittests",
-      "ipc_tests",
-      "jingle_unittests",
-      "keyboard_unittests",
-      "mandoline:all",
-      "media_unittests",
-      "media_blink_unittests",
-      "message_center_unittests",
-      "ppapi_unittests",
-      "printing_unittests",
-      "sbox_integration_tests",
-      "sbox_unittests",
-      "sbox_validation_tests",
-      "skia_unittests",
-      "sql_unittests",
-      "sync_integration_tests",
-      "sync_unit_tests",
-      "ui_base_unittests",
-      "ui_touch_selection_unittests",
-      "url_unittests",
-      "views_unittests",
-      "wm_unittests"
-    ]
-  },
   "Win8 GN (dbg)": {
     "additional_compile_targets": [
       "accessibility_unittests",
@@ -1708,6 +1656,7 @@
       "message_center_unittests",
       "ppapi_unittests",
       "printing_unittests",
+      "remoting_all",
       "sbox_integration_tests",
       "sbox_unittests",
       "sbox_validation_tests",
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times-expected.txt
new file mode 100644
index 0000000..a7565e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times-expected.txt
@@ -0,0 +1,17 @@
+Tests autofocus is run every time a dialog is opened.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS document.activeElement is document.getElementById("outer-button")
+PASS document.activeElement is document.getElementById("input2")
+PASS document.activeElement is document.getElementById("input1")
+PASS document.activeElement is document.getElementById("input2")
+PASS document.activeElement is document.getElementById("input1")
+PASS document.activeElement is document.getElementById("input2")
+PASS document.activeElement is document.getElementById("input1")
+PASS 3 is 3
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html
new file mode 100644
index 0000000..fa02a005
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/dom/HTMLDialogElement/dialog-autofocus-multiple-times.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../../resources/js-test.js"></script>
+<script src="../../forms/resources/common.js"></script>
+<script>
+description('Tests autofocus is run every time a dialog is opened.');
+
+function test() {
+    shouldBe('document.activeElement', 'document.getElementById("outer-button")');
+
+    var focusCount = 0;
+    input2.onfocus = function() { focusCount += 1 };
+
+    var expectedFocusCount = 3;
+    for (i = 0; i < expectedFocusCount; i++) {
+        dlg.show();
+        shouldBe('document.activeElement', 'document.getElementById("input2")');
+        input1.focus();
+        shouldBe('document.activeElement', 'document.getElementById("input1")');
+        dlg.close();
+    }
+
+    shouldBe(focusCount.toString(), expectedFocusCount.toString());
+
+    finishJSTest();
+}
+
+jsTestIsAsync = true;
+waitUntilLoadedAndAutofocused(test);
+</script>
+</head>
+<body>
+<button id="outer-button" autofocus></button>
+<dialog id="dlg">
+    <input id="input1"></input>
+    <input id="input2" autofocus></input>
+</dialog>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
index 127e09a6..857c4a4a 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -103,7 +103,10 @@
     {
     }
 
-    void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override { }
+    void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override
+    {
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 
     const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName) override
     {
diff --git a/third_party/WebKit/Source/core/dom/StyleChangeReason.h b/third_party/WebKit/Source/core/dom/StyleChangeReason.h
index 0909210..7a31cac 100644
--- a/third_party/WebKit/Source/core/dom/StyleChangeReason.h
+++ b/third_party/WebKit/Source/core/dom/StyleChangeReason.h
@@ -6,7 +6,6 @@
 #define StyleChangeReason_h
 
 #include "core/dom/QualifiedName.h"
-#include "wtf/NullPtr.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/text/AtomicString.h"
 #include "wtf/text/WTFString.h"
diff --git a/third_party/WebKit/Source/core/fetch/CachingCorrectnessTest.cpp b/third_party/WebKit/Source/core/fetch/CachingCorrectnessTest.cpp
index 297b776..260b95f 100644
--- a/third_party/WebKit/Source/core/fetch/CachingCorrectnessTest.cpp
+++ b/third_party/WebKit/Source/core/fetch/CachingCorrectnessTest.cpp
@@ -147,7 +147,10 @@
         }
 
         // These blink::Platform methods must be overriden to make a usable object.
-        virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); }
+        virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length)
+        {
+            RELEASE_ASSERT_NOT_REACHED();
+        }
         virtual const unsigned char* getTraceCategoryEnabledFlag(const char* categoryName)
         {
             return &kAConstUnsignedCharZero;
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.h b/third_party/WebKit/Source/core/frame/LocalFrame.h
index b133866..be53fd4 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.h
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.h
@@ -235,6 +235,7 @@
     // weak callback, the set itself is not on the heap and the
     // references are bare pointers (rather than WeakMembers.)
     // See LocalFrame::clearWeakMembers().
+    GC_PLUGIN_IGNORE("553613")
     HashSet<HTMLPlugInElement*> m_pluginElements;
 #endif
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 8f76e2c..d240ffb 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -872,6 +872,7 @@
         SelectionSelectAllChildren = 1010,
         SelectionDeleteDromDocument = 1011,
         SelectionDOMString = 1012,
+        InputTypeRangeVerticalAppearance = 1013,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
index eba56ca..03fb812 100644
--- a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
@@ -41,8 +41,8 @@
 
 using namespace HTMLNames;
 
-// This function chooses the focused element when showModal() is invoked, as described in the spec for showModal().
-static void setFocusForModalDialog(HTMLDialogElement* dialog)
+// This function chooses the focused element when show() or showModal() is invoked, as described in their spec.
+static void setFocusForDialog(HTMLDialogElement* dialog)
 {
     Element* focusableDescendant = 0;
     Node* next = 0;
@@ -141,6 +141,12 @@
     if (fastHasAttribute(openAttr))
         return;
     setBooleanAttribute(openAttr, true);
+
+    // The layout must be updated here because setFocusForDialog calls
+    // Element::isFocusable, which requires an up-to-date layout.
+    document().updateLayoutIgnorePendingStylesheets();
+
+    setFocusForDialog(this);
 }
 
 void HTMLDialogElement::showModal(ExceptionState& exceptionState)
@@ -162,7 +168,7 @@
     inertSubtreesChanged(document());
 
     forceLayoutForCentering();
-    setFocusForModalDialog(this);
+    setFocusForDialog(this);
 }
 
 void HTMLDialogElement::removedFrom(ContainerNode* insertionPoint)
diff --git a/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp b/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
index 64bcdcc..19f08be 100644
--- a/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/RangeInputType.cpp
@@ -36,6 +36,7 @@
 #include "core/HTMLNames.h"
 #include "core/InputTypeNames.h"
 #include "core/dom/AXObjectCache.h"
+#include "core/dom/NodeComputedStyle.h"
 #include "core/dom/Touch.h"
 #include "core/dom/TouchList.h"
 #include "core/dom/shadow/ShadowRoot.h"
@@ -88,6 +89,10 @@
 void RangeInputType::countUsage()
 {
     countUsageIfVisible(UseCounter::InputTypeRange);
+    if (const ComputedStyle* style = element().computedStyle()) {
+        if (style->appearance() == SliderVerticalPart)
+            UseCounter::count(element().document(), UseCounter::InputTypeRangeVerticalAppearance);
+    }
 }
 
 const AtomicString& RangeInputType::formControlType() const
diff --git a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
index 8a707bccc..446a2ea9 100755
--- a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
+++ b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspector.py
@@ -1705,7 +1705,7 @@
 
         Generator.method_name_enum_list.append("        %s," % cmd_enum_name)
         Generator.method_handler_list.append("            &InspectorBackendDispatcherImpl::%s_%s," % (domain_name, json_command_name))
-        Generator.backend_method_declaration_list.append("    void %s_%s(int sessionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
+        Generator.backend_method_declaration_list.append("    void %s_%s(int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
 
         backend_agent_interface_list = [] if "redirect" in json_command else Generator.backend_agent_interface_list
 
@@ -1786,7 +1786,7 @@
 
             callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
             callback_writer.newline("public:\n")
-            callback_writer.newline("    " + callback_name + "(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl>, int sessionId, int id);\n")
+            callback_writer.newline("    " + callback_name + "(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl>, int id);\n")
             callback_writer.newline("    CORE_EXPORT void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
             error_part_writer = callback_writer.insert_writer("")
             callback_writer.newline("};\n")
@@ -1807,7 +1807,7 @@
 
             ad_hoc_type_output.append(callback_output)
 
-            method_out_code += "    RefPtrWillBeRawPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRefWillBeNoop(new " + agent_interface_name + "::" + callback_name + "(this, sessionId, callId));\n"
+            method_out_code += "    RefPtrWillBeRawPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRefWillBeNoop(new " + agent_interface_name + "::" + callback_name + "(this, callId));\n"
             agent_call_param_list.append("callback")
             normal_response_cook_text += "    if (!error.length()) \n"
             normal_response_cook_text += "        return;\n"
diff --git a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
index 03e46f91..e20c806b 100644
--- a/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
+++ b/third_party/WebKit/Source/core/inspector/CodeGeneratorInspectorStrings.py
@@ -43,19 +43,19 @@
 """)
 
 backend_method = (
-"""void InspectorBackendDispatcherImpl::${domainName}_$methodName(int sessionId, int callId, JSONObject*$requestMessageObject, JSONArray* protocolErrors)
+"""void InspectorBackendDispatcherImpl::${domainName}_$methodName(int callId, JSONObject*$requestMessageObject, JSONArray* protocolErrors)
 {
     if (!$agentField)
         protocolErrors->pushString("${domainName} handler is not available.");
 $methodCode
     if (protocolErrors->length()) {
-        reportProtocolError(sessionId, callId, InvalidParams, String::format(InvalidParamsFormatString, commandName($commandNameIndex)), protocolErrors);
+        reportProtocolError(callId, InvalidParams, String::format(InvalidParamsFormatString, commandName($commandNameIndex)), protocolErrors);
         return;
     }
 $agentCallParamsDeclaration
     $agentField->$methodName($agentCallParams);
 $responseCook
-    sendResponse(sessionId, callId, $sendResponseCallParams);
+    sendResponse(callId, $sendResponseCallParams);
 }
 """)
 
@@ -69,7 +69,7 @@
 """)
 
 callback_main_methods = (
-"""InspectorBackendDispatcher::$agentName::$callbackName::$callbackName(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id) : CallbackBase(backendImpl, sessionId, id) {}
+"""InspectorBackendDispatcher::$agentName::$callbackName::$callbackName(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id) : CallbackBase(backendImpl, id) {}
 
 void InspectorBackendDispatcher::$agentName::$callbackName::sendSuccess($parameters)
 {
@@ -150,7 +150,7 @@
 
     class CORE_EXPORT CallbackBase: public RefCountedWillBeGarbageCollectedFinalized<CallbackBase> {
     public:
-        CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id);
+        CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id);
         virtual ~CallbackBase();
         DECLARE_VIRTUAL_TRACE();
         void sendFailure(const ErrorString&);
@@ -163,7 +163,6 @@
         void disable() { m_alreadySent = true; }
 
         RefPtrWillBeMember<InspectorBackendDispatcherImpl> m_backendImpl;
-        int m_sessionId;
         int m_id;
         bool m_alreadySent;
 
@@ -185,9 +184,9 @@
         LastEntry,
     };
 
-    void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage) const;
-    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
-    virtual void dispatch(int sessionId, const String& message) = 0;
+    void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage) const;
+    virtual void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
+    virtual void dispatch(const String& message) = 0;
     static bool getCommandName(const String& message, String* result);
 
     enum MethodNames {
@@ -259,16 +258,16 @@
     }
 
     virtual void clearFrontend() { m_inspectorFrontendChannel = 0; }
-    virtual void dispatch(int sessionId, const String& message);
-    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
+    virtual void dispatch(const String& message);
+    virtual void reportProtocolError(int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
     using InspectorBackendDispatcher::reportProtocolError;
 
-    void sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
+    void sendResponse(int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
     bool isActive() { return m_inspectorFrontendChannel; }
 
 $setters
 private:
-    using CallHandler = void (InspectorBackendDispatcherImpl::*)(int sessionId, int callId, JSONObject* messageObject, JSONArray* protocolErrors);
+    using CallHandler = void (InspectorBackendDispatcherImpl::*)(int callId, JSONObject* messageObject, JSONArray* protocolErrors);
     using DispatchMap = HashMap<String, CallHandler>;
 
 $methodDeclarations
@@ -286,13 +285,13 @@
     static PassRefPtr<JSONObject> getObject(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
     static PassRefPtr<JSONArray> getArray(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
 
-    void sendResponse(int sessionId, int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
+    void sendResponse(int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
     {
-        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), result);
+        sendResponse(callId, invocationError, RefPtr<JSONValue>(), result);
     }
-    void sendResponse(int sessionId, int callId, ErrorString invocationError)
+    void sendResponse(int callId, ErrorString invocationError)
     {
-        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
+        sendResponse(callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
     }
     static const char InvalidParamsFormatString[];
 
@@ -310,7 +309,7 @@
 }
 
 
-void InspectorBackendDispatcherImpl::dispatch(int sessionId, const String& message)
+void InspectorBackendDispatcherImpl::dispatch(const String& message)
 {
     RefPtrWillBeRawPtr<InspectorBackendDispatcher> protect(this);
     int callId = 0;
@@ -330,18 +329,18 @@
 
     HashMap<String, CallHandler>::iterator it = m_dispatchMap.find(method);
     if (it == m_dispatchMap.end()) {
-        reportProtocolError(sessionId, callId, MethodNotFound, "'" + method + "' wasn't found");
+        reportProtocolError(callId, MethodNotFound, "'" + method + "' wasn't found");
         return;
     }
 
     RefPtr<JSONArray> protocolErrors = JSONArray::create();
-    ((*this).*it->value)(sessionId, callId, messageObject.get(), protocolErrors.get());
+    ((*this).*it->value)(callId, messageObject.get(), protocolErrors.get());
 }
 
-void InspectorBackendDispatcherImpl::sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
+void InspectorBackendDispatcherImpl::sendResponse(int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
 {
     if (invocationError.length()) {
-        reportProtocolError(sessionId, callId, ServerError, invocationError, errorData);
+        reportProtocolError(callId, ServerError, invocationError, errorData);
         return;
     }
 
@@ -349,15 +348,15 @@
     responseMessage->setNumber("id", callId);
     responseMessage->setObject("result", result);
     if (m_inspectorFrontendChannel)
-        m_inspectorFrontendChannel->sendProtocolResponse(sessionId, callId, responseMessage.release());
+        m_inspectorFrontendChannel->sendProtocolResponse(callId, responseMessage.release());
 }
 
-void InspectorBackendDispatcher::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage) const
+void InspectorBackendDispatcher::reportProtocolError(int callId, CommonErrorCode code, const String& errorMessage) const
 {
-    reportProtocolError(sessionId, callId, code, errorMessage, PassRefPtr<JSONValue>());
+    reportProtocolError(callId, code, errorMessage, PassRefPtr<JSONValue>());
 }
 
-void InspectorBackendDispatcherImpl::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
+void InspectorBackendDispatcherImpl::reportProtocolError(int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
 {
     ASSERT(code >=0);
     ASSERT((unsigned)code < m_commonErrors.size());
@@ -372,7 +371,7 @@
     message->setObject("error", error);
     message->setNumber("id", callId);
     if (m_inspectorFrontendChannel)
-        m_inspectorFrontendChannel->sendProtocolResponse(sessionId, callId, message.release());
+        m_inspectorFrontendChannel->sendProtocolResponse(callId, message.release());
 }
 
 template<typename R, typename V, typename V0>
@@ -465,8 +464,8 @@
     return true;
 }
 
-InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int sessionId, int id)
-    : m_backendImpl(backendImpl), m_sessionId(sessionId), m_id(id), m_alreadySent(false) {}
+InspectorBackendDispatcher::CallbackBase::CallbackBase(PassRefPtrWillBeRawPtr<InspectorBackendDispatcherImpl> backendImpl, int id)
+    : m_backendImpl(backendImpl), m_id(id), m_alreadySent(false) {}
 
 InspectorBackendDispatcher::CallbackBase::~CallbackBase() {}
 
@@ -490,7 +489,7 @@
 {
     if (m_alreadySent)
         return;
-    m_backendImpl->sendResponse(m_sessionId, m_id, invocationError, errorData, partialMessage);
+    m_backendImpl->sendResponse(m_id, invocationError, errorData, partialMessage);
     m_alreadySent = true;
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h b/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
index 580a12d3..8b687d1 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorFrontendChannel.h
@@ -34,7 +34,7 @@
 class InspectorFrontendChannel {
 public:
     virtual ~InspectorFrontendChannel() { }
-    virtual void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) = 0;
+    virtual void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) = 0;
     virtual void sendProtocolNotification(PassRefPtr<JSONObject> message) = 0;
     virtual void flush() = 0;
 };
diff --git a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
index eef8237..6e1493d9 100644
--- a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
+++ b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
@@ -65,7 +65,7 @@
     explicit PageInspectorProxy(WorkerGlobalScope* workerGlobalScope) : m_workerGlobalScope(workerGlobalScope) { }
     ~PageInspectorProxy() override { }
 private:
-    void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) override
+    void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) override
     {
         // Worker messages are wrapped, no need to handle callId.
         m_workerGlobalScope->thread()->workerReportingProxy().postMessageToPageInspector(message->toJSONString());
@@ -197,10 +197,8 @@
 void WorkerInspectorController::dispatchMessageFromFrontend(const String& message)
 {
     InspectorTaskRunner::IgnoreInterruptsScope scope(m_inspectorTaskRunner.get());
-    if (m_backendDispatcher) {
-        // sessionId will be overwritten by WebDevToolsAgent::sendProtocolNotifications call.
-        m_backendDispatcher->dispatch(0, message);
-    }
+    if (m_backendDispatcher)
+        m_backendDispatcher->dispatch(message);
 }
 
 void WorkerInspectorController::dispose()
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.h b/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.h
index c4018fa..e0d05ef 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerFilterInfo.h
@@ -48,12 +48,35 @@
 
 typedef HashMap<const PaintLayer*, PaintLayerFilterInfo*> PaintLayerFilterInfoMap;
 
+// PaintLayerFilterInfo holds the filter information for painting.
+// https://drafts.fxtf.org/filters/
+//
+// Because PaintLayer is not allocated for SVG objects, SVG filters (both
+// software and hardware-accelerated) use a different code path to paint the
+// filters (SVGFilterPainer), but both code paths use the same abstraction for
+// painting non-hardware accelerated filters (FilterEffect). Hardware
+// accelerated CSS filters use WebFilterOperations, that is backed by cc.
+//
+// PaintLayerFilterInfo is allocated when filters are present and store in an
+// internal map (s_filterMap) to save memory as 'filter' should be a rare
+// property.
 class PaintLayerFilterInfo final : public DocumentResourceClient {
     USING_FAST_MALLOC(PaintLayerFilterInfo);
     WTF_MAKE_NONCOPYABLE(PaintLayerFilterInfo);
 public:
+    // Queries the PaintLayerFilterInfo for the associated PaintLayer.
+    // The function returns nullptr if there is no associated
+    // |PaintLayerFilterInfo|.
     static PaintLayerFilterInfo* filterInfoForLayer(const PaintLayer*);
+
+    // Creates a new PaintLayerFilterInfo for the associated PaintLayer.
+    // If there is one already, it returns it instead of creating a new one.
+    //
+    // This function will never return nullptr.
     static PaintLayerFilterInfo* createFilterInfoForLayerIfNeeded(PaintLayer*);
+
+    // Remove the PaintLayerFilterInfo associated with PaintLayer.
+    // If there is none, this function  does nothing.
     static void removeFilterInfoForLayer(PaintLayer*);
 
     FilterEffectBuilder* builder() const { return m_builder.get(); }
@@ -73,7 +96,13 @@
     RefPtrWillBePersistent<FilterEffectBuilder> m_builder;
 
     static PaintLayerFilterInfoMap* s_filterMap;
+
+    // This field stores SVG reference filters (filter: url(#someElement)).
+    // It is used when SVG filters are applied to an HTML element via CSS.
     WillBePersistentHeapVector<RefPtrWillBeMember<Element>> m_internalSVGReferences;
+
+    // Same as m_internalSVGReferences, except that the reference belongs to a
+    // different document.
     Vector<ResourcePtr<DocumentResource>> m_externalSVGReferences;
 };
 
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi
index 92851c8..0ebeb00c 100644
--- a/third_party/WebKit/Source/devtools/devtools.gypi
+++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -204,6 +204,7 @@
             'front_end/emulation/devicesSettingsTab.css',
             'front_end/emulation/deviceModeToolbar.css',
             'front_end/emulation/deviceModeView.css',
+            'front_end/emulation/mediaQueryInspector.css',
             'front_end/emulation/overrides.css',
             'front_end/emulation/sensors.css',
             'front_end/emulation/responsiveDesignView.css',
diff --git a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
index 0923787..203d65bb 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/Linkifier.js
@@ -432,7 +432,7 @@
     var container = createDocumentFragment();
     var linkStringRegEx = /(?:[a-zA-Z][a-zA-Z0-9+.-]{2,}:\/\/|data:|www\.)[\w$\-_+*'=\|\/\\(){}[\]^%@&#~,:;.!?]{2,}[\w$\-_+*=\|\/\\({^%@&#~]/;
 
-    while (string) {
+    while (string && string.length < 10000) {
         var linkString = linkStringRegEx.exec(string);
         if (!linkString)
             break;
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
index e08e9cf0..c24f452 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
@@ -36,6 +36,10 @@
     this._screenOrientation = "";
     /** @type {number} */
     this._fixedFitScale = 0;
+    /** @type {string} */
+    this._warning = "";
+    /** @type {boolean} */
+    this._emulatingMobile = false;
 
     /** @type {?WebInspector.Target} */
     this._target = null;
@@ -185,13 +189,29 @@
     },
 
     /**
+     * @return {string}
+     */
+    warning: function()
+    {
+        return this._warning;
+    },
+
+    clearWarning: function()
+    {
+        this._warning = "";
+        this._updateCallback.call(this);
+    },
+
+    /**
      * @override
      * @param {!WebInspector.Target} target
      */
     targetAdded: function(target)
     {
-        if (!this._target)
+        if (!this._target) {
             this._target = target;
+            this._target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this.clearWarning, this);
+        }
     },
 
     /**
@@ -200,8 +220,10 @@
      */
     targetRemoved: function(target)
     {
-        if (this._target === target)
+        if (this._target === target) {
+            this._target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this.clearWarning, this);
             this._target = null;
+        }
     },
 
     _fitSettingChanged: function()
@@ -230,7 +252,7 @@
                     scale *= 0.8;
             }
             this._applyDeviceMetrics(new Size(screenWidth, screenHeight), this._mode.insets, scale, this._device.deviceScaleFactor, this._device.mobile(), resetScrollAndPageScale);
-            WebInspector.multitargetNetworkManager.setUserAgentOverride(this._device.userAgent);
+            this._applyUserAgent(this._device.userAgent);
             this._applyTouch(this._device.touch(), this._device.mobile());
             this._applyScreenOrientation(this._mode.orientation == WebInspector.EmulatedDevice.Horizontal ? "landscapePrimary" : "portraitPrimary");
         } else {
@@ -250,7 +272,7 @@
             }
             var screenHeight = Math.floor(this._availableSize.height / scale);
             this._applyDeviceMetrics(new Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0), scale, deviceScaleFactor, mobile, resetScrollAndPageScale);
-            WebInspector.multitargetNetworkManager.setUserAgentOverride(
+            this._applyUserAgent(
                 this._type === WebInspector.DeviceModeModel.Type.Mobile ? WebInspector.DeviceModeModel._genericMobileUserAgent :
                 (this._type === WebInspector.DeviceModeModel.Type.Tablet ? WebInspector.DeviceModeModel._genericTabletUserAgent : ""));
             this._applyTouch(this._type !== WebInspector.DeviceModeModel.Type.Desktop, mobile);
@@ -259,7 +281,21 @@
             else
                 this._applyScreenOrientation(screenHeight >= screenWidth ? "portraitPrimary" : "landscapePrimary");
         }
-        this._updateCallback();
+        this._updateCallback.call(null);
+    },
+
+    /**
+     * @param {string} userAgent
+     */
+    _applyUserAgent: function(userAgent)
+    {
+        var current = WebInspector.multitargetNetworkManager.userAgentOverride();
+        if (current !== userAgent) {
+            WebInspector.multitargetNetworkManager.setUserAgentOverride(userAgent);
+            if (!this._warning)
+                this._warning = WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering.");
+        }
+
     },
 
     /**
@@ -323,12 +359,17 @@
         function apiCallback(error)
         {
             if (error) {
-                // TODO(dgozman): warning: "Screen emulation is not available on this page."
+                this._warning = WebInspector.UIString("Screen emulation is not available on this page.");
+                this._updateCallback.call(null);
                 this._deviceMetricsOverrideAppliedForTest();
                 return;
             }
 
-            // TODO(dgozman): warning when mobile changed: "You might need to reload the page for proper user agent spoofing and viewport rendering."
+            if (mobile !== this._emulatingMobile && !this._warning) {
+                this._warning = WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering.");
+                this._updateCallback.call(null);
+            }
+            this._emulatingMobile = mobile;
             this._deviceMetricsOverrideAppliedForTest();
         }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
index 8242ccb2..d4948c9 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -13,9 +13,11 @@
     this.setMinimumSize(150, 150);
     this.element.classList.add("device-mode-view");
     this.registerRequiredCSS("emulation/deviceModeView.css");
+    WebInspector.Tooltip.addNativeOverrideContainer(this.contentElement);
 
     this._model = new WebInspector.DeviceModeModel(this._updateUI.bind(this));
-    // TODO(dgozman): media query inspector, warning, better full control, controlling mode, persist type/device, more fit options.
+    this._mediaInspector = new WebInspector.MediaQueryInspector(this._model.genericWidthSetting());
+    // TODO(dgozman): better full control, controlling mode, persist type/device, more fit options.
 
     this._inspectedPagePlaceholder = inspectedPagePlaceholder;
     this._createUI();
@@ -25,8 +27,8 @@
 WebInspector.DeviceModeView.prototype = {
     _createUI: function()
     {
-        this._createToolbar();
-
+        var toolbarContainer = this.contentElement.createChild("div", "device-mode-toolbar");
+        var mediaInspectorContainer = this.contentElement.createChild("div", "device-mode-media-container");
         this._contentArea = this.contentElement.createChild("div", "device-mode-content-area");
 
         this._screenArea = this._contentArea.createChild("div", "device-mode-screen-area");
@@ -41,11 +43,22 @@
         this._pageArea = this._screenArea.createChild("div", "device-mode-page-area");
         this._inspectedPagePlaceholder.clearMinimumSizeAndMargins();
         this._inspectedPagePlaceholder.show(this._pageArea);
+
+        this._warningInfobar = new WebInspector.Infobar(WebInspector.Infobar.Type.Warning, WebInspector.moduleSetting("disableOverridesWarning"));
+        this._warningInfobar.element.classList.add("device-mode-warning");
+        this._warningInfobar.setCloseCallback(this._model.clearWarning.bind(this._model));
+        this._contentArea.appendChild(this._warningInfobar.element);
+        this._warningMessage = this._warningInfobar.element.createChild("span");
+
+        this._createToolbar(toolbarContainer, mediaInspectorContainer);
     },
 
-    _createToolbar: function()
+    /**
+     * @param {!Element} toolbarContainer
+     * @param {!Element} mediaInspectorContainer
+     */
+    _createToolbar: function(toolbarContainer, mediaInspectorContainer)
     {
-        var toolbarContainer = this.contentElement.createChild("div", "device-mode-toolbar");
         var toolbar = new WebInspector.Toolbar(toolbarContainer);
 
         var deviceSelect = this._createDeviceSelect();
@@ -70,6 +83,10 @@
         var fitCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Fit"), this._model.fitSetting(), true, WebInspector.UIString("Zoom to fit available space"));
         var fitItem = new WebInspector.ToolbarItem(fitCheckbox);
         toolbar.appendToolbarItem(fitItem);
+        toolbar.appendSeparator();
+
+        var mediaInspectorButton = new WebInspector.DeviceModeView.MediaInspectorButton(this._mediaInspector, mediaInspectorContainer, this.onResize.bind(this));
+        toolbar.appendToolbarItem(mediaInspectorButton.button());
     },
 
     /**
@@ -242,6 +259,12 @@
             this._deviceSizeItem.setVisible(isDevice);
         }
 
+        var warning = this._model.warning();
+        if (warning !== this._cachedWarning) {
+            this._warningMessage.textContent = warning;
+            this._warningInfobar.setVisible(!!warning);
+        }
+
         if (this._model.type() === WebInspector.DeviceModeModel.Type.Device) {
             var deviceSize = this._model.appliedDeviceSize();
             this._deviceSizeInput.value = deviceSize.width + "x" + deviceSize.height;
@@ -249,10 +272,12 @@
         this._loadScreenImage(this._model.screenImage());
         if (resizePagePlaceholder)
             this._inspectedPagePlaceholder.onResize();
+        this._mediaInspector.setAxisTransform(-cssScreenRect.left, this._model.fitScale());
 
         this._cachedCssScreenRect = cssScreenRect;
         this._cachedCssVisiblePageRect = cssVisiblePageRect;
         this._cachedModelType = this._model.type();
+        this._cachedWarning = warning;
     },
 
     /**
@@ -275,6 +300,9 @@
         this._screenImage.classList.toggle("hidden", !success);
     },
 
+    /**
+     * @override
+     */
     onResize: function()
     {
         var zoomFactor = WebInspector.zoomManager.zoomFactor();
@@ -282,5 +310,92 @@
         this._model.availableSizeChanged(new Size(Math.max(rect.width * zoomFactor, 1), Math.max(rect.height * zoomFactor, 1)));
     },
 
+    /**
+     * @override
+     */
+    wasShown: function()
+    {
+        this._mediaInspector.setEnabled(true);
+    },
+
+    /**
+     * @override
+     */
+    willHide: function()
+    {
+        this._mediaInspector.setEnabled(false);
+    },
+
     __proto__: WebInspector.VBox.prototype
 }
+
+
+/**
+ * @param {!WebInspector.MediaQueryInspector} mediaInspector
+ * @param {!Element} container
+ * @param {function()} resizeCallback
+ * @constructor
+ */
+WebInspector.DeviceModeView.MediaInspectorButton = function(mediaInspector, container, resizeCallback)
+{
+    this._mediaInspector = mediaInspector;
+    this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.CountUpdated, this._updateButton, this);
+    this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.HeightUpdated, resizeCallback);
+
+    this._resizeCallback = resizeCallback;
+    this._container = container;
+
+    this._setting = WebInspector.settings.createSetting("showMediaQueryInspector", false);
+    this._setting.addChangeListener(this._settingChanged, this);
+
+    this._button = new WebInspector.ToolbarButton(WebInspector.UIString("Media queries not found"), "waterfall-toolbar-item");
+    this._button.setToggled(this._setting.get());
+    this._button.setEnabled(false);
+    this._button.addEventListener("click", this._buttonClick, this);
+
+    this._updateMediaInspector();
+}
+
+WebInspector.DeviceModeView.MediaInspectorButton.prototype = {
+    /**
+     * @return {!WebInspector.ToolbarButton}
+     */
+    button: function()
+    {
+        return this._button;
+    },
+
+    _settingChanged: function()
+    {
+        this._updateMediaInspector();
+        this._resizeCallback.call(null);
+    },
+
+    _buttonClick: function()
+    {
+        this._setting.set(!this._button.toggled());
+    },
+
+    _updateMediaInspector: function()
+    {
+        var show = this._setting.get();
+        this._button.setToggled(show);
+        if (this._mediaInspector.isShowing() && !show)
+            this._mediaInspector.detach();
+        if (!this._mediaInspector.isShowing() && show)
+            this._mediaInspector.show(this._container);
+    },
+
+    /**
+     * @param {!WebInspector.Event} event
+     */
+    _updateButton: function(event)
+    {
+        var count = /** @type {number} */ (event.data);
+        this._button.setEnabled(!!count);
+        if (!count)
+            this._button.setTitle(WebInspector.UIString("Media queries not found"));
+        else
+            this._button.setTitle(WebInspector.UIString((count === 1 ? "%d media query found" : "%d media queries found"), count));
+    }
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js
index 6624d38..afc432a 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js
@@ -6,15 +6,18 @@
  * @constructor
  * @extends {WebInspector.Widget}
  * @implements {WebInspector.TargetManager.Observer}
+ * @param {!WebInspector.Setting} widthSetting
  */
-WebInspector.MediaQueryInspector = function()
+WebInspector.MediaQueryInspector = function(widthSetting)
 {
-    WebInspector.Widget.call(this);
-    this.element.classList.add("media-inspector-view", "media-inspector-view-empty");
-    this.element.addEventListener("click", this._onMediaQueryClicked.bind(this), false);
-    this.element.addEventListener("contextmenu", this._onContextMenu.bind(this), false);
+    WebInspector.Widget.call(this, true);
+    this.registerRequiredCSS("emulation/mediaQueryInspector.css");
+    this.contentElement.classList.add("media-inspector-view", "media-inspector-view-empty");
+    this.contentElement.addEventListener("click", this._onMediaQueryClicked.bind(this), false);
+    this.contentElement.addEventListener("contextmenu", this._onContextMenu.bind(this), false);
     this._mediaThrottler = new WebInspector.Throttler(0);
 
+    this._widthSetting = widthSetting;
     this._offset = 0;
     this._scale = 1;
     this._lastReportedCount = 0;
@@ -103,29 +106,20 @@
         if (!mediaQueryMarker)
             return;
 
-        /**
-         * @param {number} width
-         */
-        function setWidth(width)
-        {
-            WebInspector.overridesSupport.settings.deviceWidth.set(width);
-            WebInspector.overridesSupport.settings.emulateResolution.set(true);
-        }
-
         var model = mediaQueryMarker._model;
         if (model.section() === WebInspector.MediaQueryInspector.Section.Max) {
-            setWidth(model.maxWidthExpression().computedLength());
+            this._widthSetting.set(model.maxWidthExpression().computedLength());
             return;
         }
         if (model.section() === WebInspector.MediaQueryInspector.Section.Min) {
-            setWidth(model.minWidthExpression().computedLength());
+            this._widthSetting.set(model.minWidthExpression().computedLength());
             return;
         }
-        var currentWidth = WebInspector.overridesSupport.settings.deviceWidth.get();
+        var currentWidth = this._widthSetting.get();
         if (currentWidth !== model.minWidthExpression().computedLength())
-            setWidth(model.minWidthExpression().computedLength());
+            this._widthSetting.set(model.minWidthExpression().computedLength());
         else
-            setWidth(model.maxWidthExpression().computedLength());
+            this._widthSetting.set(model.maxWidthExpression().computedLength());
     },
 
     /**
@@ -268,14 +262,14 @@
         if (!this.isShowing())
             return;
 
-        var oldChildrenCount = this.element.children.length;
-        var scrollTop = this.element.scrollTop;
-        this.element.removeChildren();
+        var oldChildrenCount = this.contentElement.children.length;
+        var scrollTop = this.contentElement.scrollTop;
+        this.contentElement.removeChildren();
 
         var container = null;
         for (var i = 0; i < markers.length; ++i) {
             if (!i || markers[i].model.section() !== markers[i - 1].model.section())
-                container = this.element.createChild("div", "media-inspector-marker-container");
+                container = this.contentElement.createChild("div", "media-inspector-marker-container");
             var marker = markers[i];
             var bar = this._createElementFromMediaQueryModel(marker.model);
             bar._model = marker.model;
@@ -283,9 +277,9 @@
             bar.classList.toggle("media-inspector-marker-inactive", !marker.active);
             container.appendChild(bar);
         }
-        this.element.scrollTop = scrollTop;
-        this.element.classList.toggle("media-inspector-view-empty", !this.element.children.length);
-        if (this.element.children.length !== oldChildrenCount)
+        this.contentElement.scrollTop = scrollTop;
+        this.contentElement.classList.toggle("media-inspector-view-empty", !this.contentElement.children.length);
+        if (this.contentElement.children.length !== oldChildrenCount)
             this.dispatchEventToListeners(WebInspector.MediaQueryInspector.Events.HeightUpdated);
     },
 
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/ResponsiveDesignView.js b/third_party/WebKit/Source/devtools/front_end/emulation/ResponsiveDesignView.js
index 9768135..750fcdf 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/ResponsiveDesignView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/ResponsiveDesignView.js
@@ -62,7 +62,7 @@
 
         this._mediaInspectorContainer = this._canvasContainer.element.createChild("div", "responsive-design-media-container");
         WebInspector.Tooltip.addNativeOverrideContainer(this._mediaInspectorContainer);
-        this._mediaInspector = new WebInspector.MediaQueryInspector();
+        this._mediaInspector = new WebInspector.MediaQueryInspector(WebInspector.overridesSupport.settings.deviceWidth);
         this._updateMediaQueryInspector();
 
         this._warningInfobar = new WebInspector.Infobar(WebInspector.Infobar.Type.Warning, WebInspector.moduleSetting("disableOverridesWarning"));
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
index dfb8491c6a..0839b77 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
@@ -8,6 +8,7 @@
     overflow: hidden;
     align-items: stretch;
     flex: auto;
+    background-color: #fcfcfc;
 }
 
 .device-mode-toolbar {
@@ -20,10 +21,23 @@
     justify-content: center;
 }
 
+.device-mode-media-container {
+    flex: none;
+    overflow: hidden;
+}
+
 .device-mode-content-area {
     flex: auto;
     position: relative;
-    overflow: hidden;
+    margin: 25px 0 23px 0;
+}
+
+.device-mode-warning {
+    position: absolute;
+    bottom: -24px;
+    left: 0;
+    right: 0;
+    border-top: 1px solid #ccc;
 }
 
 .device-mode-screen-area {
@@ -32,8 +46,8 @@
     right: 0;
     width: 0;
     height: 0;
-    outline: 1px solid hsl(0, 0%, 95%);
     background-color: #171717;
+    box-shadow: hsl(0, 0%, 88%) 0 0 0 1px, hsla(0, 0%, 80%, 0.6) 0 0 16px;
 }
 
 .device-mode-screen-image {
@@ -73,5 +87,5 @@
     width: 0;
     height: 0;
     display: flex;
-    background-color: rgb(255, 255, 255);
+    background-color: #fcfcfc;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/mediaQueryInspector.css b/third_party/WebKit/Source/devtools/front_end/emulation/mediaQueryInspector.css
new file mode 100644
index 0000000..a8d2f79
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/mediaQueryInspector.css
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Media query bars */
+
+.media-inspector-marker-container {
+    position: relative;
+    height: 14px;
+    margin: 2px 0;
+}
+
+.media-inspector-marker {
+    position: absolute;
+    top: 1px;
+    bottom: 1px;
+    white-space: nowrap;
+    border-radius: 2px;
+}
+
+.media-inspector-marker-inactive {
+    -webkit-filter: brightness(80%);
+}
+
+.media-inspector-marker:hover {
+    top: -1px;
+    bottom: -1px;
+    -webkit-filter: brightness(115%) !important;
+}
+
+.media-inspector-marker-max-width {
+    background: linear-gradient(to left, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(72, 139, 249), rgb(26, 113, 233));
+    border-radius: 0 2px 2px 0;
+    border-right: 2px solid rgb(171, 207, 255);
+}
+
+.media-inspector-marker-min-max-width {
+    background: linear-gradient(to right, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to left, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(112, 174, 7), rgb(3, 131, 0));
+    border-radius: 2px;
+    border-left: 2px solid rgb(80, 226, 40);
+    border-right: 2px solid rgb(80, 226, 40);
+}
+
+.media-inspector-marker-min-max-width:hover {
+    z-index: 1;
+}
+
+.media-inspector-marker-min-width {
+    background: linear-gradient(to right, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(222, 129, 30), rgb(204, 104, 31));
+    border-radius: 2px 0 0 2px;
+    border-left: 2px solid rgb(255, 181, 142);
+}
+
+/* Media query labels */
+
+.media-inspector-marker:not(:hover) .media-inspector-marker-label-container {
+    display: none;
+}
+
+.media-inspector-marker-label-container {
+    position: absolute;
+}
+
+.media-inspector-marker-label-container-left {
+    left: -2px;
+}
+
+.media-inspector-marker-label-container-right {
+    right: -2px;
+}
+
+.media-inspector-marker-label {
+    color: #eee;
+    position: absolute;
+    top: 1px;
+    bottom: 0;
+    font-size: 10px;
+    text-shadow: rgba(0, 0, 0, 0.6) 1px 1px;
+    pointer-events: none;
+}
+
+.media-inspector-label-right {
+    right: 4px;
+}
+
+.media-inspector-label-left {
+    left: 4px;
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/module.json b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
index 4e08aa30..11530de6 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/module.json
@@ -96,6 +96,7 @@
         "devicesSettingsTab.css",
         "deviceModeToolbar.css",
         "deviceModeView.css",
+        "mediaQueryInspector.css",
         "responsiveDesignView.css",
         "overrides.css",
         "sensors.css"
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/responsiveDesignView.css b/third_party/WebKit/Source/devtools/front_end/emulation/responsiveDesignView.css
index 2ee452b..1295c69 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/responsiveDesignView.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/responsiveDesignView.css
@@ -434,88 +434,3 @@
     padding-bottom: 5px;
     overflow: hidden;
 }
-
-/* Media query bars */
-
-.media-inspector-marker-container {
-    position: relative;
-    height: 14px;
-    margin: 2px 0;
-}
-
-.media-inspector-marker {
-    position: absolute;
-    top: 1px;
-    bottom: 1px;
-    white-space: nowrap;
-    border-radius: 2px;
-}
-
-.media-inspector-marker-inactive {
-    -webkit-filter: brightness(80%);
-}
-
-.media-inspector-marker:hover {
-    top: -1px;
-    bottom: -1px;
-    -webkit-filter: brightness(115%) !important;
-}
-
-.media-inspector-marker-max-width {
-    background: linear-gradient(to left, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(72, 139, 249), rgb(26, 113, 233));
-    border-radius: 0 2px 2px 0;
-    border-right: 2px solid rgb(171, 207, 255);
-}
-
-.media-inspector-marker-min-max-width {
-    background: linear-gradient(to right, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to left, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(112, 174, 7), rgb(3, 131, 0));
-    border-radius: 2px;
-    border-left: 2px solid rgb(80, 226, 40);
-    border-right: 2px solid rgb(80, 226, 40);
-}
-
-.media-inspector-marker-min-max-width:hover {
-    z-index: 1;
-}
-
-.media-inspector-marker-min-width {
-    background: linear-gradient(to right, rgba(255, 255, 255, 0.27), rgba(0,0,0,0) 30px), linear-gradient(to bottom, rgb(222, 129, 30), rgb(204, 104, 31));
-    border-radius: 2px 0 0 2px;
-    border-left: 2px solid rgb(255, 181, 142);
-}
-
-/* Media query labels */
-
-.media-inspector-marker:not(:hover) .media-inspector-marker-label-container {
-    display: none;
-}
-
-.media-inspector-marker-label-container {
-    position: absolute;
-}
-
-.media-inspector-marker-label-container-left {
-    left: -2px;
-}
-
-.media-inspector-marker-label-container-right {
-    right: -2px;
-}
-
-.media-inspector-marker-label {
-    color: #eee;
-    position: absolute;
-    top: 1px;
-    bottom: 0;
-    font-size: 10px;
-    text-shadow: rgba(0, 0, 0, 0.6) 1px 1px;
-    pointer-events: none;
-}
-
-.media-inspector-label-right {
-    right: 4px;
-}
-
-.media-inspector-label-left {
-    left: 4px;
-}
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
index 247f2ea..96575cd0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesView.js
@@ -291,8 +291,6 @@
         var project = event.data;
         var uiSourceCodes = project.uiSourceCodes();
         this._removeUISourceCodes(uiSourceCodes);
-        if (project.type() === WebInspector.projectTypes.Network)
-            this._editorContainer.reset();
     },
 
     _updateScriptViewToolbarItems: function()
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js
index 116a79c..55efff58 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js
@@ -288,9 +288,6 @@
     addUISourceCode: function(uiSourceCode)
     {
         var uri = uiSourceCode.uri();
-        if (this._userSelectedFiles)
-            return;
-
         var index = this._history.index(uri);
         if (index === -1)
             return;
@@ -341,14 +338,12 @@
      */
     _editorClosedByUserAction: function(uiSourceCode)
     {
-        this._userSelectedFiles = true;
         this._history.remove(uiSourceCode.uri());
         this._updateHistory();
     },
 
     _editorSelectedByUserAction: function()
     {
-        this._userSelectedFiles = true;
         this._updateHistory();
     },
 
@@ -499,11 +494,6 @@
         this._updateFileTitle(uiSourceCode);
     },
 
-    reset: function()
-    {
-        delete this._userSelectedFiles;
-    },
-
     /**
      * @return {string}
      */
diff --git a/third_party/WebKit/Source/platform/TestingPlatformSupport.cpp b/third_party/WebKit/Source/platform/TestingPlatformSupport.cpp
index 7733af6..96fed1a 100644
--- a/third_party/WebKit/Source/platform/TestingPlatformSupport.cpp
+++ b/third_party/WebKit/Source/platform/TestingPlatformSupport.cpp
@@ -88,6 +88,7 @@
 
 void TestingPlatformSupport::cryptographicallyRandomValues(unsigned char* buffer, size_t length)
 {
+    RELEASE_ASSERT_NOT_REACHED();
 }
 
 const unsigned char* TestingPlatformSupport::getTraceCategoryEnabledFlag(const char* categoryName)
diff --git a/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp b/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp
index e29ecb6a..cafdcae1 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCacheTest.cpp
@@ -16,7 +16,10 @@
 public:
     EmptyPlatform() {}
     ~EmptyPlatform() override {}
-    void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override { }
+    void cryptographicallyRandomValues(unsigned char* buffer, size_t length) override
+    {
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 };
 
 TEST(FontCache, getLastResortFallbackFont)
diff --git a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
index a128a26..a6fd744 100644
--- a/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/RecordingImageBufferSurfaceTest.cpp
@@ -338,7 +338,10 @@
     class CurrentThreadPlatformMock : public Platform {
     public:
         CurrentThreadPlatformMock() { }
-        virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length) { ASSERT_NOT_REACHED(); }
+        virtual void cryptographicallyRandomValues(unsigned char* buffer, size_t length)
+        {
+            RELEASE_ASSERT_NOT_REACHED();
+        }
         WebThread* currentThread() override { return &m_currentThread; }
 
         void enterRunLoop() { m_currentThread.enterRunLoop(); }
diff --git a/third_party/WebKit/Source/platform/heap/RunAllTests.cpp b/third_party/WebKit/Source/platform/heap/RunAllTests.cpp
index 8ce81dd..3a74f389 100644
--- a/third_party/WebKit/Source/platform/heap/RunAllTests.cpp
+++ b/third_party/WebKit/Source/platform/heap/RunAllTests.cpp
@@ -32,7 +32,6 @@
 
 #include "platform/EventTracer.h"
 #include "platform/heap/Heap.h"
-#include "wtf/CryptographicallyRandomNumber.h"
 #include "wtf/MainThread.h"
 #include <base/bind.h>
 #include <base/test/launcher/unit_test_launcher.h>
diff --git a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp
index 8a3562c..e500aa4 100644
--- a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp
+++ b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp
@@ -63,7 +63,10 @@
     }
 
     // Stub for pure virtual method.
-    void cryptographicallyRandomValues(unsigned char*, size_t) override { ASSERT_NOT_REACHED(); }
+    void cryptographicallyRandomValues(unsigned char*, size_t) override
+    {
+        RELEASE_ASSERT_NOT_REACHED();
+    }
 
     void setPublicSuffix(const blink::WebString& suffix)
     {
diff --git a/third_party/WebKit/Source/web/ImageDecodeBench.cpp b/third_party/WebKit/Source/web/ImageDecodeBench.cpp
index 98f7fa1..988f2e8f 100644
--- a/third_party/WebKit/Source/web/ImageDecodeBench.cpp
+++ b/third_party/WebKit/Source/web/ImageDecodeBench.cpp
@@ -369,7 +369,7 @@
 
         void cryptographicallyRandomValues(unsigned char*, size_t) override
         {
-            // Do nothing: make blink::Platform use the default crypto-randoms.
+            RELEASE_ASSERT_NOT_REACHED();
         }
 
         void screenColorProfile(WebVector<char>* profile) override
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
index 5565ad0..62258a2b 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -254,9 +254,8 @@
 
 class DebuggerTask : public InspectorTaskRunner::Task {
 public:
-    DebuggerTask(int sessionId, PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor)
-        : m_sessionId(sessionId)
-        , m_descriptor(descriptor)
+    DebuggerTask(PassOwnPtr<WebDevToolsAgent::MessageDescriptor> descriptor)
+        : m_descriptor(descriptor)
     {
     }
 
@@ -269,11 +268,10 @@
 
         WebDevToolsAgentImpl* agentImpl = static_cast<WebDevToolsAgentImpl*>(webagent);
         if (agentImpl->m_attached)
-            agentImpl->dispatchMessageFromFrontend(m_sessionId, m_descriptor->message());
+            agentImpl->dispatchMessageFromFrontend(m_descriptor->message());
     }
 
 private:
-    int m_sessionId;
     OwnPtr<WebDevToolsAgent::MessageDescriptor> m_descriptor;
 };
 
@@ -333,7 +331,6 @@
     , m_pageConsoleAgent(nullptr)
     , m_agents(m_instrumentingAgents.get(), m_state.get())
     , m_deferredAgentsInitialized(false)
-    , m_sessionId(0)
 {
     ASSERT(isMainThread());
     ASSERT(m_webLocalFrameImpl->frame());
@@ -500,14 +497,13 @@
     m_agents.append(agent);
 }
 
-void WebDevToolsAgentImpl::attach(const WebString& hostId, int sessionId)
+void WebDevToolsAgentImpl::attach(const WebString& hostId)
 {
     if (m_attached)
         return;
 
     // Set the attached bit first so that sync notifications were delivered.
     m_attached = true;
-    m_sessionId = sessionId;
 
     initializeDeferredAgents();
     m_resourceAgent->setHostId(hostId);
@@ -526,12 +522,12 @@
     Platform::current()->currentThread()->addTaskObserver(this);
 }
 
-void WebDevToolsAgentImpl::reattach(const WebString& hostId, int sessionId, const WebString& savedState)
+void WebDevToolsAgentImpl::reattach(const WebString& hostId, const WebString& savedState)
 {
     if (m_attached)
         return;
 
-    attach(hostId, sessionId);
+    attach(hostId);
     m_state->loadFromCookie(savedState);
     m_agents.restore();
 }
@@ -558,7 +554,6 @@
     InspectorInstrumentation::frontendDeleted();
     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
 
-    m_sessionId = 0;
     m_attached = false;
 }
 
@@ -603,21 +598,21 @@
     m_client->disableTracing();
 }
 
-void WebDevToolsAgentImpl::dispatchOnInspectorBackend(int sessionId, const WebString& message)
+void WebDevToolsAgentImpl::dispatchOnInspectorBackend(const WebString& message)
 {
     if (!m_attached)
         return;
     if (WebDevToolsAgent::shouldInterruptForMessage(message))
         MainThreadDebugger::instance()->taskRunner()->runPendingTasks();
     else
-        dispatchMessageFromFrontend(sessionId, message);
+        dispatchMessageFromFrontend(message);
 }
 
-void WebDevToolsAgentImpl::dispatchMessageFromFrontend(int sessionId, const String& message)
+void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const String& message)
 {
     InspectorTaskRunner::IgnoreInterruptsScope scope(MainThreadDebugger::instance()->taskRunner());
     if (m_inspectorBackendDispatcher)
-        m_inspectorBackendDispatcher->dispatch(sessionId, message);
+        m_inspectorBackendDispatcher->dispatch(message);
 }
 
 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& pointInRootFrame)
@@ -637,12 +632,12 @@
     m_domAgent->inspect(node);
 }
 
-void WebDevToolsAgentImpl::sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message)
+void WebDevToolsAgentImpl::sendProtocolResponse(int callId, PassRefPtr<JSONObject> message)
 {
     if (!m_attached)
         return;
     flushPendingProtocolNotifications();
-    m_client->sendProtocolMessage(sessionId, callId, message->toJSONString(), m_stateCookie);
+    m_client->sendProtocolMessage(callId, message->toJSONString(), m_stateCookie);
     m_stateCookie = String();
 }
 
@@ -650,7 +645,7 @@
 {
     if (!m_attached)
         return;
-    m_notificationQueue.append(std::make_pair(m_sessionId, message));
+    m_notificationQueue.append(message);
 }
 
 void WebDevToolsAgentImpl::flush()
@@ -683,11 +678,12 @@
 
 void WebDevToolsAgentImpl::flushPendingProtocolNotifications()
 {
-    if (m_attached) {
-        m_agents.flushPendingProtocolNotifications();
-        for (size_t i = 0; i < m_notificationQueue.size(); ++i)
-            m_client->sendProtocolMessage(m_notificationQueue[i].first, 0, m_notificationQueue[i].second->toJSONString(), WebString());
-    }
+    if (!m_attached)
+        return;
+
+    m_agents.flushPendingProtocolNotifications();
+    for (size_t i = 0; i < m_notificationQueue.size(); ++i)
+        m_client->sendProtocolMessage(0, m_notificationQueue[i]->toJSONString(), WebString());
     m_notificationQueue.clear();
 }
 
@@ -708,11 +704,11 @@
     flushPendingProtocolNotifications();
 }
 
-void WebDevToolsAgent::interruptAndDispatch(int sessionId, MessageDescriptor* rawDescriptor)
+void WebDevToolsAgent::interruptAndDispatch(MessageDescriptor* rawDescriptor)
 {
     // rawDescriptor can't be a PassOwnPtr because interruptAndDispatch is a WebKit API function.
     OwnPtr<MessageDescriptor> descriptor = adoptPtr(rawDescriptor);
-    OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(sessionId, descriptor.release()));
+    OwnPtr<DebuggerTask> task = adoptPtr(new DebuggerTask(descriptor.release()));
     MainThreadDebugger::interruptMainThreadAndRun(task.release());
 }
 
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
index e1980180..9ce980bb 100644
--- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
+++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.h
@@ -85,7 +85,7 @@
     WebDevToolsAgentClient* client() { return m_client; }
     InspectorOverlay* overlay() const { return m_overlay.get(); }
     void flushPendingProtocolNotifications();
-    void dispatchMessageFromFrontend(int sessionId, const String& message);
+    void dispatchMessageFromFrontend(const String& message);
     void registerAgent(PassOwnPtrWillBeRawPtr<InspectorAgent>);
     static void webViewImplClosed(WebViewImpl*);
     static void webFrameWidgetImplClosed(WebFrameWidgetImpl*);
@@ -98,11 +98,11 @@
     void layerTreeViewChanged(WebLayerTreeView*);
 
     // WebDevToolsAgent implementation.
-    void attach(const WebString& hostId, int sessionId) override;
-    void reattach(const WebString& hostId, int sessionId, const WebString& savedState) override;
+    void attach(const WebString& hostId) override;
+    void reattach(const WebString& hostId, const WebString& savedState) override;
     void detach() override;
     void continueProgram() override;
-    void dispatchOnInspectorBackend(int sessionId, const WebString& message) override;
+    void dispatchOnInspectorBackend(const WebString& message) override;
     void inspectElementAt(const WebPoint&) override;
     void evaluateInWebInspector(long callId, const WebString& script) override;
     WebString evaluateInWebInspectorOverlay(const WebString& script) override;
@@ -121,7 +121,7 @@
     void resumeStartup() override;
 
     // InspectorFrontendChannel implementation.
-    void sendProtocolResponse(int sessionId, int callId, PassRefPtr<JSONObject> message) override;
+    void sendProtocolResponse(int callId, PassRefPtr<JSONObject> message) override;
     void sendProtocolNotification(PassRefPtr<JSONObject> message) override;
     void flush() override;
 
@@ -159,9 +159,8 @@
     InspectorAgentRegistry m_agents;
     bool m_deferredAgentsInitialized;
 
-    typedef Vector<std::pair<int, RefPtr<JSONObject>>> NotificationQueue;
+    typedef Vector<RefPtr<JSONObject>> NotificationQueue;
     NotificationQueue m_notificationQueue;
-    int m_sessionId;
     String m_stateCookie;
 
     friend class DebuggerTask;
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
index 747ea14..7873baa8 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.cpp
@@ -152,18 +152,18 @@
     m_workerInspectorProxy->workerThreadTerminated();
 }
 
-void WebEmbeddedWorkerImpl::attachDevTools(const WebString& hostId, int sessionId)
+void WebEmbeddedWorkerImpl::attachDevTools(const WebString& hostId)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->attach(hostId, sessionId);
+        devtoolsAgent->attach(hostId);
 }
 
-void WebEmbeddedWorkerImpl::reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState)
+void WebEmbeddedWorkerImpl::reattachDevTools(const WebString& hostId, const WebString& savedState)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->reattach(hostId, sessionId, savedState);
+        devtoolsAgent->reattach(hostId, savedState);
     resumeStartup();
 }
 
@@ -174,13 +174,13 @@
         devtoolsAgent->detach();
 }
 
-void WebEmbeddedWorkerImpl::dispatchDevToolsMessage(int sessionId, const WebString& message)
+void WebEmbeddedWorkerImpl::dispatchDevToolsMessage(const WebString& message)
 {
     if (m_askedToTerminate)
         return;
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->dispatchOnInspectorBackend(sessionId, message);
+        devtoolsAgent->dispatchOnInspectorBackend(message);
 }
 
 void WebEmbeddedWorkerImpl::postMessageToPageInspector(const String& message)
@@ -280,9 +280,9 @@
     // invoked and |this| might have been deleted at this point.
 }
 
-void WebEmbeddedWorkerImpl::sendProtocolMessage(int sessionId, int callId, const WebString& message, const WebString& state)
+void WebEmbeddedWorkerImpl::sendProtocolMessage(int callId, const WebString& message, const WebString& state)
 {
-    m_workerContextClient->sendDevToolsMessage(sessionId, callId, message, state);
+    m_workerContextClient->sendDevToolsMessage(callId, message, state);
 }
 
 void WebEmbeddedWorkerImpl::resumeStartup()
diff --git a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
index 18c70b44d..8c4d9d9 100644
--- a/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebEmbeddedWorkerImpl.h
@@ -62,10 +62,10 @@
     // WebEmbeddedWorker overrides.
     void startWorkerContext(const WebEmbeddedWorkerStartData&) override;
     void terminateWorkerContext() override;
-    void attachDevTools(const WebString& hostId, int sessionId) override;
-    void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) override;
+    void attachDevTools(const WebString& hostId) override;
+    void reattachDevTools(const WebString& hostId, const WebString& savedState) override;
     void detachDevTools() override;
-    void dispatchDevToolsMessage(int sessionId, const WebString&) override;
+    void dispatchDevToolsMessage(const WebString&) override;
 
     void postMessageToPageInspector(const WTF::String&);
 
@@ -80,7 +80,7 @@
     void didFinishDocumentLoad(WebLocalFrame*, bool documentIsEmpty) override;
 
     // WebDevToolsAgentClient overrides.
-    void sendProtocolMessage(int sessionId, int callId, const WebString&, const WebString&) override;
+    void sendProtocolMessage(int callId, const WebString&, const WebString&) override;
     void resumeStartup() override;
 
     void onScriptLoaderFinished();
diff --git a/third_party/WebKit/Source/web/WebPageSerializer.cpp b/third_party/WebKit/Source/web/WebPageSerializer.cpp
index f9ce7fe..193da0a 100644
--- a/third_party/WebKit/Source/web/WebPageSerializer.cpp
+++ b/third_party/WebKit/Source/web/WebPageSerializer.cpp
@@ -63,92 +63,6 @@
 
 namespace {
 
-KURL getSubResourceURLFromElement(Element* element)
-{
-    ASSERT(element);
-    const QualifiedName& attributeName = element->subResourceAttributeName();
-    if (attributeName == QualifiedName::null())
-        return KURL();
-
-    String value = element->getAttribute(attributeName);
-    // Ignore javascript content.
-    if (value.isEmpty() || value.stripWhiteSpace().startsWith("javascript:", TextCaseInsensitive))
-        return KURL();
-
-    return element->document().completeURL(value);
-}
-
-void retrieveResourcesForElement(Element* element,
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>>* visitedFrames,
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>>* framesToVisit,
-    Vector<KURL>* frameURLs,
-    Vector<KURL>* resourceURLs)
-{
-    ASSERT(element);
-    // If the node is a frame, we'll process it later in retrieveResourcesForFrame.
-    if (isHTMLFrameElementBase(*element) || isHTMLObjectElement(*element) || isHTMLEmbedElement(*element)) {
-        Frame* frame = toHTMLFrameOwnerElement(element)->contentFrame();
-        if (frame && frame->isLocalFrame()) {
-            if (!visitedFrames->contains(toLocalFrame(frame)))
-                framesToVisit->append(toLocalFrame(frame));
-            return;
-        }
-    }
-
-    KURL url = getSubResourceURLFromElement(element);
-    if (url.isEmpty() || !url.isValid())
-        return; // No subresource for this node.
-
-    // Ignore URLs that have a non-standard protocols. Since the FTP protocol
-    // does no have a cache mechanism, we skip it as well.
-    if (!url.protocolIsInHTTPFamily() && !url.isLocalFile())
-        return;
-
-    if (!resourceURLs->contains(url))
-        resourceURLs->append(url);
-}
-
-void retrieveResourcesForFrame(LocalFrame* frame,
-    const WebVector<WebCString>& supportedSchemes,
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>>* visitedFrames,
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>>* framesToVisit,
-    Vector<KURL>* frameURLs,
-    Vector<KURL>* resourceURLs)
-{
-    KURL frameURL = frame->loader().documentLoader()->request().url();
-
-    // If the frame's URL is invalid, ignore it, it is not retrievable.
-    if (!frameURL.isValid())
-        return;
-
-    // Ignore frames from unsupported schemes.
-    bool isValidScheme = false;
-    for (size_t i = 0; i < supportedSchemes.size(); ++i) {
-        if (frameURL.protocolIs(static_cast<CString>(supportedSchemes[i]).data())) {
-            isValidScheme = true;
-            break;
-        }
-    }
-    if (!isValidScheme)
-        return;
-
-    // If we have already seen that frame, ignore it.
-    if (visitedFrames->contains(frame))
-        return;
-    visitedFrames->append(frame);
-    if (!frameURLs->contains(frameURL))
-        frameURLs->append(frameURL);
-
-    // Now get the resources associated with each node of the document.
-    RefPtrWillBeRawPtr<HTMLAllCollection> allElements = frame->document()->all();
-    for (unsigned i = 0; i < allElements->length(); ++i) {
-        Element* element = allElements->item(i);
-        retrieveResourcesForElement(element,
-                                    visitedFrames, framesToVisit,
-                                    frameURLs, resourceURLs);
-    }
-}
-
 class MHTMLPageSerializerDelegate final : public PageSerializer::Delegate {
 public:
     ~MHTMLPageSerializerDelegate() override;
@@ -170,25 +84,6 @@
 
 } // namespace
 
-void WebPageSerializer::serialize(WebView* view, WebVector<WebPageSerializer::Resource>* resourcesParam)
-{
-    Vector<SerializedResource> resources;
-    PageSerializer serializer(&resources, PassOwnPtr<PageSerializer::Delegate>(nullptr));
-    serializer.serialize(toWebViewImpl(view)->page());
-
-    Vector<Resource> result;
-    for (Vector<SerializedResource>::const_iterator iter = resources.begin(); iter != resources.end(); ++iter) {
-        Resource resource;
-        resource.url = iter->url;
-        resource.mimeType = iter->mimeType.ascii();
-        // FIXME: we are copying all the resource data here. Idealy we would have a WebSharedData().
-        resource.data = WebCString(iter->data->data(), iter->data->size());
-        result.append(resource);
-    }
-
-    *resourcesParam = result;
-}
-
 static PassRefPtr<SharedBuffer> serializePageToMHTML(Page* page, MHTMLArchive::EncodingPolicy encodingPolicy)
 {
     Vector<SerializedResource> resources;
@@ -223,48 +118,6 @@
     return serializerImpl.serialize();
 }
 
-bool WebPageSerializer::retrieveAllResources(WebView* view,
-                                             const WebVector<WebCString>& supportedSchemes,
-                                             WebVector<WebURL>* resourceURLs,
-                                             WebVector<WebURL>* frameURLs) {
-    WebLocalFrameImpl* mainFrame = toWebLocalFrameImpl(view->mainFrame());
-    if (!mainFrame)
-        return false;
-
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>> framesToVisit;
-    WillBeHeapVector<RawPtrWillBeMember<LocalFrame>> visitedFrames;
-    Vector<KURL> frameKURLs;
-    Vector<KURL> resourceKURLs;
-
-    // Let's retrieve the resources from every frame in this page.
-    framesToVisit.append(mainFrame->frame());
-    while (!framesToVisit.isEmpty()) {
-        LocalFrame* frame = framesToVisit[0];
-        framesToVisit.remove(0);
-        retrieveResourcesForFrame(frame, supportedSchemes,
-                                  &visitedFrames, &framesToVisit,
-                                  &frameKURLs, &resourceKURLs);
-    }
-
-    // Converts the results to WebURLs.
-    WebVector<WebURL> resultResourceURLs(resourceKURLs.size());
-    for (size_t i = 0; i < resourceKURLs.size(); ++i) {
-        resultResourceURLs[i] = resourceKURLs[i];
-        // A frame's src can point to the same URL as another resource, keep the
-        // resource URL only in such cases.
-        size_t index = frameKURLs.find(resourceKURLs[i]);
-        if (index != kNotFound)
-            frameKURLs.remove(index);
-    }
-    *resourceURLs = resultResourceURLs;
-    WebVector<WebURL> resultFrameURLs(frameKURLs.size());
-    for (size_t i = 0; i < frameKURLs.size(); ++i)
-        resultFrameURLs[i] = frameKURLs[i];
-    *frameURLs = resultFrameURLs;
-
-    return true;
-}
-
 WebString WebPageSerializer::generateMetaCharsetDeclaration(const WebString& charset)
 {
     // TODO(yosin) We should call |PageSerializer::metaCharsetDeclarationOf()|.
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
index 9839da9..e2df066 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.cpp
@@ -197,9 +197,9 @@
     return m_networkProvider->serviceWorkerID(dataSource);
 }
 
-void WebSharedWorkerImpl::sendProtocolMessage(int sessionId, int callId, const WebString& message, const WebString& state)
+void WebSharedWorkerImpl::sendProtocolMessage(int callId, const WebString& message, const WebString& state)
 {
-    m_client->sendDevToolsMessage(sessionId, callId, message, state);
+    m_client->sendDevToolsMessage(callId, message, state);
 }
 
 void WebSharedWorkerImpl::resumeStartup()
@@ -364,18 +364,18 @@
     m_pauseWorkerContextOnStart = true;
 }
 
-void WebSharedWorkerImpl::attachDevTools(const WebString& hostId, int sessionId)
+void WebSharedWorkerImpl::attachDevTools(const WebString& hostId)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->attach(hostId, sessionId);
+        devtoolsAgent->attach(hostId);
 }
 
-void WebSharedWorkerImpl::reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState)
+void WebSharedWorkerImpl::reattachDevTools(const WebString& hostId, const WebString& savedState)
 {
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->reattach(hostId, sessionId, savedState);
+        devtoolsAgent->reattach(hostId, savedState);
     resumeStartup();
 }
 
@@ -386,13 +386,13 @@
         devtoolsAgent->detach();
 }
 
-void WebSharedWorkerImpl::dispatchDevToolsMessage(int sessionId, const WebString& message)
+void WebSharedWorkerImpl::dispatchDevToolsMessage(const WebString& message)
 {
     if (m_askedToTerminate)
         return;
     WebDevToolsAgent* devtoolsAgent = m_mainFrame->devToolsAgent();
     if (devtoolsAgent)
-        devtoolsAgent->dispatchOnInspectorBackend(sessionId, message);
+        devtoolsAgent->dispatchOnInspectorBackend(message);
 }
 
 WebSharedWorker* WebSharedWorker::create(WebSharedWorkerClient* client)
diff --git a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
index 76648cb6..7845be60 100644
--- a/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
+++ b/third_party/WebKit/Source/web/WebSharedWorkerImpl.h
@@ -93,7 +93,7 @@
     int64_t serviceWorkerID(WebDataSource&) override;
 
     // WebDevToolsAgentClient overrides.
-    void sendProtocolMessage(int sessionId, int callId, const WebString&, const WebString&) override;
+    void sendProtocolMessage(int callId, const WebString&, const WebString&) override;
     void resumeStartup() override;
 
     // WebSharedWorker methods:
@@ -102,10 +102,10 @@
     void terminateWorkerContext() override;
 
     void pauseWorkerContextOnStart() override;
-    void attachDevTools(const WebString& hostId, int sessionId) override;
-    void reattachDevTools(const WebString& hostId, int sesionId, const WebString& savedState) override;
+    void attachDevTools(const WebString& hostId) override;
+    void reattachDevTools(const WebString& hostId, const WebString& savedState) override;
     void detachDevTools() override;
-    void dispatchDevToolsMessage(int sessionId, const WebString&) override;
+    void dispatchDevToolsMessage(const WebString&) override;
 
 private:
     ~WebSharedWorkerImpl() override;
diff --git a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
index ff4e07a..0eab234d 100644
--- a/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebPageSerializerTest.cpp
@@ -125,52 +125,6 @@
     FrameTestHelpers::WebViewHelper m_helper;
 };
 
-TEST_F(WebPageSerializerTest, HTMLNodes)
-{
-    // Register the mocked frame and load it.
-    WebURL topFrameURL = toKURL("http://www.test.com");
-    registerMockedURLLoad("http://www.test.com", WebString::fromUTF8("simple_page.html"));
-    registerMockedURLLoad("http://www.example.com/beautifull.css", WebString::fromUTF8("beautifull.css"));
-
-    registerMockedImageURL("http://www.test.com/imageButton.png");
-    registerMockedImageURL("http://www.test.com/tableBackground.png");
-    registerMockedImageURL("http://www.test.com/trBackground.png");
-    registerMockedImageURL("http://www.test.com/tdBackground.png");
-    registerMockedImageURL("http://www.test.com/innerFrame.png");
-    registerMockedImageURL("http://www.test.com/bodyBackground.jpg");
-    registerMockedImageURL("https://www.secure.com/https.gif");
-    registerMockedImageURL("ftp://ftp.com/ftp.gif");
-    registerMockedImageURL("unknown://unkown.com/unknown.gif");
-
-    loadURLInTopFrame(topFrameURL);
-
-    // Retrieve all resources.
-    WebVector<WebURL> frames;
-    WebVector<WebURL> resources;
-    ASSERT_TRUE(WebPageSerializer::retrieveAllResources(
-        webView(), m_supportedSchemes, &resources, &frames));
-
-    // Tests that all resources from the frame have been retrieved.
-    EXPECT_EQ(1U, frames.size()); // There should be no duplicates.
-    EXPECT_TRUE(webVectorContains(frames, "http://www.test.com"));
-
-    EXPECT_EQ(14U, resources.size()); // There should be no duplicates.
-    EXPECT_TRUE(webVectorContains(resources, "http://www.example.com/beautifull.css"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/awesome.js"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/bodyBackground.jpg"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/awesome.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/imageButton.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/tableBackground.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/trBackground.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/tdBackground.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.evene.fr/citations/auteur.php?ida=46"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.brainyquote.com/quotes/authors/c/charles_darwin.html"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/why_deleted.html"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/why_inserted.html"));
-    EXPECT_TRUE(webVectorContains(resources, "https://www.secure.com/https.gif"));
-    EXPECT_TRUE(webVectorContains(resources, "file://c/my_folder/file.gif"));
-}
-
 TEST_F(WebPageSerializerTest, URLAttributeValues)
 {
     WebURL topFrameURL = toKURL("http://www.test.com");
@@ -231,45 +185,4 @@
     EXPECT_EQ("<!-- saved from url=(0030)http://www.test.com/?-%2Dx-%2D -->", serializerClient.toString().substr(1, 60));
 }
 
-TEST_F(WebPageSerializerTest, MultipleFrames)
-{
-    // Register the mocked frames.
-    WebURL topFrameURL = toKURL("http://www.test.com");
-    registerMockedURLLoad("http://www.test.com", WebString::fromUTF8("top_frame.html"));
-    registerMockedURLLoad("http://www.test.com/simple_iframe.html",
-                          WebString::fromUTF8("simple_iframe.html"));
-    registerMockedURLLoad("http://www.test.com/object_iframe.html",
-                          WebString::fromUTF8("object_iframe.html"));
-    registerMockedURLLoad("http://www.test.com/embed_iframe.html",
-                          WebString::fromUTF8("embed_iframe.html"));
-    registerMockedImageURL("http://www.test.com/innerFrame.png");
-    registerMockedImageURL("http://www.test.com/embed.png");
-    registerMockedImageURL("http://www.test.com/object.png");
-
-    loadURLInTopFrame(topFrameURL);
-
-    // Retrieve all resources.
-    WebVector<WebURL> frames;
-    WebVector<WebURL> resources;
-    ASSERT_TRUE(WebPageSerializer::retrieveAllResources(
-        webView(), m_supportedSchemes, &resources, &frames));
-
-    // Tests that all resources from the frame have been retrieved.
-    EXPECT_EQ(4U, frames.size()); // There should be no duplicates.
-    EXPECT_TRUE(webVectorContains(frames, "http://www.test.com"));
-    EXPECT_TRUE(webVectorContains(frames, "http://www.test.com/simple_iframe.html"));
-    EXPECT_TRUE(webVectorContains(frames, "http://www.test.com/object_iframe.html"));
-    EXPECT_TRUE(webVectorContains(frames, "http://www.test.com/embed_iframe.html"));
-
-    EXPECT_EQ(5U, resources.size()); // There should be no duplicates.
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/awesome.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/innerFrame.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/flash.swf"));
-    // FIXME: for some reason the following resources is missing on one of the bot
-    //        causing the test to fail. Probably a plugin issue.
-    // EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/music.mid"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/object.png"));
-    EXPECT_TRUE(webVectorContains(resources, "http://www.test.com/embed.png"));
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/wtf/NullPtr.h b/third_party/WebKit/Source/wtf/NullPtr.h
deleted file mode 100644
index 6d9949d..0000000
--- a/third_party/WebKit/Source/wtf/NullPtr.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-
-Copyright (C) 2010 Apple Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
-1.  Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-2.  Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in the
-    documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
-DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-*/
-
-#ifndef NullPtr_h
-#define NullPtr_h
-
-// For compilers and standard libraries that do not yet include it, this adds the
-// nullptr_t type and nullptr object. They are defined in the same namespaces they
-// would be in compiler and library that had the support.
-
-// Need to include one of the standard C++ library anyway in order to have
-// __GLIBCXX__ or _STLPORT_VERSION.
-#include <cstddef>
-
-// libstdc++ supports nullptr_t starting with gcc 4.6. STLport doesn't define it.
-#if (defined(__GLIBCXX__) && __GLIBCXX__ < 20110325) || defined(_STLPORT_VERSION)
-namespace std {
-typedef decltype(nullptr) nullptr_t;
-}
-#endif
-#endif
diff --git a/third_party/WebKit/Source/wtf/OwnPtr.h b/third_party/WebKit/Source/wtf/OwnPtr.h
index fa4ece7..abc5966b 100644
--- a/third_party/WebKit/Source/wtf/OwnPtr.h
+++ b/third_party/WebKit/Source/wtf/OwnPtr.h
@@ -24,7 +24,6 @@
 
 #include "wtf/HashTableDeletedValueType.h"
 #include "wtf/Noncopyable.h"
-#include "wtf/NullPtr.h"
 #include "wtf/OwnPtrCommon.h"
 #include <algorithm>
 #include <utility>
diff --git a/third_party/WebKit/Source/wtf/PassOwnPtr.h b/third_party/WebKit/Source/wtf/PassOwnPtr.h
index 4bc5c0ed..452a12b 100644
--- a/third_party/WebKit/Source/wtf/PassOwnPtr.h
+++ b/third_party/WebKit/Source/wtf/PassOwnPtr.h
@@ -27,7 +27,6 @@
 #ifndef WTF_PassOwnPtr_h
 #define WTF_PassOwnPtr_h
 
-#include "wtf/NullPtr.h"
 #include "wtf/OwnPtrCommon.h"
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/PassRefPtr.h b/third_party/WebKit/Source/wtf/PassRefPtr.h
index 5e3a4e1..8fce6bb 100644
--- a/third_party/WebKit/Source/wtf/PassRefPtr.h
+++ b/third_party/WebKit/Source/wtf/PassRefPtr.h
@@ -22,7 +22,6 @@
 #define WTF_PassRefPtr_h
 
 #include "wtf/Assertions.h"
-#include "wtf/NullPtr.h"
 #include "wtf/RawPtr.h"
 #include "wtf/TypeTraits.h"
 
diff --git a/third_party/WebKit/Source/wtf/RawPtr.h b/third_party/WebKit/Source/wtf/RawPtr.h
index 5d6584ba..c3a82ec 100644
--- a/third_party/WebKit/Source/wtf/RawPtr.h
+++ b/third_party/WebKit/Source/wtf/RawPtr.h
@@ -32,7 +32,6 @@
 #define WTF_RawPtr_h
 
 #include "wtf/HashTableDeletedValueType.h"
-#include "wtf/NullPtr.h"
 #include "wtf/TypeTraits.h"
 #include <algorithm>
 #include <stdint.h>
diff --git a/third_party/WebKit/Source/wtf/RetainPtr.h b/third_party/WebKit/Source/wtf/RetainPtr.h
index 3ba98f4f..f063901 100644
--- a/third_party/WebKit/Source/wtf/RetainPtr.h
+++ b/third_party/WebKit/Source/wtf/RetainPtr.h
@@ -23,7 +23,6 @@
 
 #include "wtf/HashTableDeletedValueType.h"
 #include "wtf/HashTraits.h"
-#include "wtf/NullPtr.h"
 #include "wtf/TypeTraits.h"
 #include <algorithm>
 #include <utility>
diff --git a/third_party/WebKit/Source/wtf/wtf.gypi b/third_party/WebKit/Source/wtf/wtf.gypi
index 48ab13b..1a5f7e03 100644
--- a/third_party/WebKit/Source/wtf/wtf.gypi
+++ b/third_party/WebKit/Source/wtf/wtf.gypi
@@ -81,7 +81,6 @@
             'NonCopyingSort.h',
             'Noncopyable.h',
             'NotFound.h',
-            'NullPtr.h',
             'Optional.h',
             'OwnPtr.h',
             'OwnPtrCommon.h',
diff --git a/third_party/WebKit/public/platform/WebPassOwnPtr.h b/third_party/WebKit/public/platform/WebPassOwnPtr.h
index fc57aa2..217bd54 100644
--- a/third_party/WebKit/public/platform/WebPassOwnPtr.h
+++ b/third_party/WebKit/public/platform/WebPassOwnPtr.h
@@ -6,6 +6,7 @@
 #define WebPassOwnPtr_h
 
 #include "public/platform/WebCommon.h"
+#include <cstddef>
 
 #if INSIDE_BLINK
 #include "wtf/PassOwnPtr.h"
@@ -22,7 +23,7 @@
 class WebPassOwnPtr final {
 public:
     WebPassOwnPtr() : m_ptr(nullptr) {}
-    WebPassOwnPtr(decltype(nullptr)) : m_ptr(nullptr) {}
+    WebPassOwnPtr(std::nullptr_t) : m_ptr(nullptr) {}
     // We need |const| to bind an rvalue. As a result, |m_ptr| needs to be
     // mutable because we manipulate it.
     template <typename U>
diff --git a/third_party/WebKit/public/platform/WebPrivateOwnPtr.h b/third_party/WebKit/public/platform/WebPrivateOwnPtr.h
index 8b91126..9dea900 100644
--- a/third_party/WebKit/public/platform/WebPrivateOwnPtr.h
+++ b/third_party/WebKit/public/platform/WebPrivateOwnPtr.h
@@ -29,6 +29,7 @@
 
 #include "WebCommon.h"
 #include "WebNonCopyable.h"
+#include <cstddef>
 
 #if INSIDE_BLINK
 #include "wtf/PassOwnPtr.h"
@@ -46,7 +47,7 @@
 class WebPrivateOwnPtr : public WebNonCopyable {
 public:
     WebPrivateOwnPtr() : m_ptr(nullptr) {}
-    WebPrivateOwnPtr(decltype(nullptr)) : m_ptr(nullptr) {}
+    WebPrivateOwnPtr(std::nullptr_t) : m_ptr(nullptr) {}
     ~WebPrivateOwnPtr() { BLINK_ASSERT(!m_ptr); }
 
     explicit WebPrivateOwnPtr(T* ptr)
diff --git a/third_party/WebKit/public/web/WebDevToolsAgent.h b/third_party/WebKit/public/web/WebDevToolsAgent.h
index 05daf115..dcb76c8 100644
--- a/third_party/WebKit/public/web/WebDevToolsAgent.h
+++ b/third_party/WebKit/public/web/WebDevToolsAgent.h
@@ -43,13 +43,13 @@
 public:
     virtual ~WebDevToolsAgent() {}
 
-    virtual void attach(const WebString& hostId, int sessionId) = 0;
-    virtual void reattach(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
+    virtual void attach(const WebString& hostId) = 0;
+    virtual void reattach(const WebString& hostId, const WebString& savedState) = 0;
     virtual void detach() = 0;
 
     virtual void continueProgram() = 0;
 
-    virtual void dispatchOnInspectorBackend(int sessionId, const WebString& message) = 0;
+    virtual void dispatchOnInspectorBackend(const WebString& message) = 0;
 
     virtual void inspectElementAt(const WebPoint&) = 0;
 
@@ -64,7 +64,7 @@
         virtual WebString message() = 0;
     };
     // Asynchronously request debugger to pause immediately and run the command.
-    BLINK_EXPORT static void interruptAndDispatch(int sessionId, MessageDescriptor*);
+    BLINK_EXPORT static void interruptAndDispatch(MessageDescriptor*);
     BLINK_EXPORT static bool shouldInterruptForMessage(const WebString&);
 
 };
diff --git a/third_party/WebKit/public/web/WebDevToolsAgentClient.h b/third_party/WebKit/public/web/WebDevToolsAgentClient.h
index fa8c9b7..f674358 100644
--- a/third_party/WebKit/public/web/WebDevToolsAgentClient.h
+++ b/third_party/WebKit/public/web/WebDevToolsAgentClient.h
@@ -44,7 +44,7 @@
 public:
     // Sends response message over the protocol, update agent state on the browser side for
     // potential re-attach. |callId| for notifications is 0, |state| for notifications is empty.
-    virtual void sendProtocolMessage(int sessionId, int callId, const WebString& response, const WebString& state) { }
+    virtual void sendProtocolMessage(int callId, const WebString& response, const WebString& state) { }
 
     // Returns process id.
     virtual long processId() { return -1; }
diff --git a/third_party/WebKit/public/web/WebEmbeddedWorker.h b/third_party/WebKit/public/web/WebEmbeddedWorker.h
index 027e030d..0731215 100644
--- a/third_party/WebKit/public/web/WebEmbeddedWorker.h
+++ b/third_party/WebKit/public/web/WebEmbeddedWorker.h
@@ -59,10 +59,10 @@
     virtual void terminateWorkerContext() = 0;
 
     // Inspector related methods.
-    virtual void attachDevTools(const WebString& hostId, int sessionId) = 0;
-    virtual void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
+    virtual void attachDevTools(const WebString& hostId) = 0;
+    virtual void reattachDevTools(const WebString& hostId, const WebString& savedState) = 0;
     virtual void detachDevTools() = 0;
-    virtual void dispatchDevToolsMessage(int sessionId, const WebString&) = 0;
+    virtual void dispatchDevToolsMessage(const WebString&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebPageSerializer.h b/third_party/WebKit/public/web/WebPageSerializer.h
index f1a5f372..285fc865 100644
--- a/third_party/WebKit/public/web/WebPageSerializer.h
+++ b/third_party/WebKit/public/web/WebPageSerializer.h
@@ -47,18 +47,6 @@
 // which contain all resource links that have local copy.
 class WebPageSerializer {
 public:
-    struct Resource {
-        WebURL url;
-        WebCString mimeType;
-        WebCString data;
-    };
-
-    // Serializes all the frames from the WebView, retrieves the page's
-    // resources (such as images and CSS) and adds them to the passed vector.
-    // The first resource in that vector is the top frame contents.
-    // Note that this also strips-out any script tag or link to JavaScript.
-    BLINK_EXPORT static void serialize(WebView*, WebVector<Resource>*);
-
     // Serializes the WebView contents to a MHTML representation.
     BLINK_EXPORT static WebCString serializeToMHTML(WebView*);
 
@@ -93,14 +81,6 @@
         const WebVector<WebString>& localPaths,
         const WebString& localDirectoryName);
 
-    // Retrieve all the resource for the passed view, including the main frame
-    // and sub-frames. Returns true if all resources were retrieved
-    // successfully.
-    BLINK_EXPORT static bool retrieveAllResources(WebView*,
-                                                   const WebVector<WebCString>& supportedSchemes,
-                                                   WebVector<WebURL>* resources,
-                                                   WebVector<WebURL>* frames);
-
     // FIXME: The following are here for unit testing purposes. Consider
     // changing the unit tests instead.
 
diff --git a/third_party/WebKit/public/web/WebSharedWorker.h b/third_party/WebKit/public/web/WebSharedWorker.h
index 8143de2..407d3d1 100644
--- a/third_party/WebKit/public/web/WebSharedWorker.h
+++ b/third_party/WebKit/public/web/WebSharedWorker.h
@@ -62,10 +62,10 @@
     virtual void terminateWorkerContext() = 0;
 
     virtual void pauseWorkerContextOnStart() = 0;
-    virtual void attachDevTools(const WebString& hostId, int sessionId) = 0;
-    virtual void reattachDevTools(const WebString& hostId, int sessionId, const WebString& savedState) = 0;
+    virtual void attachDevTools(const WebString& hostId) = 0;
+    virtual void reattachDevTools(const WebString& hostId, const WebString& savedState) = 0;
     virtual void detachDevTools() = 0;
-    virtual void dispatchDevToolsMessage(int sessionId, const WebString&) = 0;
+    virtual void dispatchDevToolsMessage(const WebString&) = 0;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/WebSharedWorkerClient.h b/third_party/WebKit/public/web/WebSharedWorkerClient.h
index bca580d..cae3117 100644
--- a/third_party/WebKit/public/web/WebSharedWorkerClient.h
+++ b/third_party/WebKit/public/web/WebSharedWorkerClient.h
@@ -78,7 +78,7 @@
     // Ownership of the returned object is transferred to the caller.
     virtual WebServiceWorkerNetworkProvider* createServiceWorkerNetworkProvider(WebDataSource*) { return nullptr; }
 
-    virtual void sendDevToolsMessage(int sessionId, int callId, const WebString& message, const WebString& state) { }
+    virtual void sendDevToolsMessage(int callId, const WebString& message, const WebString& state) { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
index 18fadb6..473a176 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextClient.h
@@ -103,7 +103,7 @@
     virtual void reportConsoleMessage(int source, int level, const WebString& message, int lineNumber, const WebString& sourceURL) { }
 
     // Inspector related messages.
-    virtual void sendDevToolsMessage(int sessionId, int callId, const WebString& message, const WebString& state) { }
+    virtual void sendDevToolsMessage(int callId, const WebString& message, const WebString& state) { }
 
     // ServiceWorker specific method.
     virtual void didHandleActivateEvent(int eventID, WebServiceWorkerEventResult result) { }
diff --git a/third_party/boringssl/boringssl.gypi b/third_party/boringssl/boringssl.gypi
index 149a029b..19484fb 100644
--- a/third_party/boringssl/boringssl.gypi
+++ b/third_party/boringssl/boringssl.gypi
@@ -305,6 +305,7 @@
     ],
     'boringssl_linux_aarch64_sources': [
       'linux-aarch64/crypto/aes/aesv8-armx64.S',
+      'linux-aarch64/crypto/bn/armv8-mont.S',
       'linux-aarch64/crypto/modes/ghashv8-armx64.S',
       'linux-aarch64/crypto/sha/sha1-armv8.S',
       'linux-aarch64/crypto/sha/sha256-armv8.S',
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index 258a5c3..38580d1 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -189,43 +189,43 @@
     0x28328b9b,
     0x28330b6c,
     0x28338bae,
-    0x2c322bfd,
-    0x2c32ac0b,
-    0x2c332c1d,
-    0x2c33ac2f,
-    0x2c342c43,
-    0x2c34ac55,
-    0x2c352c70,
-    0x2c35ac82,
-    0x2c362c95,
+    0x2c322c0b,
+    0x2c32ac19,
+    0x2c332c2b,
+    0x2c33ac3d,
+    0x2c342c51,
+    0x2c34ac63,
+    0x2c352c7e,
+    0x2c35ac90,
+    0x2c362ca3,
     0x2c3682f3,
-    0x2c372ca2,
-    0x2c37acb4,
-    0x2c382cc7,
-    0x2c38acd5,
-    0x2c392ce5,
-    0x2c39acf7,
-    0x2c3a2d0b,
-    0x2c3aad1c,
+    0x2c372cb0,
+    0x2c37acc2,
+    0x2c382cd5,
+    0x2c38ace3,
+    0x2c392cf3,
+    0x2c39ad05,
+    0x2c3a2d19,
+    0x2c3aad2a,
     0x2c3b1359,
-    0x2c3bad2d,
-    0x2c3c2d41,
-    0x2c3cad57,
-    0x2c3d2d70,
-    0x2c3dad9e,
-    0x2c3e2dac,
-    0x2c3eadc4,
-    0x2c3f2ddc,
-    0x2c3fade9,
-    0x2c402e0c,
-    0x2c40ae2b,
+    0x2c3bad3b,
+    0x2c3c2d4f,
+    0x2c3cad65,
+    0x2c3d2d7e,
+    0x2c3dadac,
+    0x2c3e2dba,
+    0x2c3eadd2,
+    0x2c3f2dea,
+    0x2c3fadf7,
+    0x2c402e1a,
+    0x2c40ae39,
     0x2c4111c3,
-    0x2c41ae3c,
-    0x2c422e4f,
+    0x2c41ae4a,
+    0x2c422e5d,
     0x2c429135,
-    0x2c432e60,
+    0x2c432e6e,
     0x2c4386a2,
-    0x2c442d8d,
+    0x2c442d9b,
     0x30320000,
     0x30328015,
     0x3033001f,
@@ -393,178 +393,179 @@
     0x40471b35,
     0x40479b47,
     0x40481b6b,
-    0x40489b8b,
-    0x40491b9f,
-    0x40499bb4,
-    0x404a1bcd,
-    0x404a9c07,
-    0x404b1c38,
-    0x404b9c6e,
-    0x404c1c89,
-    0x404c9ca3,
-    0x404d1cba,
-    0x404d9ce2,
-    0x404e1cf9,
-    0x404e9d15,
-    0x404f1d31,
-    0x404f9d52,
-    0x40501d74,
-    0x40509d90,
-    0x40511da4,
-    0x40519db1,
-    0x40521dc8,
-    0x40529dd8,
-    0x40531de8,
-    0x40539dfc,
-    0x40541e17,
-    0x40549e27,
-    0x40551e3e,
-    0x40559e4d,
-    0x40561e7a,
-    0x40569e92,
-    0x40571eae,
-    0x40579ec7,
-    0x40581eda,
-    0x40589eef,
-    0x40591f12,
-    0x40599f3d,
-    0x405a1f4a,
-    0x405a9f63,
-    0x405b1f7b,
-    0x405b9f8e,
-    0x405c1fa3,
-    0x405c9fb5,
-    0x405d1fca,
-    0x405d9fda,
-    0x405e1ff3,
-    0x405ea007,
-    0x405f2017,
-    0x405fa02f,
-    0x40602040,
-    0x4060a053,
-    0x40612064,
-    0x4061a082,
-    0x40622093,
-    0x4062a0a0,
-    0x406320b7,
-    0x4063a0f8,
-    0x4064210f,
-    0x4064a11c,
-    0x4065212a,
-    0x4065a14c,
-    0x40662174,
-    0x4066a189,
-    0x406721a0,
-    0x4067a1b1,
-    0x406821c2,
-    0x4068a1d3,
-    0x406921e8,
-    0x4069a1ff,
-    0x406a2210,
-    0x406aa229,
-    0x406b2244,
-    0x406ba25b,
-    0x406c22c8,
-    0x406ca2e9,
-    0x406d22fc,
-    0x406da31d,
-    0x406e2338,
-    0x406ea381,
-    0x406f23a2,
-    0x406fa3c8,
-    0x407023e8,
-    0x4070a404,
-    0x40712591,
-    0x4071a5b4,
-    0x407225ca,
-    0x4072a5e9,
-    0x40732601,
-    0x4073a621,
-    0x4074284b,
-    0x4074a870,
-    0x4075288b,
-    0x4075a8aa,
-    0x407628d9,
-    0x4076a901,
-    0x40772932,
-    0x4077a951,
-    0x4078298b,
-    0x4078a9a2,
-    0x407929b5,
-    0x4079a9d2,
+    0x40489b99,
+    0x40491bad,
+    0x40499bc2,
+    0x404a1bdb,
+    0x404a9c15,
+    0x404b1c46,
+    0x404b9c7c,
+    0x404c1c97,
+    0x404c9cb1,
+    0x404d1cc8,
+    0x404d9cf0,
+    0x404e1d07,
+    0x404e9d23,
+    0x404f1d3f,
+    0x404f9d60,
+    0x40501d82,
+    0x40509d9e,
+    0x40511db2,
+    0x40519dbf,
+    0x40521dd6,
+    0x40529de6,
+    0x40531df6,
+    0x40539e0a,
+    0x40541e25,
+    0x40549e35,
+    0x40551e4c,
+    0x40559e5b,
+    0x40561e88,
+    0x40569ea0,
+    0x40571ebc,
+    0x40579ed5,
+    0x40581ee8,
+    0x40589efd,
+    0x40591f20,
+    0x40599f4b,
+    0x405a1f58,
+    0x405a9f71,
+    0x405b1f89,
+    0x405b9f9c,
+    0x405c1fb1,
+    0x405c9fc3,
+    0x405d1fd8,
+    0x405d9fe8,
+    0x405e2001,
+    0x405ea015,
+    0x405f2025,
+    0x405fa03d,
+    0x4060204e,
+    0x4060a061,
+    0x40612072,
+    0x4061a090,
+    0x406220a1,
+    0x4062a0ae,
+    0x406320c5,
+    0x4063a106,
+    0x4064211d,
+    0x4064a12a,
+    0x40652138,
+    0x4065a15a,
+    0x40662182,
+    0x4066a197,
+    0x406721ae,
+    0x4067a1bf,
+    0x406821d0,
+    0x4068a1e1,
+    0x406921f6,
+    0x4069a20d,
+    0x406a221e,
+    0x406aa237,
+    0x406b2252,
+    0x406ba269,
+    0x406c22d6,
+    0x406ca2f7,
+    0x406d230a,
+    0x406da32b,
+    0x406e2346,
+    0x406ea38f,
+    0x406f23b0,
+    0x406fa3d6,
+    0x407023f6,
+    0x4070a412,
+    0x4071259f,
+    0x4071a5c2,
+    0x407225d8,
+    0x4072a5f7,
+    0x4073260f,
+    0x4073a62f,
+    0x40742859,
+    0x4074a87e,
+    0x40752899,
+    0x4075a8b8,
+    0x407628e7,
+    0x4076a90f,
+    0x40772940,
+    0x4077a95f,
+    0x40782999,
+    0x4078a9b0,
+    0x407929c3,
+    0x4079a9e0,
     0x407a0782,
-    0x407aa9e4,
-    0x407b29f7,
-    0x407baa10,
-    0x407c2a28,
+    0x407aa9f2,
+    0x407b2a05,
+    0x407baa1e,
+    0x407c2a36,
     0x407c90bd,
-    0x407d2a3c,
-    0x407daa56,
-    0x407e2a67,
-    0x407eaa7b,
-    0x407f2a89,
-    0x407faaa4,
+    0x407d2a4a,
+    0x407daa64,
+    0x407e2a75,
+    0x407eaa89,
+    0x407f2a97,
+    0x407faab2,
     0x40801286,
-    0x4080aac9,
-    0x40812aeb,
-    0x4081ab06,
-    0x40822b1b,
-    0x4082ab33,
-    0x40832b4b,
-    0x4083ab62,
-    0x40842b78,
-    0x4084ab84,
-    0x40852b97,
-    0x4085abac,
-    0x40862bbe,
-    0x4086abd3,
-    0x40872bdc,
-    0x40879cd0,
+    0x4080aad7,
+    0x40812af9,
+    0x4081ab14,
+    0x40822b29,
+    0x4082ab41,
+    0x40832b59,
+    0x4083ab70,
+    0x40842b86,
+    0x4084ab92,
+    0x40852ba5,
+    0x4085abba,
+    0x40862bcc,
+    0x4086abe1,
+    0x40872bea,
+    0x40879cde,
     0x40880083,
-    0x4088a0d7,
+    0x4088a0e5,
     0x40890a17,
-    0x4089a273,
-    0x408a1bf0,
-    0x408aa29d,
-    0x408b291a,
-    0x408ba976,
-    0x408c2353,
-    0x408c9c21,
-    0x408d1c56,
-    0x408d9e68,
+    0x4089a281,
+    0x408a1bfe,
+    0x408aa2ab,
+    0x408b2928,
+    0x408ba984,
+    0x408c2361,
+    0x408c9c2f,
+    0x408d1c64,
+    0x408d9e76,
     0x408e1ab9,
     0x408e9add,
-    0x408f1f20,
-    0x41f424bc,
-    0x41f9254e,
-    0x41fe2441,
-    0x41fea672,
-    0x41ff2763,
-    0x420324d5,
-    0x420824f7,
-    0x4208a533,
-    0x42092425,
-    0x4209a56d,
-    0x420a247c,
-    0x420aa45c,
-    0x420b249c,
-    0x420ba515,
-    0x420c277f,
-    0x420ca63f,
-    0x420d2659,
-    0x420da690,
-    0x421226aa,
-    0x42172746,
-    0x4217a6ec,
-    0x421c270e,
-    0x421f26c9,
-    0x42212796,
-    0x42262729,
-    0x422b282f,
-    0x422ba7f8,
-    0x422c2817,
-    0x422ca7d2,
-    0x422d27b1,
+    0x408f1f2e,
+    0x408f9b8b,
+    0x41f424ca,
+    0x41f9255c,
+    0x41fe244f,
+    0x41fea680,
+    0x41ff2771,
+    0x420324e3,
+    0x42082505,
+    0x4208a541,
+    0x42092433,
+    0x4209a57b,
+    0x420a248a,
+    0x420aa46a,
+    0x420b24aa,
+    0x420ba523,
+    0x420c278d,
+    0x420ca64d,
+    0x420d2667,
+    0x420da69e,
+    0x421226b8,
+    0x42172754,
+    0x4217a6fa,
+    0x421c271c,
+    0x421f26d7,
+    0x422127a4,
+    0x42262737,
+    0x422b283d,
+    0x422ba806,
+    0x422c2825,
+    0x422ca7e0,
+    0x422d27bf,
     0x443206ad,
     0x443286bc,
     0x443306c8,
@@ -607,69 +608,69 @@
     0x4c3d10bd,
     0x4c3d9449,
     0x4c3e1456,
-    0x50322e72,
-    0x5032ae81,
-    0x50332e8c,
-    0x5033ae9c,
-    0x50342eb5,
-    0x5034aecf,
-    0x50352edd,
-    0x5035aef3,
-    0x50362f05,
-    0x5036af1b,
-    0x50372f34,
-    0x5037af47,
-    0x50382f5f,
-    0x5038af70,
-    0x50392f85,
-    0x5039af99,
-    0x503a2fb9,
-    0x503aafcf,
-    0x503b2fe7,
-    0x503baff9,
-    0x503c3015,
-    0x503cb02c,
-    0x503d3045,
-    0x503db05b,
-    0x503e3068,
-    0x503eb07e,
-    0x503f3090,
+    0x50322e80,
+    0x5032ae8f,
+    0x50332e9a,
+    0x5033aeaa,
+    0x50342ec3,
+    0x5034aedd,
+    0x50352eeb,
+    0x5035af01,
+    0x50362f13,
+    0x5036af29,
+    0x50372f42,
+    0x5037af55,
+    0x50382f6d,
+    0x5038af7e,
+    0x50392f93,
+    0x5039afa7,
+    0x503a2fc7,
+    0x503aafdd,
+    0x503b2ff5,
+    0x503bb007,
+    0x503c3023,
+    0x503cb03a,
+    0x503d3053,
+    0x503db069,
+    0x503e3076,
+    0x503eb08c,
+    0x503f309e,
     0x503f8348,
-    0x504030a3,
-    0x5040b0b3,
-    0x504130cd,
-    0x5041b0dc,
-    0x504230f6,
-    0x5042b113,
-    0x50433123,
-    0x5043b133,
-    0x50443142,
+    0x504030b1,
+    0x5040b0c1,
+    0x504130db,
+    0x5041b0ea,
+    0x50423104,
+    0x5042b121,
+    0x50433131,
+    0x5043b141,
+    0x50443150,
     0x50448414,
-    0x50453156,
-    0x5045b174,
-    0x50463187,
-    0x5046b19d,
-    0x504731af,
-    0x5047b1c4,
-    0x504831ea,
-    0x5048b1f8,
-    0x5049320b,
-    0x5049b220,
-    0x504a3236,
-    0x504ab246,
-    0x504b3266,
-    0x504bb279,
-    0x504c329c,
-    0x504cb2ca,
-    0x504d32dc,
-    0x504db2f9,
-    0x504e3314,
-    0x504eb330,
-    0x504f3342,
-    0x504fb359,
-    0x50503368,
+    0x50453164,
+    0x5045b182,
+    0x50463195,
+    0x5046b1ab,
+    0x504731bd,
+    0x5047b1d2,
+    0x504831f8,
+    0x5048b206,
+    0x50493219,
+    0x5049b22e,
+    0x504a3244,
+    0x504ab254,
+    0x504b3274,
+    0x504bb287,
+    0x504c32aa,
+    0x504cb2d8,
+    0x504d32ea,
+    0x504db307,
+    0x504e3322,
+    0x504eb33e,
+    0x504f3350,
+    0x504fb367,
+    0x50503376,
     0x50508687,
-    0x5051337b,
+    0x50513389,
     0x58320e1f,
     0x68320de1,
     0x68328b9b,
@@ -1065,6 +1066,7 @@
     "DECRYPTION_FAILED\0"
     "DECRYPTION_FAILED_OR_BAD_RECORD_MAC\0"
     "DH_PUBLIC_VALUE_LENGTH_IS_WRONG\0"
+    "DH_P_TOO_LONG\0"
     "DIGEST_CHECK_FAILED\0"
     "DTLS_MESSAGE_TOO_BIG\0"
     "ECC_CERT_NOT_FOR_SIGNING\0"
diff --git a/third_party/boringssl/linux-aarch64/crypto/bn/armv8-mont.S b/third_party/boringssl/linux-aarch64/crypto/bn/armv8-mont.S
new file mode 100644
index 0000000..9355ce7
--- /dev/null
+++ b/third_party/boringssl/linux-aarch64/crypto/bn/armv8-mont.S
@@ -0,0 +1,1406 @@
+#if defined(__aarch64__)
+.text
+
+.globl	bn_mul_mont
+.type	bn_mul_mont,%function
+.align	5
+bn_mul_mont:
+	tst	x5,#7
+	b.eq	__bn_sqr8x_mont
+	tst	x5,#3
+	b.eq	__bn_mul4x_mont
+.Lmul_mont:
+	stp	x29,x30,[sp,#-64]!
+	add	x29,sp,#0
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+
+	ldr	x9,[x2],#8		// bp[0]
+	sub	x22,sp,x5,lsl#3
+	ldp	x7,x8,[x1],#16	// ap[0..1]
+	lsl	x5,x5,#3
+	ldr	x4,[x4]		// *n0
+	and	x22,x22,#-16		// ABI says so
+	ldp	x13,x14,[x3],#16	// np[0..1]
+
+	mul	x6,x7,x9		// ap[0]*bp[0]
+	sub	x21,x5,#16		// j=num-2
+	umulh	x7,x7,x9
+	mul	x10,x8,x9		// ap[1]*bp[0]
+	umulh	x11,x8,x9
+
+	mul	x15,x6,x4		// "tp[0]"*n0
+	mov	sp,x22			// alloca
+
+	// (*)	mul	x12,x13,x15	// np[0]*m1
+	umulh	x13,x13,x15
+	mul	x16,x14,x15		// np[1]*m1
+	// (*)	adds	x12,x12,x6	// discarded
+	// (*)	As for removal of first multiplication and addition
+	//	instructions. The outcome of first addition is
+	//	guaranteed to be zero, which leaves two computationally
+	//	significant outcomes: it either carries or not. Then
+	//	question is when does it carry? Is there alternative
+	//	way to deduce it? If you follow operations, you can
+	//	observe that condition for carry is quite simple:
+	//	x6 being non-zero. So that carry can be calculated
+	//	by adding -1 to x6. That's what next instruction does.
+	subs	xzr,x6,#1		// (*)
+	umulh	x17,x14,x15
+	adc	x13,x13,xzr
+	cbz	x21,.L1st_skip
+
+.L1st:
+	ldr	x8,[x1],#8
+	adds	x6,x10,x7
+	sub	x21,x21,#8		// j--
+	adc	x7,x11,xzr
+
+	ldr	x14,[x3],#8
+	adds	x12,x16,x13
+	mul	x10,x8,x9		// ap[j]*bp[0]
+	adc	x13,x17,xzr
+	umulh	x11,x8,x9
+
+	adds	x12,x12,x6
+	mul	x16,x14,x15		// np[j]*m1
+	adc	x13,x13,xzr
+	umulh	x17,x14,x15
+	str	x12,[x22],#8		// tp[j-1]
+	cbnz	x21,.L1st
+
+.L1st_skip:
+	adds	x6,x10,x7
+	sub	x1,x1,x5		// rewind x1
+	adc	x7,x11,xzr
+
+	adds	x12,x16,x13
+	sub	x3,x3,x5		// rewind x3
+	adc	x13,x17,xzr
+
+	adds	x12,x12,x6
+	sub	x20,x5,#8		// i=num-1
+	adcs	x13,x13,x7
+
+	adc	x19,xzr,xzr		// upmost overflow bit
+	stp	x12,x13,[x22]
+
+.Louter:
+	ldr	x9,[x2],#8		// bp[i]
+	ldp	x7,x8,[x1],#16
+	ldr	x23,[sp]		// tp[0]
+	add	x22,sp,#8
+
+	mul	x6,x7,x9		// ap[0]*bp[i]
+	sub	x21,x5,#16		// j=num-2
+	umulh	x7,x7,x9
+	ldp	x13,x14,[x3],#16
+	mul	x10,x8,x9		// ap[1]*bp[i]
+	adds	x6,x6,x23
+	umulh	x11,x8,x9
+	adc	x7,x7,xzr
+
+	mul	x15,x6,x4
+	sub	x20,x20,#8		// i--
+
+	// (*)	mul	x12,x13,x15	// np[0]*m1
+	umulh	x13,x13,x15
+	mul	x16,x14,x15		// np[1]*m1
+	// (*)	adds	x12,x12,x6
+	subs	xzr,x6,#1		// (*)
+	umulh	x17,x14,x15
+	cbz	x21,.Linner_skip
+
+.Linner:
+	ldr	x8,[x1],#8
+	adc	x13,x13,xzr
+	ldr	x23,[x22],#8		// tp[j]
+	adds	x6,x10,x7
+	sub	x21,x21,#8		// j--
+	adc	x7,x11,xzr
+
+	adds	x12,x16,x13
+	ldr	x14,[x3],#8
+	adc	x13,x17,xzr
+
+	mul	x10,x8,x9		// ap[j]*bp[i]
+	adds	x6,x6,x23
+	umulh	x11,x8,x9
+	adc	x7,x7,xzr
+
+	mul	x16,x14,x15		// np[j]*m1
+	adds	x12,x12,x6
+	umulh	x17,x14,x15
+	str	x12,[x22,#-16]		// tp[j-1]
+	cbnz	x21,.Linner
+
+.Linner_skip:
+	ldr	x23,[x22],#8		// tp[j]
+	adc	x13,x13,xzr
+	adds	x6,x10,x7
+	sub	x1,x1,x5		// rewind x1
+	adc	x7,x11,xzr
+
+	adds	x12,x16,x13
+	sub	x3,x3,x5		// rewind x3
+	adcs	x13,x17,x19
+	adc	x19,xzr,xzr
+
+	adds	x6,x6,x23
+	adc	x7,x7,xzr
+
+	adds	x12,x12,x6
+	adcs	x13,x13,x7
+	adc	x19,x19,xzr		// upmost overflow bit
+	stp	x12,x13,[x22,#-16]
+
+	cbnz	x20,.Louter
+
+	// Final step. We see if result is larger than modulus, and
+	// if it is, subtract the modulus. But comparison implies
+	// subtraction. So we subtract modulus, see if it borrowed,
+	// and conditionally copy original value.
+	ldr	x23,[sp]		// tp[0]
+	add	x22,sp,#8
+	ldr	x14,[x3],#8		// np[0]
+	subs	x21,x5,#8		// j=num-1 and clear borrow
+	mov	x1,x0
+.Lsub:
+	sbcs	x8,x23,x14		// tp[j]-np[j]
+	ldr	x23,[x22],#8
+	sub	x21,x21,#8		// j--
+	ldr	x14,[x3],#8
+	str	x8,[x1],#8		// rp[j]=tp[j]-np[j]
+	cbnz	x21,.Lsub
+
+	sbcs	x8,x23,x14
+	sbcs	x19,x19,xzr		// did it borrow?
+	str	x8,[x1],#8		// rp[num-1]
+
+	ldr	x23,[sp]		// tp[0]
+	add	x22,sp,#8
+	ldr	x8,[x0],#8		// rp[0]
+	sub	x5,x5,#8		// num--
+	nop
+.Lcond_copy:
+	sub	x5,x5,#8		// num--
+	csel	x14,x23,x8,lo		// did it borrow?
+	ldr	x23,[x22],#8
+	ldr	x8,[x0],#8
+	str	xzr,[x22,#-16]		// wipe tp
+	str	x14,[x0,#-16]
+	cbnz	x5,.Lcond_copy
+
+	csel	x14,x23,x8,lo
+	str	xzr,[x22,#-8]		// wipe tp
+	str	x14,[x0,#-8]
+
+	ldp	x19,x20,[x29,#16]
+	mov	sp,x29
+	ldp	x21,x22,[x29,#32]
+	mov	x0,#1
+	ldp	x23,x24,[x29,#48]
+	ldr	x29,[sp],#64
+	ret
+.size	bn_mul_mont,.-bn_mul_mont
+.type	__bn_sqr8x_mont,%function
+.align	5
+__bn_sqr8x_mont:
+	cmp	x1,x2
+	b.ne	__bn_mul4x_mont
+.Lsqr8x_mont:
+	stp	x29,x30,[sp,#-128]!
+	add	x29,sp,#0
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+	stp	x0,x3,[sp,#96]	// offload rp and np
+
+	ldp	x6,x7,[x1,#8*0]
+	ldp	x8,x9,[x1,#8*2]
+	ldp	x10,x11,[x1,#8*4]
+	ldp	x12,x13,[x1,#8*6]
+
+	sub	x2,sp,x5,lsl#4
+	lsl	x5,x5,#3
+	ldr	x4,[x4]		// *n0
+	mov	sp,x2			// alloca
+	sub	x27,x5,#8*8
+	b	.Lsqr8x_zero_start
+
+.Lsqr8x_zero:
+	sub	x27,x27,#8*8
+	stp	xzr,xzr,[x2,#8*0]
+	stp	xzr,xzr,[x2,#8*2]
+	stp	xzr,xzr,[x2,#8*4]
+	stp	xzr,xzr,[x2,#8*6]
+.Lsqr8x_zero_start:
+	stp	xzr,xzr,[x2,#8*8]
+	stp	xzr,xzr,[x2,#8*10]
+	stp	xzr,xzr,[x2,#8*12]
+	stp	xzr,xzr,[x2,#8*14]
+	add	x2,x2,#8*16
+	cbnz	x27,.Lsqr8x_zero
+
+	add	x3,x1,x5
+	add	x1,x1,#8*8
+	mov	x19,xzr
+	mov	x20,xzr
+	mov	x21,xzr
+	mov	x22,xzr
+	mov	x23,xzr
+	mov	x24,xzr
+	mov	x25,xzr
+	mov	x26,xzr
+	mov	x2,sp
+	str	x4,[x29,#112]		// offload n0
+
+	// Multiply everything but a[i]*a[i]
+.align	4
+.Lsqr8x_outer_loop:
+        //                                                 a[1]a[0]	(i)
+        //                                             a[2]a[0]
+        //                                         a[3]a[0]
+        //                                     a[4]a[0]
+        //                                 a[5]a[0]
+        //                             a[6]a[0]
+        //                         a[7]a[0]
+        //                                         a[2]a[1]		(ii)
+        //                                     a[3]a[1]
+        //                                 a[4]a[1]
+        //                             a[5]a[1]
+        //                         a[6]a[1]
+        //                     a[7]a[1]
+        //                                 a[3]a[2]			(iii)
+        //                             a[4]a[2]
+        //                         a[5]a[2]
+        //                     a[6]a[2]
+        //                 a[7]a[2]
+        //                         a[4]a[3]				(iv)
+        //                     a[5]a[3]
+        //                 a[6]a[3]
+        //             a[7]a[3]
+        //                 a[5]a[4]					(v)
+        //             a[6]a[4]
+        //         a[7]a[4]
+        //         a[6]a[5]						(vi)
+        //     a[7]a[5]
+        // a[7]a[6]							(vii)
+
+	mul	x14,x7,x6		// lo(a[1..7]*a[0])		(i)
+	mul	x15,x8,x6
+	mul	x16,x9,x6
+	mul	x17,x10,x6
+	adds	x20,x20,x14		// t[1]+lo(a[1]*a[0])
+	mul	x14,x11,x6
+	adcs	x21,x21,x15
+	mul	x15,x12,x6
+	adcs	x22,x22,x16
+	mul	x16,x13,x6
+	adcs	x23,x23,x17
+	umulh	x17,x7,x6		// hi(a[1..7]*a[0])
+	adcs	x24,x24,x14
+	umulh	x14,x8,x6
+	adcs	x25,x25,x15
+	umulh	x15,x9,x6
+	adcs	x26,x26,x16
+	umulh	x16,x10,x6
+	stp	x19,x20,[x2],#8*2	// t[0..1]
+	adc	x19,xzr,xzr		// t[8]
+	adds	x21,x21,x17		// t[2]+lo(a[1]*a[0])
+	umulh	x17,x11,x6
+	adcs	x22,x22,x14
+	umulh	x14,x12,x6
+	adcs	x23,x23,x15
+	umulh	x15,x13,x6
+	adcs	x24,x24,x16
+	mul	x16,x8,x7		// lo(a[2..7]*a[1])		(ii)
+	adcs	x25,x25,x17
+	mul	x17,x9,x7
+	adcs	x26,x26,x14
+	mul	x14,x10,x7
+	adc	x19,x19,x15
+
+	mul	x15,x11,x7
+	adds	x22,x22,x16
+	mul	x16,x12,x7
+	adcs	x23,x23,x17
+	mul	x17,x13,x7
+	adcs	x24,x24,x14
+	umulh	x14,x8,x7		// hi(a[2..7]*a[1])
+	adcs	x25,x25,x15
+	umulh	x15,x9,x7
+	adcs	x26,x26,x16
+	umulh	x16,x10,x7
+	adcs	x19,x19,x17
+	umulh	x17,x11,x7
+	stp	x21,x22,[x2],#8*2	// t[2..3]
+	adc	x20,xzr,xzr		// t[9]
+	adds	x23,x23,x14
+	umulh	x14,x12,x7
+	adcs	x24,x24,x15
+	umulh	x15,x13,x7
+	adcs	x25,x25,x16
+	mul	x16,x9,x8		// lo(a[3..7]*a[2])		(iii)
+	adcs	x26,x26,x17
+	mul	x17,x10,x8
+	adcs	x19,x19,x14
+	mul	x14,x11,x8
+	adc	x20,x20,x15
+
+	mul	x15,x12,x8
+	adds	x24,x24,x16
+	mul	x16,x13,x8
+	adcs	x25,x25,x17
+	umulh	x17,x9,x8		// hi(a[3..7]*a[2])
+	adcs	x26,x26,x14
+	umulh	x14,x10,x8
+	adcs	x19,x19,x15
+	umulh	x15,x11,x8
+	adcs	x20,x20,x16
+	umulh	x16,x12,x8
+	stp	x23,x24,[x2],#8*2	// t[4..5]
+	adc	x21,xzr,xzr		// t[10]
+	adds	x25,x25,x17
+	umulh	x17,x13,x8
+	adcs	x26,x26,x14
+	mul	x14,x10,x9		// lo(a[4..7]*a[3])		(iv)
+	adcs	x19,x19,x15
+	mul	x15,x11,x9
+	adcs	x20,x20,x16
+	mul	x16,x12,x9
+	adc	x21,x21,x17
+
+	mul	x17,x13,x9
+	adds	x26,x26,x14
+	umulh	x14,x10,x9		// hi(a[4..7]*a[3])
+	adcs	x19,x19,x15
+	umulh	x15,x11,x9
+	adcs	x20,x20,x16
+	umulh	x16,x12,x9
+	adcs	x21,x21,x17
+	umulh	x17,x13,x9
+	stp	x25,x26,[x2],#8*2	// t[6..7]
+	adc	x22,xzr,xzr		// t[11]
+	adds	x19,x19,x14
+	mul	x14,x11,x10		// lo(a[5..7]*a[4])		(v)
+	adcs	x20,x20,x15
+	mul	x15,x12,x10
+	adcs	x21,x21,x16
+	mul	x16,x13,x10
+	adc	x22,x22,x17
+
+	umulh	x17,x11,x10		// hi(a[5..7]*a[4])
+	adds	x20,x20,x14
+	umulh	x14,x12,x10
+	adcs	x21,x21,x15
+	umulh	x15,x13,x10
+	adcs	x22,x22,x16
+	mul	x16,x12,x11		// lo(a[6..7]*a[5])		(vi)
+	adc	x23,xzr,xzr		// t[12]
+	adds	x21,x21,x17
+	mul	x17,x13,x11
+	adcs	x22,x22,x14
+	umulh	x14,x12,x11		// hi(a[6..7]*a[5])
+	adc	x23,x23,x15
+
+	umulh	x15,x13,x11
+	adds	x22,x22,x16
+	mul	x16,x13,x12		// lo(a[7]*a[6])		(vii)
+	adcs	x23,x23,x17
+	umulh	x17,x13,x12		// hi(a[7]*a[6])
+	adc	x24,xzr,xzr		// t[13]
+	adds	x23,x23,x14
+	sub	x27,x3,x1	// done yet?
+	adc	x24,x24,x15
+
+	adds	x24,x24,x16
+	sub	x14,x3,x5	// rewinded ap
+	adc	x25,xzr,xzr		// t[14]
+	add	x25,x25,x17
+
+	cbz	x27,.Lsqr8x_outer_break
+
+	mov	x4,x6
+	ldp	x6,x7,[x2,#8*0]
+	ldp	x8,x9,[x2,#8*2]
+	ldp	x10,x11,[x2,#8*4]
+	ldp	x12,x13,[x2,#8*6]
+	adds	x19,x19,x6
+	adcs	x20,x20,x7
+	ldp	x6,x7,[x1,#8*0]
+	adcs	x21,x21,x8
+	adcs	x22,x22,x9
+	ldp	x8,x9,[x1,#8*2]
+	adcs	x23,x23,x10
+	adcs	x24,x24,x11
+	ldp	x10,x11,[x1,#8*4]
+	adcs	x25,x25,x12
+	mov	x0,x1
+	adcs	x26,xzr,x13
+	ldp	x12,x13,[x1,#8*6]
+	add	x1,x1,#8*8
+	//adc	x28,xzr,xzr		// moved below
+	mov	x27,#-8*8
+
+	//                                                         a[8]a[0]
+	//                                                     a[9]a[0]
+	//                                                 a[a]a[0]
+	//                                             a[b]a[0]
+	//                                         a[c]a[0]
+	//                                     a[d]a[0]
+	//                                 a[e]a[0]
+	//                             a[f]a[0]
+	//                                                     a[8]a[1]
+	//                         a[f]a[1]........................
+	//                                                 a[8]a[2]
+	//                     a[f]a[2]........................
+	//                                             a[8]a[3]
+	//                 a[f]a[3]........................
+	//                                         a[8]a[4]
+	//             a[f]a[4]........................
+	//                                     a[8]a[5]
+	//         a[f]a[5]........................
+	//                                 a[8]a[6]
+	//     a[f]a[6]........................
+	//                             a[8]a[7]
+	// a[f]a[7]........................
+.Lsqr8x_mul:
+	mul	x14,x6,x4
+	adc	x28,xzr,xzr		// carry bit, modulo-scheduled
+	mul	x15,x7,x4
+	add	x27,x27,#8
+	mul	x16,x8,x4
+	mul	x17,x9,x4
+	adds	x19,x19,x14
+	mul	x14,x10,x4
+	adcs	x20,x20,x15
+	mul	x15,x11,x4
+	adcs	x21,x21,x16
+	mul	x16,x12,x4
+	adcs	x22,x22,x17
+	mul	x17,x13,x4
+	adcs	x23,x23,x14
+	umulh	x14,x6,x4
+	adcs	x24,x24,x15
+	umulh	x15,x7,x4
+	adcs	x25,x25,x16
+	umulh	x16,x8,x4
+	adcs	x26,x26,x17
+	umulh	x17,x9,x4
+	adc	x28,x28,xzr
+	str	x19,[x2],#8
+	adds	x19,x20,x14
+	umulh	x14,x10,x4
+	adcs	x20,x21,x15
+	umulh	x15,x11,x4
+	adcs	x21,x22,x16
+	umulh	x16,x12,x4
+	adcs	x22,x23,x17
+	umulh	x17,x13,x4
+	ldr	x4,[x0,x27]
+	adcs	x23,x24,x14
+	adcs	x24,x25,x15
+	adcs	x25,x26,x16
+	adcs	x26,x28,x17
+	//adc	x28,xzr,xzr		// moved above
+	cbnz	x27,.Lsqr8x_mul
+					// note that carry flag is guaranteed
+					// to be zero at this point
+	cmp	x1,x3		// done yet?
+	b.eq	.Lsqr8x_break
+
+	ldp	x6,x7,[x2,#8*0]
+	ldp	x8,x9,[x2,#8*2]
+	ldp	x10,x11,[x2,#8*4]
+	ldp	x12,x13,[x2,#8*6]
+	adds	x19,x19,x6
+	ldr	x4,[x0,#-8*8]
+	adcs	x20,x20,x7
+	ldp	x6,x7,[x1,#8*0]
+	adcs	x21,x21,x8
+	adcs	x22,x22,x9
+	ldp	x8,x9,[x1,#8*2]
+	adcs	x23,x23,x10
+	adcs	x24,x24,x11
+	ldp	x10,x11,[x1,#8*4]
+	adcs	x25,x25,x12
+	mov	x27,#-8*8
+	adcs	x26,x26,x13
+	ldp	x12,x13,[x1,#8*6]
+	add	x1,x1,#8*8
+	//adc	x28,xzr,xzr		// moved above
+	b	.Lsqr8x_mul
+
+.align	4
+.Lsqr8x_break:
+	ldp	x6,x7,[x0,#8*0]
+	add	x1,x0,#8*8
+	ldp	x8,x9,[x0,#8*2]
+	sub	x14,x3,x1		// is it last iteration?
+	ldp	x10,x11,[x0,#8*4]
+	sub	x15,x2,x14
+	ldp	x12,x13,[x0,#8*6]
+	cbz	x14,.Lsqr8x_outer_loop
+
+	stp	x19,x20,[x2,#8*0]
+	ldp	x19,x20,[x15,#8*0]
+	stp	x21,x22,[x2,#8*2]
+	ldp	x21,x22,[x15,#8*2]
+	stp	x23,x24,[x2,#8*4]
+	ldp	x23,x24,[x15,#8*4]
+	stp	x25,x26,[x2,#8*6]
+	mov	x2,x15
+	ldp	x25,x26,[x15,#8*6]
+	b	.Lsqr8x_outer_loop
+
+.align	4
+.Lsqr8x_outer_break:
+	// Now multiply above result by 2 and add a[n-1]*a[n-1]|...|a[0]*a[0]
+	ldp	x7,x9,[x14,#8*0]	// recall that x14 is &a[0]
+	ldp	x15,x16,[sp,#8*1]
+	ldp	x11,x13,[x14,#8*2]
+	add	x1,x14,#8*4
+	ldp	x17,x14,[sp,#8*3]
+
+	stp	x19,x20,[x2,#8*0]
+	mul	x19,x7,x7
+	stp	x21,x22,[x2,#8*2]
+	umulh	x7,x7,x7
+	stp	x23,x24,[x2,#8*4]
+	mul	x8,x9,x9
+	stp	x25,x26,[x2,#8*6]
+	mov	x2,sp
+	umulh	x9,x9,x9
+	adds	x20,x7,x15,lsl#1
+	extr	x15,x16,x15,#63
+	sub	x27,x5,#8*4
+
+.Lsqr4x_shift_n_add:
+	adcs	x21,x8,x15
+	extr	x16,x17,x16,#63
+	sub	x27,x27,#8*4
+	adcs	x22,x9,x16
+	ldp	x15,x16,[x2,#8*5]
+	mul	x10,x11,x11
+	ldp	x7,x9,[x1],#8*2
+	umulh	x11,x11,x11
+	mul	x12,x13,x13
+	umulh	x13,x13,x13
+	extr	x17,x14,x17,#63
+	stp	x19,x20,[x2,#8*0]
+	adcs	x23,x10,x17
+	extr	x14,x15,x14,#63
+	stp	x21,x22,[x2,#8*2]
+	adcs	x24,x11,x14
+	ldp	x17,x14,[x2,#8*7]
+	extr	x15,x16,x15,#63
+	adcs	x25,x12,x15
+	extr	x16,x17,x16,#63
+	adcs	x26,x13,x16
+	ldp	x15,x16,[x2,#8*9]
+	mul	x6,x7,x7
+	ldp	x11,x13,[x1],#8*2
+	umulh	x7,x7,x7
+	mul	x8,x9,x9
+	umulh	x9,x9,x9
+	stp	x23,x24,[x2,#8*4]
+	extr	x17,x14,x17,#63
+	stp	x25,x26,[x2,#8*6]
+	add	x2,x2,#8*8
+	adcs	x19,x6,x17
+	extr	x14,x15,x14,#63
+	adcs	x20,x7,x14
+	ldp	x17,x14,[x2,#8*3]
+	extr	x15,x16,x15,#63
+	cbnz	x27,.Lsqr4x_shift_n_add
+	ldp	x1,x4,[x29,#104]	// pull np and n0
+
+	adcs	x21,x8,x15
+	extr	x16,x17,x16,#63
+	adcs	x22,x9,x16
+	ldp	x15,x16,[x2,#8*5]
+	mul	x10,x11,x11
+	umulh	x11,x11,x11
+	stp	x19,x20,[x2,#8*0]
+	mul	x12,x13,x13
+	umulh	x13,x13,x13
+	stp	x21,x22,[x2,#8*2]
+	extr	x17,x14,x17,#63
+	adcs	x23,x10,x17
+	extr	x14,x15,x14,#63
+	ldp	x19,x20,[sp,#8*0]
+	adcs	x24,x11,x14
+	extr	x15,x16,x15,#63
+	ldp	x6,x7,[x1,#8*0]
+	adcs	x25,x12,x15
+	extr	x16,xzr,x16,#63
+	ldp	x8,x9,[x1,#8*2]
+	adc	x26,x13,x16
+	ldp	x10,x11,[x1,#8*4]
+
+	// Reduce by 512 bits per iteration
+	mul	x28,x4,x19		// t[0]*n0
+	ldp	x12,x13,[x1,#8*6]
+	add	x3,x1,x5
+	ldp	x21,x22,[sp,#8*2]
+	stp	x23,x24,[x2,#8*4]
+	ldp	x23,x24,[sp,#8*4]
+	stp	x25,x26,[x2,#8*6]
+	ldp	x25,x26,[sp,#8*6]
+	add	x1,x1,#8*8
+	mov	x30,xzr		// initial top-most carry
+	mov	x2,sp
+	mov	x27,#8
+
+.Lsqr8x_reduction:
+	// (*)	mul	x14,x6,x28	// lo(n[0-7])*lo(t[0]*n0)
+	mul	x15,x7,x28
+	sub	x27,x27,#1
+	mul	x16,x8,x28
+	str	x28,[x2],#8		// put aside t[0]*n0 for tail processing
+	mul	x17,x9,x28
+	// (*)	adds	xzr,x19,x14
+	subs	xzr,x19,#1		// (*)
+	mul	x14,x10,x28
+	adcs	x19,x20,x15
+	mul	x15,x11,x28
+	adcs	x20,x21,x16
+	mul	x16,x12,x28
+	adcs	x21,x22,x17
+	mul	x17,x13,x28
+	adcs	x22,x23,x14
+	umulh	x14,x6,x28		// hi(n[0-7])*lo(t[0]*n0)
+	adcs	x23,x24,x15
+	umulh	x15,x7,x28
+	adcs	x24,x25,x16
+	umulh	x16,x8,x28
+	adcs	x25,x26,x17
+	umulh	x17,x9,x28
+	adc	x26,xzr,xzr
+	adds	x19,x19,x14
+	umulh	x14,x10,x28
+	adcs	x20,x20,x15
+	umulh	x15,x11,x28
+	adcs	x21,x21,x16
+	umulh	x16,x12,x28
+	adcs	x22,x22,x17
+	umulh	x17,x13,x28
+	mul	x28,x4,x19		// next t[0]*n0
+	adcs	x23,x23,x14
+	adcs	x24,x24,x15
+	adcs	x25,x25,x16
+	adc	x26,x26,x17
+	cbnz	x27,.Lsqr8x_reduction
+
+	ldp	x14,x15,[x2,#8*0]
+	ldp	x16,x17,[x2,#8*2]
+	mov	x0,x2
+	sub	x27,x3,x1	// done yet?
+	adds	x19,x19,x14
+	adcs	x20,x20,x15
+	ldp	x14,x15,[x2,#8*4]
+	adcs	x21,x21,x16
+	adcs	x22,x22,x17
+	ldp	x16,x17,[x2,#8*6]
+	adcs	x23,x23,x14
+	adcs	x24,x24,x15
+	adcs	x25,x25,x16
+	adcs	x26,x26,x17
+	//adc	x28,xzr,xzr		// moved below
+	cbz	x27,.Lsqr8x8_post_condition
+
+	ldr	x4,[x2,#-8*8]
+	ldp	x6,x7,[x1,#8*0]
+	ldp	x8,x9,[x1,#8*2]
+	ldp	x10,x11,[x1,#8*4]
+	mov	x27,#-8*8
+	ldp	x12,x13,[x1,#8*6]
+	add	x1,x1,#8*8
+
+.Lsqr8x_tail:
+	mul	x14,x6,x4
+	adc	x28,xzr,xzr		// carry bit, modulo-scheduled
+	mul	x15,x7,x4
+	add	x27,x27,#8
+	mul	x16,x8,x4
+	mul	x17,x9,x4
+	adds	x19,x19,x14
+	mul	x14,x10,x4
+	adcs	x20,x20,x15
+	mul	x15,x11,x4
+	adcs	x21,x21,x16
+	mul	x16,x12,x4
+	adcs	x22,x22,x17
+	mul	x17,x13,x4
+	adcs	x23,x23,x14
+	umulh	x14,x6,x4
+	adcs	x24,x24,x15
+	umulh	x15,x7,x4
+	adcs	x25,x25,x16
+	umulh	x16,x8,x4
+	adcs	x26,x26,x17
+	umulh	x17,x9,x4
+	adc	x28,x28,xzr
+	str	x19,[x2],#8
+	adds	x19,x20,x14
+	umulh	x14,x10,x4
+	adcs	x20,x21,x15
+	umulh	x15,x11,x4
+	adcs	x21,x22,x16
+	umulh	x16,x12,x4
+	adcs	x22,x23,x17
+	umulh	x17,x13,x4
+	ldr	x4,[x0,x27]
+	adcs	x23,x24,x14
+	adcs	x24,x25,x15
+	adcs	x25,x26,x16
+	adcs	x26,x28,x17
+	//adc	x28,xzr,xzr		// moved above
+	cbnz	x27,.Lsqr8x_tail
+					// note that carry flag is guaranteed
+					// to be zero at this point
+	ldp	x6,x7,[x2,#8*0]
+	sub	x27,x3,x1	// done yet?
+	sub	x16,x3,x5	// rewinded np
+	ldp	x8,x9,[x2,#8*2]
+	ldp	x10,x11,[x2,#8*4]
+	ldp	x12,x13,[x2,#8*6]
+	cbz	x27,.Lsqr8x_tail_break
+
+	ldr	x4,[x0,#-8*8]
+	adds	x19,x19,x6
+	adcs	x20,x20,x7
+	ldp	x6,x7,[x1,#8*0]
+	adcs	x21,x21,x8
+	adcs	x22,x22,x9
+	ldp	x8,x9,[x1,#8*2]
+	adcs	x23,x23,x10
+	adcs	x24,x24,x11
+	ldp	x10,x11,[x1,#8*4]
+	adcs	x25,x25,x12
+	mov	x27,#-8*8
+	adcs	x26,x26,x13
+	ldp	x12,x13,[x1,#8*6]
+	add	x1,x1,#8*8
+	//adc	x28,xzr,xzr		// moved above
+	b	.Lsqr8x_tail
+
+.align	4
+.Lsqr8x_tail_break:
+	ldr	x4,[x29,#112]		// pull n0
+	add	x27,x2,#8*8		// end of current t[num] window
+
+	subs	xzr,x30,#1		// "move" top-most carry to carry bit
+	adcs	x14,x19,x6
+	adcs	x15,x20,x7
+	ldp	x19,x20,[x0,#8*0]
+	adcs	x21,x21,x8
+	ldp	x6,x7,[x16,#8*0]	// recall that x16 is &n[0]
+	adcs	x22,x22,x9
+	ldp	x8,x9,[x16,#8*2]
+	adcs	x23,x23,x10
+	adcs	x24,x24,x11
+	ldp	x10,x11,[x16,#8*4]
+	adcs	x25,x25,x12
+	adcs	x26,x26,x13
+	ldp	x12,x13,[x16,#8*6]
+	add	x1,x16,#8*8
+	adc	x30,xzr,xzr	// top-most carry
+	mul	x28,x4,x19
+	stp	x14,x15,[x2,#8*0]
+	stp	x21,x22,[x2,#8*2]
+	ldp	x21,x22,[x0,#8*2]
+	stp	x23,x24,[x2,#8*4]
+	ldp	x23,x24,[x0,#8*4]
+	cmp	x27,x29		// did we hit the bottom?
+	stp	x25,x26,[x2,#8*6]
+	mov	x2,x0			// slide the window
+	ldp	x25,x26,[x0,#8*6]
+	mov	x27,#8
+	b.ne	.Lsqr8x_reduction
+
+	// Final step. We see if result is larger than modulus, and
+	// if it is, subtract the modulus. But comparison implies
+	// subtraction. So we subtract modulus, see if it borrowed,
+	// and conditionally copy original value.
+	ldr	x0,[x29,#96]		// pull rp
+	add	x2,x2,#8*8
+	subs	x14,x19,x6
+	sbcs	x15,x20,x7
+	sub	x27,x5,#8*8
+	mov	x3,x0		// x0 copy
+
+.Lsqr8x_sub:
+	sbcs	x16,x21,x8
+	ldp	x6,x7,[x1,#8*0]
+	sbcs	x17,x22,x9
+	stp	x14,x15,[x0,#8*0]
+	sbcs	x14,x23,x10
+	ldp	x8,x9,[x1,#8*2]
+	sbcs	x15,x24,x11
+	stp	x16,x17,[x0,#8*2]
+	sbcs	x16,x25,x12
+	ldp	x10,x11,[x1,#8*4]
+	sbcs	x17,x26,x13
+	ldp	x12,x13,[x1,#8*6]
+	add	x1,x1,#8*8
+	ldp	x19,x20,[x2,#8*0]
+	sub	x27,x27,#8*8
+	ldp	x21,x22,[x2,#8*2]
+	ldp	x23,x24,[x2,#8*4]
+	ldp	x25,x26,[x2,#8*6]
+	add	x2,x2,#8*8
+	stp	x14,x15,[x0,#8*4]
+	sbcs	x14,x19,x6
+	stp	x16,x17,[x0,#8*6]
+	add	x0,x0,#8*8
+	sbcs	x15,x20,x7
+	cbnz	x27,.Lsqr8x_sub
+
+	sbcs	x16,x21,x8
+	mov	x2,sp
+	add	x1,sp,x5
+	ldp	x6,x7,[x3,#8*0]
+	sbcs	x17,x22,x9
+	stp	x14,x15,[x0,#8*0]
+	sbcs	x14,x23,x10
+	ldp	x8,x9,[x3,#8*2]
+	sbcs	x15,x24,x11
+	stp	x16,x17,[x0,#8*2]
+	sbcs	x16,x25,x12
+	ldp	x19,x20,[x1,#8*0]
+	sbcs	x17,x26,x13
+	ldp	x21,x22,[x1,#8*2]
+	sbcs	xzr,x30,xzr	// did it borrow?
+	ldr	x30,[x29,#8]		// pull return address
+	stp	x14,x15,[x0,#8*4]
+	stp	x16,x17,[x0,#8*6]
+
+	sub	x27,x5,#8*4
+.Lsqr4x_cond_copy:
+	sub	x27,x27,#8*4
+	csel	x14,x19,x6,lo
+	stp	xzr,xzr,[x2,#8*0]
+	csel	x15,x20,x7,lo
+	ldp	x6,x7,[x3,#8*4]
+	ldp	x19,x20,[x1,#8*4]
+	csel	x16,x21,x8,lo
+	stp	xzr,xzr,[x2,#8*2]
+	add	x2,x2,#8*4
+	csel	x17,x22,x9,lo
+	ldp	x8,x9,[x3,#8*6]
+	ldp	x21,x22,[x1,#8*6]
+	add	x1,x1,#8*4
+	stp	x14,x15,[x3,#8*0]
+	stp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+	stp	xzr,xzr,[x1,#8*0]
+	stp	xzr,xzr,[x1,#8*2]
+	cbnz	x27,.Lsqr4x_cond_copy
+
+	csel	x14,x19,x6,lo
+	stp	xzr,xzr,[x2,#8*0]
+	csel	x15,x20,x7,lo
+	stp	xzr,xzr,[x2,#8*2]
+	csel	x16,x21,x8,lo
+	csel	x17,x22,x9,lo
+	stp	x14,x15,[x3,#8*0]
+	stp	x16,x17,[x3,#8*2]
+
+	b	.Lsqr8x_done
+
+.align	4
+.Lsqr8x8_post_condition:
+	adc	x28,xzr,xzr
+	ldr	x30,[x29,#8]		// pull return address
+	// x19-7,x28 hold result, x6-7 hold modulus
+	subs	x6,x19,x6
+	ldr	x1,[x29,#96]		// pull rp
+	sbcs	x7,x20,x7
+	stp	xzr,xzr,[sp,#8*0]
+	sbcs	x8,x21,x8
+	stp	xzr,xzr,[sp,#8*2]
+	sbcs	x9,x22,x9
+	stp	xzr,xzr,[sp,#8*4]
+	sbcs	x10,x23,x10
+	stp	xzr,xzr,[sp,#8*6]
+	sbcs	x11,x24,x11
+	stp	xzr,xzr,[sp,#8*8]
+	sbcs	x12,x25,x12
+	stp	xzr,xzr,[sp,#8*10]
+	sbcs	x13,x26,x13
+	stp	xzr,xzr,[sp,#8*12]
+	sbcs	x28,x28,xzr	// did it borrow?
+	stp	xzr,xzr,[sp,#8*14]
+
+	// x6-7 hold result-modulus
+	csel	x6,x19,x6,lo
+	csel	x7,x20,x7,lo
+	csel	x8,x21,x8,lo
+	csel	x9,x22,x9,lo
+	stp	x6,x7,[x1,#8*0]
+	csel	x10,x23,x10,lo
+	csel	x11,x24,x11,lo
+	stp	x8,x9,[x1,#8*2]
+	csel	x12,x25,x12,lo
+	csel	x13,x26,x13,lo
+	stp	x10,x11,[x1,#8*4]
+	stp	x12,x13,[x1,#8*6]
+
+.Lsqr8x_done:
+	ldp	x19,x20,[x29,#16]
+	mov	sp,x29
+	ldp	x21,x22,[x29,#32]
+	mov	x0,#1
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldr	x29,[sp],#128
+	ret
+.size	__bn_sqr8x_mont,.-__bn_sqr8x_mont
+.type	__bn_mul4x_mont,%function
+.align	5
+__bn_mul4x_mont:
+	stp	x29,x30,[sp,#-128]!
+	add	x29,sp,#0
+	stp	x19,x20,[sp,#16]
+	stp	x21,x22,[sp,#32]
+	stp	x23,x24,[sp,#48]
+	stp	x25,x26,[sp,#64]
+	stp	x27,x28,[sp,#80]
+
+	sub	x26,sp,x5,lsl#3
+	lsl	x5,x5,#3
+	ldr	x4,[x4]		// *n0
+	sub	sp,x26,#8*4		// alloca
+
+	add	x10,x2,x5
+	add	x27,x1,x5
+	stp	x0,x10,[x29,#96]	// offload rp and &b[num]
+
+	ldr	x24,[x2,#8*0]		// b[0]
+	ldp	x6,x7,[x1,#8*0]	// a[0..3]
+	ldp	x8,x9,[x1,#8*2]
+	add	x1,x1,#8*4
+	mov	x19,xzr
+	mov	x20,xzr
+	mov	x21,xzr
+	mov	x22,xzr
+	ldp	x14,x15,[x3,#8*0]	// n[0..3]
+	ldp	x16,x17,[x3,#8*2]
+	adds	x3,x3,#8*4		// clear carry bit
+	mov	x0,xzr
+	mov	x28,#0
+	mov	x26,sp
+
+.Loop_mul4x_1st_reduction:
+	mul	x10,x6,x24		// lo(a[0..3]*b[0])
+	adc	x0,x0,xzr	// modulo-scheduled
+	mul	x11,x7,x24
+	add	x28,x28,#8
+	mul	x12,x8,x24
+	and	x28,x28,#31
+	mul	x13,x9,x24
+	adds	x19,x19,x10
+	umulh	x10,x6,x24		// hi(a[0..3]*b[0])
+	adcs	x20,x20,x11
+	mul	x25,x19,x4		// t[0]*n0
+	adcs	x21,x21,x12
+	umulh	x11,x7,x24
+	adcs	x22,x22,x13
+	umulh	x12,x8,x24
+	adc	x23,xzr,xzr
+	umulh	x13,x9,x24
+	ldr	x24,[x2,x28]		// next b[i] (or b[0])
+	adds	x20,x20,x10
+	// (*)	mul	x10,x14,x25	// lo(n[0..3]*t[0]*n0)
+	str	x25,[x26],#8		// put aside t[0]*n0 for tail processing
+	adcs	x21,x21,x11
+	mul	x11,x15,x25
+	adcs	x22,x22,x12
+	mul	x12,x16,x25
+	adc	x23,x23,x13		// can't overflow
+	mul	x13,x17,x25
+	// (*)	adds	xzr,x19,x10
+	subs	xzr,x19,#1		// (*)
+	umulh	x10,x14,x25		// hi(n[0..3]*t[0]*n0)
+	adcs	x19,x20,x11
+	umulh	x11,x15,x25
+	adcs	x20,x21,x12
+	umulh	x12,x16,x25
+	adcs	x21,x22,x13
+	umulh	x13,x17,x25
+	adcs	x22,x23,x0
+	adc	x0,xzr,xzr
+	adds	x19,x19,x10
+	sub	x10,x27,x1
+	adcs	x20,x20,x11
+	adcs	x21,x21,x12
+	adcs	x22,x22,x13
+	//adc	x0,x0,xzr
+	cbnz	x28,.Loop_mul4x_1st_reduction
+
+	cbz	x10,.Lmul4x4_post_condition
+
+	ldp	x6,x7,[x1,#8*0]	// a[4..7]
+	ldp	x8,x9,[x1,#8*2]
+	add	x1,x1,#8*4
+	ldr	x25,[sp]		// a[0]*n0
+	ldp	x14,x15,[x3,#8*0]	// n[4..7]
+	ldp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+
+.Loop_mul4x_1st_tail:
+	mul	x10,x6,x24		// lo(a[4..7]*b[i])
+	adc	x0,x0,xzr	// modulo-scheduled
+	mul	x11,x7,x24
+	add	x28,x28,#8
+	mul	x12,x8,x24
+	and	x28,x28,#31
+	mul	x13,x9,x24
+	adds	x19,x19,x10
+	umulh	x10,x6,x24		// hi(a[4..7]*b[i])
+	adcs	x20,x20,x11
+	umulh	x11,x7,x24
+	adcs	x21,x21,x12
+	umulh	x12,x8,x24
+	adcs	x22,x22,x13
+	umulh	x13,x9,x24
+	adc	x23,xzr,xzr
+	ldr	x24,[x2,x28]		// next b[i] (or b[0])
+	adds	x20,x20,x10
+	mul	x10,x14,x25		// lo(n[4..7]*a[0]*n0)
+	adcs	x21,x21,x11
+	mul	x11,x15,x25
+	adcs	x22,x22,x12
+	mul	x12,x16,x25
+	adc	x23,x23,x13		// can't overflow
+	mul	x13,x17,x25
+	adds	x19,x19,x10
+	umulh	x10,x14,x25		// hi(n[4..7]*a[0]*n0)
+	adcs	x20,x20,x11
+	umulh	x11,x15,x25
+	adcs	x21,x21,x12
+	umulh	x12,x16,x25
+	adcs	x22,x22,x13
+	adcs	x23,x23,x0
+	umulh	x13,x17,x25
+	adc	x0,xzr,xzr
+	ldr	x25,[sp,x28]		// next t[0]*n0
+	str	x19,[x26],#8		// result!!!
+	adds	x19,x20,x10
+	sub	x10,x27,x1		// done yet?
+	adcs	x20,x21,x11
+	adcs	x21,x22,x12
+	adcs	x22,x23,x13
+	//adc	x0,x0,xzr
+	cbnz	x28,.Loop_mul4x_1st_tail
+
+	sub	x11,x27,x5	// rewinded x1
+	cbz	x10,.Lmul4x_proceed
+
+	ldp	x6,x7,[x1,#8*0]
+	ldp	x8,x9,[x1,#8*2]
+	add	x1,x1,#8*4
+	ldp	x14,x15,[x3,#8*0]
+	ldp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+	b	.Loop_mul4x_1st_tail
+
+.align	5
+.Lmul4x_proceed:
+	ldr	x24,[x2,#8*4]!		// *++b
+	adc	x30,x0,xzr
+	ldp	x6,x7,[x11,#8*0]	// a[0..3]
+	sub	x3,x3,x5		// rewind np
+	ldp	x8,x9,[x11,#8*2]
+	add	x1,x11,#8*4
+
+	stp	x19,x20,[x26,#8*0]	// result!!!
+	ldp	x19,x20,[sp,#8*4]	// t[0..3]
+	stp	x21,x22,[x26,#8*2]	// result!!!
+	ldp	x21,x22,[sp,#8*6]
+
+	ldp	x14,x15,[x3,#8*0]	// n[0..3]
+	mov	x26,sp
+	ldp	x16,x17,[x3,#8*2]
+	adds	x3,x3,#8*4		// clear carry bit
+	mov	x0,xzr
+
+.align	4
+.Loop_mul4x_reduction:
+	mul	x10,x6,x24		// lo(a[0..3]*b[4])
+	adc	x0,x0,xzr	// modulo-scheduled
+	mul	x11,x7,x24
+	add	x28,x28,#8
+	mul	x12,x8,x24
+	and	x28,x28,#31
+	mul	x13,x9,x24
+	adds	x19,x19,x10
+	umulh	x10,x6,x24		// hi(a[0..3]*b[4])
+	adcs	x20,x20,x11
+	mul	x25,x19,x4		// t[0]*n0
+	adcs	x21,x21,x12
+	umulh	x11,x7,x24
+	adcs	x22,x22,x13
+	umulh	x12,x8,x24
+	adc	x23,xzr,xzr
+	umulh	x13,x9,x24
+	ldr	x24,[x2,x28]		// next b[i]
+	adds	x20,x20,x10
+	// (*)	mul	x10,x14,x25
+	str	x25,[x26],#8		// put aside t[0]*n0 for tail processing
+	adcs	x21,x21,x11
+	mul	x11,x15,x25		// lo(n[0..3]*t[0]*n0
+	adcs	x22,x22,x12
+	mul	x12,x16,x25
+	adc	x23,x23,x13		// can't overflow
+	mul	x13,x17,x25
+	// (*)	adds	xzr,x19,x10
+	subs	xzr,x19,#1		// (*)
+	umulh	x10,x14,x25		// hi(n[0..3]*t[0]*n0
+	adcs	x19,x20,x11
+	umulh	x11,x15,x25
+	adcs	x20,x21,x12
+	umulh	x12,x16,x25
+	adcs	x21,x22,x13
+	umulh	x13,x17,x25
+	adcs	x22,x23,x0
+	adc	x0,xzr,xzr
+	adds	x19,x19,x10
+	adcs	x20,x20,x11
+	adcs	x21,x21,x12
+	adcs	x22,x22,x13
+	//adc	x0,x0,xzr
+	cbnz	x28,.Loop_mul4x_reduction
+
+	adc	x0,x0,xzr
+	ldp	x10,x11,[x26,#8*4]	// t[4..7]
+	ldp	x12,x13,[x26,#8*6]
+	ldp	x6,x7,[x1,#8*0]	// a[4..7]
+	ldp	x8,x9,[x1,#8*2]
+	add	x1,x1,#8*4
+	adds	x19,x19,x10
+	adcs	x20,x20,x11
+	adcs	x21,x21,x12
+	adcs	x22,x22,x13
+	//adc	x0,x0,xzr
+
+	ldr	x25,[sp]		// t[0]*n0
+	ldp	x14,x15,[x3,#8*0]	// n[4..7]
+	ldp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+
+.align	4
+.Loop_mul4x_tail:
+	mul	x10,x6,x24		// lo(a[4..7]*b[4])
+	adc	x0,x0,xzr	// modulo-scheduled
+	mul	x11,x7,x24
+	add	x28,x28,#8
+	mul	x12,x8,x24
+	and	x28,x28,#31
+	mul	x13,x9,x24
+	adds	x19,x19,x10
+	umulh	x10,x6,x24		// hi(a[4..7]*b[4])
+	adcs	x20,x20,x11
+	umulh	x11,x7,x24
+	adcs	x21,x21,x12
+	umulh	x12,x8,x24
+	adcs	x22,x22,x13
+	umulh	x13,x9,x24
+	adc	x23,xzr,xzr
+	ldr	x24,[x2,x28]		// next b[i]
+	adds	x20,x20,x10
+	mul	x10,x14,x25		// lo(n[4..7]*t[0]*n0)
+	adcs	x21,x21,x11
+	mul	x11,x15,x25
+	adcs	x22,x22,x12
+	mul	x12,x16,x25
+	adc	x23,x23,x13		// can't overflow
+	mul	x13,x17,x25
+	adds	x19,x19,x10
+	umulh	x10,x14,x25		// hi(n[4..7]*t[0]*n0)
+	adcs	x20,x20,x11
+	umulh	x11,x15,x25
+	adcs	x21,x21,x12
+	umulh	x12,x16,x25
+	adcs	x22,x22,x13
+	umulh	x13,x17,x25
+	adcs	x23,x23,x0
+	ldr	x25,[sp,x28]		// next a[0]*n0
+	adc	x0,xzr,xzr
+	str	x19,[x26],#8		// result!!!
+	adds	x19,x20,x10
+	sub	x10,x27,x1		// done yet?
+	adcs	x20,x21,x11
+	adcs	x21,x22,x12
+	adcs	x22,x23,x13
+	//adc	x0,x0,xzr
+	cbnz	x28,.Loop_mul4x_tail
+
+	sub	x11,x3,x5		// rewinded np?
+	adc	x0,x0,xzr
+	cbz	x10,.Loop_mul4x_break
+
+	ldp	x10,x11,[x26,#8*4]
+	ldp	x12,x13,[x26,#8*6]
+	ldp	x6,x7,[x1,#8*0]
+	ldp	x8,x9,[x1,#8*2]
+	add	x1,x1,#8*4
+	adds	x19,x19,x10
+	adcs	x20,x20,x11
+	adcs	x21,x21,x12
+	adcs	x22,x22,x13
+	//adc	x0,x0,xzr
+	ldp	x14,x15,[x3,#8*0]
+	ldp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+	b	.Loop_mul4x_tail
+
+.align	4
+.Loop_mul4x_break:
+	ldp	x12,x13,[x29,#96]	// pull rp and &b[num]
+	adds	x19,x19,x30
+	add	x2,x2,#8*4		// bp++
+	adcs	x20,x20,xzr
+	sub	x1,x1,x5		// rewind ap
+	adcs	x21,x21,xzr
+	stp	x19,x20,[x26,#8*0]	// result!!!
+	adcs	x22,x22,xzr
+	ldp	x19,x20,[sp,#8*4]	// t[0..3]
+	adc	x30,x0,xzr
+	stp	x21,x22,[x26,#8*2]	// result!!!
+	cmp	x2,x13			// done yet?
+	ldp	x21,x22,[sp,#8*6]
+	ldp	x14,x15,[x11,#8*0]	// n[0..3]
+	ldp	x16,x17,[x11,#8*2]
+	add	x3,x11,#8*4
+	b.eq	.Lmul4x_post
+
+	ldr	x24,[x2]
+	ldp	x6,x7,[x1,#8*0]	// a[0..3]
+	ldp	x8,x9,[x1,#8*2]
+	adds	x1,x1,#8*4		// clear carry bit
+	mov	x0,xzr
+	mov	x26,sp
+	b	.Loop_mul4x_reduction
+
+.align	4
+.Lmul4x_post:
+	// Final step. We see if result is larger than modulus, and
+	// if it is, subtract the modulus. But comparison implies
+	// subtraction. So we subtract modulus, see if it borrowed,
+	// and conditionally copy original value.
+	mov	x0,x12
+	mov	x27,x12		// x0 copy
+	subs	x10,x19,x14
+	add	x26,sp,#8*8
+	sbcs	x11,x20,x15
+	sub	x28,x5,#8*4
+
+.Lmul4x_sub:
+	sbcs	x12,x21,x16
+	ldp	x14,x15,[x3,#8*0]
+	sub	x28,x28,#8*4
+	ldp	x19,x20,[x26,#8*0]
+	sbcs	x13,x22,x17
+	ldp	x16,x17,[x3,#8*2]
+	add	x3,x3,#8*4
+	ldp	x21,x22,[x26,#8*2]
+	add	x26,x26,#8*4
+	stp	x10,x11,[x0,#8*0]
+	sbcs	x10,x19,x14
+	stp	x12,x13,[x0,#8*2]
+	add	x0,x0,#8*4
+	sbcs	x11,x20,x15
+	cbnz	x28,.Lmul4x_sub
+
+	sbcs	x12,x21,x16
+	mov	x26,sp
+	add	x1,sp,#8*4
+	ldp	x6,x7,[x27,#8*0]
+	sbcs	x13,x22,x17
+	stp	x10,x11,[x0,#8*0]
+	ldp	x8,x9,[x27,#8*2]
+	stp	x12,x13,[x0,#8*2]
+	ldp	x19,x20,[x1,#8*0]
+	ldp	x21,x22,[x1,#8*2]
+	sbcs	xzr,x30,xzr	// did it borrow?
+	ldr	x30,[x29,#8]		// pull return address
+
+	sub	x28,x5,#8*4
+.Lmul4x_cond_copy:
+	sub	x28,x28,#8*4
+	csel	x10,x19,x6,lo
+	stp	xzr,xzr,[x26,#8*0]
+	csel	x11,x20,x7,lo
+	ldp	x6,x7,[x27,#8*4]
+	ldp	x19,x20,[x1,#8*4]
+	csel	x12,x21,x8,lo
+	stp	xzr,xzr,[x26,#8*2]
+	add	x26,x26,#8*4
+	csel	x13,x22,x9,lo
+	ldp	x8,x9,[x27,#8*6]
+	ldp	x21,x22,[x1,#8*6]
+	add	x1,x1,#8*4
+	stp	x10,x11,[x27,#8*0]
+	stp	x12,x13,[x27,#8*2]
+	add	x27,x27,#8*4
+	cbnz	x28,.Lmul4x_cond_copy
+
+	csel	x10,x19,x6,lo
+	stp	xzr,xzr,[x26,#8*0]
+	csel	x11,x20,x7,lo
+	stp	xzr,xzr,[x26,#8*2]
+	csel	x12,x21,x8,lo
+	stp	xzr,xzr,[x26,#8*3]
+	csel	x13,x22,x9,lo
+	stp	xzr,xzr,[x26,#8*4]
+	stp	x10,x11,[x27,#8*0]
+	stp	x12,x13,[x27,#8*2]
+
+	b	.Lmul4x_done
+
+.align	4
+.Lmul4x4_post_condition:
+	adc	x0,x0,xzr
+	ldr	x1,[x29,#96]		// pull rp
+	// x19-3,x0 hold result, x14-7 hold modulus
+	subs	x6,x19,x14
+	ldr	x30,[x29,#8]		// pull return address
+	sbcs	x7,x20,x15
+	stp	xzr,xzr,[sp,#8*0]
+	sbcs	x8,x21,x16
+	stp	xzr,xzr,[sp,#8*2]
+	sbcs	x9,x22,x17
+	stp	xzr,xzr,[sp,#8*4]
+	sbcs	xzr,x0,xzr		// did it borrow?
+	stp	xzr,xzr,[sp,#8*6]
+
+	// x6-3 hold result-modulus
+	csel	x6,x19,x6,lo
+	csel	x7,x20,x7,lo
+	csel	x8,x21,x8,lo
+	csel	x9,x22,x9,lo
+	stp	x6,x7,[x1,#8*0]
+	stp	x8,x9,[x1,#8*2]
+
+.Lmul4x_done:
+	ldp	x19,x20,[x29,#16]
+	mov	sp,x29
+	ldp	x21,x22,[x29,#32]
+	mov	x0,#1
+	ldp	x23,x24,[x29,#48]
+	ldp	x25,x26,[x29,#64]
+	ldp	x27,x28,[x29,#80]
+	ldr	x29,[sp],#128
+	ret
+.size	__bn_mul4x_mont,.-__bn_mul4x_mont
+.byte	77,111,110,116,103,111,109,101,114,121,32,77,117,108,116,105,112,108,105,99,97,116,105,111,110,32,102,111,114,32,65,82,77,118,56,44,32,67,82,89,80,84,79,71,65,77,83,32,98,121,32,60,97,112,112,114,111,64,111,112,101,110,115,115,108,46,111,114,103,62,0
+.align	2
+.align	4
+#endif
\ No newline at end of file
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index b8bbecf..e0a9c119 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 10603
+Revision: 10609
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.cc b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
index 259f2e5..d12f2f2 100644
--- a/third_party/mojo/src/mojo/edk/embedder/embedder.cc
+++ b/third_party/mojo/src/mojo/edk/embedder/embedder.cc
@@ -92,22 +92,6 @@
   return static_cast<system::ChannelId>(-new_counter_value);
 }
 
-// Note: Called on the I/O thread.
-void ShutdownIPCSupportHelper() {
-  // Save these before they get nuked by |ShutdownChannelOnIOThread()|.
-  scoped_refptr<base::TaskRunner> delegate_thread_task_runner(
-      internal::g_ipc_support->delegate_thread_task_runner());
-  ProcessDelegate* process_delegate =
-      internal::g_ipc_support->process_delegate();
-
-  ShutdownIPCSupportOnIOThread();
-
-  bool ok = delegate_thread_task_runner->PostTask(
-      FROM_HERE, base::Bind(&ProcessDelegate::OnShutdownComplete,
-                            base::Unretained(process_delegate)));
-  DCHECK(ok);
-}
-
 }  // namespace
 
 void SetMaxMessageSize(size_t bytes) {
@@ -197,7 +181,6 @@
 }
 
 void InitIPCSupport(ProcessType process_type,
-                    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
                     ProcessDelegate* process_delegate,
                     scoped_refptr<base::TaskRunner> io_thread_task_runner,
                     ScopedPlatformHandle platform_handle) {
@@ -207,17 +190,14 @@
   DCHECK(!internal::g_ipc_support);
 
   internal::g_ipc_support = new system::IPCSupport(
-      internal::g_platform_support, process_type,
-      delegate_thread_task_runner, process_delegate,
+      internal::g_platform_support, process_type, process_delegate,
       io_thread_task_runner, platform_handle.Pass());
 
   // TODO(use_chrome_edk) at this point the command line to switch to the new
   // EDK might not be set yet. There's no harm in always intializing the new EDK
   // though.
   g_wrapper_process_delegate = new NewEDKProcessDelegate(process_delegate);
-  mojo::edk::InitIPCSupport(delegate_thread_task_runner,
-                            g_wrapper_process_delegate,
-                            io_thread_task_runner);
+  mojo::edk::InitIPCSupport(g_wrapper_process_delegate, io_thread_task_runner);
 }
 
 void ShutdownIPCSupportOnIOThread() {
@@ -241,8 +221,12 @@
 
   DCHECK(internal::g_ipc_support);
 
-  bool ok = internal::g_ipc_support->io_thread_task_runner()->PostTask(
-      FROM_HERE, base::Bind(&ShutdownIPCSupportHelper));
+  ProcessDelegate* delegate = internal::g_ipc_support->process_delegate();
+  bool ok = internal::g_ipc_support->io_thread_task_runner()->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&ShutdownIPCSupportOnIOThread),
+      base::Bind(&ProcessDelegate::OnShutdownComplete,
+                 base::Unretained(delegate)));
   DCHECK(ok);
 }
 
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder.h b/third_party/mojo/src/mojo/edk/embedder/embedder.h
index 758a905..140b0da6 100644
--- a/third_party/mojo/src/mojo/edk/embedder/embedder.h
+++ b/third_party/mojo/src/mojo/edk/embedder/embedder.h
@@ -77,11 +77,10 @@
 
 // Initializes a process of the given type; to be called after |Init()|.
 //   - |process_delegate| must be a process delegate of the appropriate type
-//     corresponding to |process_type|; its methods will be called on
-//     |delegate_thread_task_runner|.
-//   - |delegate_thread_task_runner|, |process_delegate|, and
-//     |io_thread_task_runner| should live at least until
-//     |ShutdownIPCSupport()|'s callback has been run or
+//     corresponding to |process_type|; its methods will be called on the same
+//     thread as Shutdown.
+//   - |process_delegate|, and |io_thread_task_runner| should live at least
+//     until |ShutdownIPCSupport()|'s callback has been run or
 //     |ShutdownIPCSupportOnIOThread()| has completed.
 //   - For slave processes (i.e., |process_type| is |ProcessType::SLAVE|),
 //     |platform_handle| should be connected to the handle passed to
@@ -89,7 +88,6 @@
 //     |platform_handle| is ignored (and should not be valid).
 MOJO_SYSTEM_IMPL_EXPORT void InitIPCSupport(
     ProcessType process_type,
-    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
     ProcessDelegate* process_delegate,
     scoped_refptr<base::TaskRunner> io_thread_task_runner,
     ScopedPlatformHandle platform_handle);
diff --git a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc
index 5ceff847..071561d 100644
--- a/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/embedder/embedder_unittest.cc
@@ -140,6 +140,7 @@
 
   void TearDown() override { EXPECT_TRUE(test::Shutdown()); }
 
+  base::MessageLoop message_loop_;
   base::TestIOThread test_io_thread_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(EmbedderTest);
@@ -494,6 +495,7 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessMasterSlave) {
+  base::MessageLoop message_loop;
   ScopedPlatformHandle client_platform_handle =
       mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
   EXPECT_TRUE(client_platform_handle.is_valid());
@@ -689,6 +691,7 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
+  base::MessageLoop message_loop;
   ScopedPlatformHandle client_platform_handle =
       mojo::test::MultiprocessTestHelper::client_platform_handle.Pass();
   EXPECT_TRUE(client_platform_handle.is_valid());
diff --git a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
index f3068998..ffe4875 100644
--- a/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/system/connection_manager_unittest.cc
@@ -89,8 +89,7 @@
   embedder::PlatformChannelPair platform_channel_pair;
   ProcessIdentifier slave_process_identifier = master->AddSlave(
       new TestSlaveInfo(slave_name), platform_channel_pair.PassServerHandle());
-  slave->Init(base::MessageLoop::current()->task_runner(),
-              slave_process_delegate, platform_channel_pair.PassClientHandle());
+  slave->Init(slave_process_delegate, platform_channel_pair.PassClientHandle());
   return slave_process_identifier;
 }
 
@@ -202,8 +201,7 @@
 
 TEST_F(ConnectionManagerTest, BasicConnectSlaves) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave1_process_delegate;
   SlaveConnectionManager slave1(platform_support());
@@ -271,8 +269,7 @@
 
 TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
@@ -301,8 +298,7 @@
 
 TEST_F(ConnectionManagerTest, SlaveCancelConnect) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave1_process_delegate;
   SlaveConnectionManager slave1(platform_support());
@@ -339,8 +335,7 @@
 // Tests that pending connections are removed on error.
 TEST_F(ConnectionManagerTest, ErrorRemovePending) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave1_process_delegate;
   SlaveConnectionManager slave1(platform_support());
@@ -382,8 +377,7 @@
 
 TEST_F(ConnectionManagerTest, ConnectSlaveToSelf) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
@@ -417,8 +411,7 @@
 
 TEST_F(ConnectionManagerTest, ConnectSlavesTwice) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave1_process_delegate;
   SlaveConnectionManager slave1(platform_support());
@@ -484,8 +477,7 @@
 
 TEST_F(ConnectionManagerTest, OverlappingSlaveConnects) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave1_process_delegate;
   SlaveConnectionManager slave1(platform_support());
@@ -546,8 +538,7 @@
 
 TEST_F(ConnectionManagerTest, ConnectMasterToSlave) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
@@ -583,8 +574,7 @@
 
 TEST_F(ConnectionManagerTest, ConnectMasterToSelf) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   ConnectionIdentifier connection_id = master.GenerateConnectionIdentifier();
   EXPECT_TRUE(master.AllowConnect(connection_id));
@@ -613,8 +603,7 @@
 
 TEST_F(ConnectionManagerTest, MasterCancelConnect) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
@@ -642,8 +631,7 @@
 
 TEST_F(ConnectionManagerTest, AddSlaveThenImmediateShutdown) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
@@ -657,8 +645,7 @@
 
 TEST_F(ConnectionManagerTest, AddSlaveAndBootstrap) {
   MasterConnectionManager master(platform_support());
-  master.Init(base::MessageLoop::current()->task_runner(),
-              &master_process_delegate());
+  master.Init(&master_process_delegate());
 
   embedder::PlatformChannelPair platform_channel_pair;
   ConnectionIdentifier connection_id = master.GenerateConnectionIdentifier();
@@ -679,8 +666,7 @@
   // We can delay creating/initializing |slave| for quite a while.
   MockSlaveProcessDelegate slave_process_delegate;
   SlaveConnectionManager slave(platform_support());
-  slave.Init(base::MessageLoop::current()->task_runner(),
-             &slave_process_delegate, platform_channel_pair.PassClientHandle());
+  slave.Init(&slave_process_delegate, platform_channel_pair.PassClientHandle());
 
   ProcessIdentifier slave_peer = kInvalidProcessIdentifier;
   embedder::ScopedPlatformHandle h2;
diff --git a/third_party/mojo/src/mojo/edk/system/ipc_support.cc b/third_party/mojo/src/mojo/edk/system/ipc_support.cc
index 49cb94b..ba4f05f 100644
--- a/third_party/mojo/src/mojo/edk/system/ipc_support.cc
+++ b/third_party/mojo/src/mojo/edk/system/ipc_support.cc
@@ -18,15 +18,12 @@
 IPCSupport::IPCSupport(
     embedder::PlatformSupport* platform_support,
     embedder::ProcessType process_type,
-    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
     embedder::ProcessDelegate* process_delegate,
     scoped_refptr<base::TaskRunner> io_thread_task_runner,
     embedder::ScopedPlatformHandle platform_handle)
     : process_type_(process_type),
-      delegate_thread_task_runner_(delegate_thread_task_runner.Pass()),
       process_delegate_(process_delegate),
       io_thread_task_runner_(io_thread_task_runner.Pass()) {
-  DCHECK(delegate_thread_task_runner_);
   DCHECK(io_thread_task_runner_);
 
   switch (process_type_) {
@@ -43,7 +40,6 @@
           new system::MasterConnectionManager(platform_support));
       static_cast<system::MasterConnectionManager*>(connection_manager_.get())
           ->Init(
-              delegate_thread_task_runner_,
               static_cast<embedder::MasterProcessDelegate*>(process_delegate_));
       break;
     case embedder::ProcessType::SLAVE:
@@ -51,7 +47,6 @@
           new system::SlaveConnectionManager(platform_support));
       static_cast<system::SlaveConnectionManager*>(connection_manager_.get())
           ->Init(
-              delegate_thread_task_runner_,
               static_cast<embedder::SlaveProcessDelegate*>(process_delegate_),
               platform_handle.Pass());
       break;
@@ -78,7 +73,6 @@
 
   io_thread_task_runner_ = nullptr;
   process_delegate_ = nullptr;
-  delegate_thread_task_runner_ = nullptr;
   process_type_ = embedder::ProcessType::UNINITIALIZED;
 }
 
diff --git a/third_party/mojo/src/mojo/edk/system/ipc_support.h b/third_party/mojo/src/mojo/edk/system/ipc_support.h
index 02301db..0acac6ef 100644
--- a/third_party/mojo/src/mojo/edk/system/ipc_support.h
+++ b/third_party/mojo/src/mojo/edk/system/ipc_support.h
@@ -64,7 +64,6 @@
   // called.
   IPCSupport(embedder::PlatformSupport* platform_support,
              embedder::ProcessType process_type,
-             scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
              embedder::ProcessDelegate* process_delegate,
              scoped_refptr<base::TaskRunner> io_thread_task_runner,
              embedder::ScopedPlatformHandle platform_handle);
@@ -125,9 +124,6 @@
   embedder::ProcessDelegate* process_delegate() const {
     return process_delegate_;
   }
-  base::TaskRunner* delegate_thread_task_runner() const {
-    return delegate_thread_task_runner_.get();
-  }
   base::TaskRunner* io_thread_task_runner() const {
     return io_thread_task_runner_.get();
   }
@@ -165,7 +161,6 @@
 
   // These are all set on construction and reset by |ShutdownOnIOThread()|.
   embedder::ProcessType process_type_;
-  scoped_refptr<base::TaskRunner> delegate_thread_task_runner_;
   embedder::ProcessDelegate* process_delegate_;
   scoped_refptr<base::TaskRunner> io_thread_task_runner_;
 
diff --git a/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc b/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
index 6796a854..3e4d330 100644
--- a/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
+++ b/third_party/mojo/src/mojo/edk/system/ipc_support_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/test/test_io_thread.h"
 #include "base/test/test_timeouts.h"
@@ -118,14 +119,14 @@
 
 class TestMasterProcessDelegate : public embedder::MasterProcessDelegate {
  public:
-  TestMasterProcessDelegate()
-      : on_slave_disconnect_event_(false, false) {}  // Auto reset.
+  TestMasterProcessDelegate() : slave_disconnected_(false) {}
   ~TestMasterProcessDelegate() override {}
 
   // Warning: There's only one slave disconnect event (which resets
   // automatically).
-  bool TryWaitForOnSlaveDisconnect() {
-    return on_slave_disconnect_event_.TimedWait(TestTimeouts::action_timeout());
+  void TryWaitForOnSlaveDisconnect() {
+    if (!slave_disconnected_)
+      run_loop_.Run();
   }
 
  private:
@@ -133,10 +134,13 @@
   void OnShutdownComplete() override { NOTREACHED(); }
 
   void OnSlaveDisconnect(embedder::SlaveInfo /*slave_info*/) override {
-    on_slave_disconnect_event_.Signal();
+    slave_disconnected_ = true;
+    if (run_loop_.running())
+      run_loop_.Quit();
   }
 
-  base::WaitableEvent on_slave_disconnect_event_;
+  bool slave_disconnected_;
+  base::RunLoop run_loop_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(TestMasterProcessDelegate);
 };
@@ -229,7 +233,6 @@
       : test_io_thread_(test_io_thread),
         slave_ipc_support_(platform_support,
                            embedder::ProcessType::SLAVE,
-                           test_io_thread->task_runner(),
                            &slave_process_delegate_,
                            test_io_thread->task_runner(),
                            platform_handle.Pass()),
@@ -335,7 +338,7 @@
 
     slave_->ShutdownChannelToMaster();
     slave_->ShutdownIPCSupport();
-    EXPECT_TRUE(master_process_delegate_->TryWaitForOnSlaveDisconnect());
+    master_process_delegate_->TryWaitForOnSlaveDisconnect();
     slave_connection_->ShutdownChannelToSlave();
 
     slave_.reset();
@@ -372,7 +375,6 @@
       : test_io_thread_(base::TestIOThread::kAutoStart),
         master_ipc_support_(&platform_support_,
                             embedder::ProcessType::MASTER,
-                            test_io_thread_.task_runner(),
                             &master_process_delegate_,
                             test_io_thread_.task_runner(),
                             embedder::ScopedPlatformHandle()) {}
@@ -402,6 +404,7 @@
   IPCSupport& master_ipc_support() { return master_ipc_support_; }
 
  private:
+  base::MessageLoop message_loop_;
   embedder::SimplePlatformSupport platform_support_;
   base::TestIOThread test_io_thread_;
 
@@ -600,8 +603,8 @@
   // Note: Run process delegate methods on the I/O thread.
   IPCSupport slave_ipc_support(
       &platform_support(), embedder::ProcessType::SLAVE,
-      test_io_thread().task_runner(), &slave_process_delegate,
-      test_io_thread().task_runner(), channel_pair.PassClientHandle());
+      &slave_process_delegate, test_io_thread().task_runner(),
+      channel_pair.PassClientHandle());
 
   embedder::ScopedPlatformHandle slave_second_platform_handle =
       slave_ipc_support.ConnectToMasterInternal(connection_id);
@@ -625,7 +628,7 @@
       FROM_HERE, base::Bind(&IPCSupport::ShutdownOnIOThread,
                             base::Unretained(&slave_ipc_support)));
 
-  EXPECT_TRUE(master_process_delegate().TryWaitForOnSlaveDisconnect());
+  master_process_delegate().TryWaitForOnSlaveDisconnect();
 
   ShutdownMasterIPCSupport();
 }
@@ -671,7 +674,7 @@
   EXPECT_EQ(1u, n);
   EXPECT_EQ('!', c);
 
-  EXPECT_TRUE(master_process_delegate().TryWaitForOnSlaveDisconnect());
+  master_process_delegate().TryWaitForOnSlaveDisconnect();
   EXPECT_TRUE(multiprocess_test_helper.WaitForChildTestShutdown());
 
   ShutdownMasterIPCSupport();
@@ -683,12 +686,12 @@
   ASSERT_TRUE(client_platform_handle.is_valid());
 
   embedder::SimplePlatformSupport platform_support;
+  base::MessageLoop message_loop;
   base::TestIOThread test_io_thread(base::TestIOThread::kAutoStart);
   TestSlaveProcessDelegate slave_process_delegate;
   // Note: Run process delegate methods on the I/O thread.
   IPCSupport ipc_support(&platform_support, embedder::ProcessType::SLAVE,
-                         test_io_thread.task_runner(), &slave_process_delegate,
-                         test_io_thread.task_runner(),
+                         &slave_process_delegate, test_io_thread.task_runner(),
                          client_platform_handle.Pass());
 
   const base::CommandLine& command_line =
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
index 5afae484..833abd36 100644
--- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
+++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.cc
@@ -334,15 +334,13 @@
 }
 
 void MasterConnectionManager::Init(
-    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
     embedder::MasterProcessDelegate* master_process_delegate) {
-  DCHECK(delegate_thread_task_runner);
   DCHECK(master_process_delegate);
   DCHECK(!delegate_thread_task_runner_);
   DCHECK(!master_process_delegate_);
   DCHECK(!private_thread_.message_loop());
 
-  delegate_thread_task_runner_ = delegate_thread_task_runner;
+  delegate_thread_task_runner_ = base::MessageLoop::current()->task_runner();
   master_process_delegate_ = master_process_delegate;
   CHECK(private_thread_.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
diff --git a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
index f78165de..acc89c2e 100644
--- a/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
+++ b/third_party/mojo/src/mojo/edk/system/master_connection_manager.h
@@ -50,8 +50,7 @@
   // |delegate_thread_task_runner| should be the task runner for the "delegate
   // thread", on which |master_process_delegate|'s methods will be called. Both
   // must stay alive at least until after |Shutdown()| has been called.
-  void Init(scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
-            embedder::MasterProcessDelegate* master_process_delegate)
+  void Init(embedder::MasterProcessDelegate* master_process_delegate)
       MOJO_NOT_THREAD_SAFE;
 
   // Adds a slave process and sets up/tracks a connection to that slave (using
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
index d223743..373d9a32 100644
--- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
+++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.cc
@@ -42,17 +42,15 @@
 }
 
 void SlaveConnectionManager::Init(
-    scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
     embedder::SlaveProcessDelegate* slave_process_delegate,
     embedder::ScopedPlatformHandle platform_handle) {
-  DCHECK(delegate_thread_task_runner);
   DCHECK(slave_process_delegate);
   DCHECK(platform_handle.is_valid());
   DCHECK(!delegate_thread_task_runner_);
   DCHECK(!slave_process_delegate_);
   DCHECK(!private_thread_.message_loop());
 
-  delegate_thread_task_runner_ = delegate_thread_task_runner;
+  delegate_thread_task_runner_ = base::MessageLoop::current()->task_runner();
   slave_process_delegate_ = slave_process_delegate;
   CHECK(private_thread_.StartWithOptions(
       base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
index 8764a7f1..366aee1b 100644
--- a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
+++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
@@ -50,8 +50,7 @@
   // |delegate_thread_task_runner| should be the task runner for the "delegate
   // thread", on which |slave_process_delegate|'s methods will be called. Both
   // must stay alive at least until after |Shutdown()| has been called.
-  void Init(scoped_refptr<base::TaskRunner> delegate_thread_task_runner,
-            embedder::SlaveProcessDelegate* slave_process_delegate,
+  void Init(embedder::SlaveProcessDelegate* slave_process_delegate,
             embedder::ScopedPlatformHandle platform_handle);
 
   // |ConnectionManager| methods:
diff --git a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
index f991f68..4965b94 100644
--- a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
+++ b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.cc
@@ -12,8 +12,7 @@
 
 namespace internal {
 
-ScopedIPCSupportHelper::ScopedIPCSupportHelper()
-    : event_(true, false) {  // Manual reset.
+ScopedIPCSupportHelper::ScopedIPCSupportHelper() {
 }
 
 ScopedIPCSupportHelper::~ScopedIPCSupportHelper() {
@@ -22,7 +21,7 @@
     embedder::ShutdownIPCSupportOnIOThread();
   } else {
     embedder::ShutdownIPCSupport();
-    event_.Wait();
+    run_loop_.Run();
   }
 }
 
@@ -33,13 +32,12 @@
     embedder::ScopedPlatformHandle platform_handle) {
   io_thread_task_runner_ = io_thread_task_runner;
   // Note: Run delegate methods on the I/O thread.
-  embedder::InitIPCSupport(process_type, io_thread_task_runner_,
-                           process_delegate, io_thread_task_runner_,
-                           platform_handle.Pass());
+  embedder::InitIPCSupport(process_type, process_delegate,
+                           io_thread_task_runner_, platform_handle.Pass());
 }
 
 void ScopedIPCSupportHelper::OnShutdownCompleteImpl() {
-  event_.Signal();
+  run_loop_.Quit();
 }
 
 }  // namespace internal
diff --git a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h
index 0df54204..2468105 100644
--- a/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h
+++ b/third_party/mojo/src/mojo/edk/test/scoped_ipc_support.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/run_loop.h"
 #include "base/task_runner.h"
 #include "third_party/mojo/src/mojo/edk/embedder/master_process_delegate.h"
 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
@@ -37,7 +37,7 @@
   scoped_refptr<base::TaskRunner> io_thread_task_runner_;
 
   // Set after shut down.
-  base::WaitableEvent event_;
+  base::RunLoop run_loop_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupportHelper);
 };
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ec96f5e5..f71a853 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -55092,6 +55092,7 @@
   <int value="1" label="Mock Bubble"/>
   <int value="10" label="Extension Installed Bubble"/>
   <int value="20" label="Translate Bubble"/>
+  <int value="30" label="Permissions Bubble"/>
 </enum>
 
 <enum name="CacheResult" type="int">
@@ -57180,6 +57181,94 @@
   <int value="156" label="u3p"/>
   <int value="157" label="vbscript"/>
   <int value="158" label="workflow"/>
+  <int value="159" label="001"/>
+  <int value="160" label="7z"/>
+  <int value="161" label="ace"/>
+  <int value="162" label="arc"/>
+  <int value="163" label="arj"/>
+  <int value="164" label="b64"/>
+  <int value="165" label="balz"/>
+  <int value="166" label="bhx"/>
+  <int value="167" label="bz"/>
+  <int value="168" label="bz2"/>
+  <int value="169" label="bzip2"/>
+  <int value="170" label="cab"/>
+  <int value="171" label="cpio"/>
+  <int value="172" label="fat"/>
+  <int value="173" label="gz"/>
+  <int value="174" label="gzip"/>
+  <int value="175" label="hfs"/>
+  <int value="176" label="hqx"/>
+  <int value="177" label="iso"/>
+  <int value="178" label="lha"/>
+  <int value="179" label="lpaq1"/>
+  <int value="180" label="lpaq5"/>
+  <int value="181" label="lpaq8"/>
+  <int value="182" label="lzh"/>
+  <int value="183" label="lzma"/>
+  <int value="184" label="mim"/>
+  <int value="185" label="ntfs"/>
+  <int value="186" label="paq8f"/>
+  <int value="187" label="paq8jd"/>
+  <int value="188" label="paq8l"/>
+  <int value="189" label="paq8o"/>
+  <int value="190" label="pea"/>
+  <int value="191" label="quad"/>
+  <int value="192" label="r00"/>
+  <int value="193" label="r01"/>
+  <int value="194" label="r02"/>
+  <int value="195" label="r03"/>
+  <int value="196" label="r04"/>
+  <int value="197" label="r05"/>
+  <int value="198" label="r06"/>
+  <int value="199" label="r07"/>
+  <int value="200" label="r08"/>
+  <int value="201" label="r09"/>
+  <int value="202" label="r10"/>
+  <int value="203" label="r11"/>
+  <int value="204" label="r12"/>
+  <int value="205" label="r13"/>
+  <int value="206" label="r14"/>
+  <int value="207" label="r15"/>
+  <int value="208" label="r16"/>
+  <int value="209" label="r17"/>
+  <int value="210" label="r18"/>
+  <int value="211" label="r19"/>
+  <int value="212" label="r20"/>
+  <int value="213" label="r21"/>
+  <int value="214" label="r22"/>
+  <int value="215" label="r23"/>
+  <int value="216" label="r24"/>
+  <int value="217" label="r25"/>
+  <int value="218" label="r26"/>
+  <int value="219" label="r27"/>
+  <int value="220" label="r28"/>
+  <int value="221" label="r29"/>
+  <int value="222" label="rar"/>
+  <int value="223" label="squashfs"/>
+  <int value="224" label="swm"/>
+  <int value="225" label="tar"/>
+  <int value="226" label="taz"/>
+  <int value="227" label="tbz"/>
+  <int value="228" label="tbz2"/>
+  <int value="229" label="tgz"/>
+  <int value="230" label="tpz"/>
+  <int value="231" label="txz"/>
+  <int value="232" label="tz"/>
+  <int value="233" label="udf"/>
+  <int value="234" label="uu"/>
+  <int value="235" label="uue"/>
+  <int value="236" label="vhd"/>
+  <int value="237" label="vmdk"/>
+  <int value="238" label="wim"/>
+  <int value="239" label="wrc"/>
+  <int value="240" label="xar"/>
+  <int value="241" label="xxe"/>
+  <int value="242" label="xz"/>
+  <int value="243" label="z"/>
+  <int value="244" label="zip"/>
+  <int value="245" label="zipx"/>
+  <int value="246" label="zpaq"/>
 </enum>
 
 <enum name="DownloadItem.DangerType" type="int">
@@ -72409,6 +72498,76 @@
   <int value="168" label="U3P"/>
   <int value="169" label="VBSCRIPT"/>
   <int value="170" label="WORKFLOW"/>
+  <int value="171" label="001"/>
+  <int value="172" label="ACE"/>
+  <int value="173" label="ARC"/>
+  <int value="174" label="B64"/>
+  <int value="175" label="BALZ"/>
+  <int value="176" label="BHX"/>
+  <int value="177" label="BZ"/>
+  <int value="178" label="FAT"/>
+  <int value="179" label="HFS"/>
+  <int value="180" label="HQX"/>
+  <int value="181" label="ISO"/>
+  <int value="182" label="LPAQ1"/>
+  <int value="183" label="LPAQ5"/>
+  <int value="184" label="LPAQ8"/>
+  <int value="185" label="MIM"/>
+  <int value="186" label="NTFS"/>
+  <int value="187" label="PAQ8F"/>
+  <int value="188" label="PAQ8JD"/>
+  <int value="189" label="PAQ8L"/>
+  <int value="190" label="PAQ8O"/>
+  <int value="191" label="PEA"/>
+  <int value="192" label="PET"/>
+  <int value="193" label="PUP"/>
+  <int value="194" label="QUAD"/>
+  <int value="195" label="R00"/>
+  <int value="196" label="R01"/>
+  <int value="197" label="R02"/>
+  <int value="198" label="R03"/>
+  <int value="199" label="R04"/>
+  <int value="200" label="R05"/>
+  <int value="201" label="R06"/>
+  <int value="202" label="R07"/>
+  <int value="203" label="R08"/>
+  <int value="204" label="R09"/>
+  <int value="205" label="R10"/>
+  <int value="206" label="R11"/>
+  <int value="207" label="R12"/>
+  <int value="208" label="R13"/>
+  <int value="209" label="R14"/>
+  <int value="210" label="R15"/>
+  <int value="211" label="R16"/>
+  <int value="212" label="R17"/>
+  <int value="213" label="R18"/>
+  <int value="214" label="R19"/>
+  <int value="215" label="R20"/>
+  <int value="216" label="R21"/>
+  <int value="217" label="R22"/>
+  <int value="218" label="R23"/>
+  <int value="219" label="R24"/>
+  <int value="220" label="R25"/>
+  <int value="221" label="R26"/>
+  <int value="222" label="R27"/>
+  <int value="223" label="R28"/>
+  <int value="224" label="R29"/>
+  <int value="225" label="SLP"/>
+  <int value="226" label="SQUASHFS"/>
+  <int value="227" label="SWM"/>
+  <int value="228" label="TPZ"/>
+  <int value="229" label="TXZ"/>
+  <int value="230" label="TZ"/>
+  <int value="231" label="UDF"/>
+  <int value="232" label="UU"/>
+  <int value="233" label="UUE"/>
+  <int value="234" label="VHD"/>
+  <int value="235" label="VMDK"/>
+  <int value="236" label="WRC"/>
+  <int value="237" label="XAR"/>
+  <int value="238" label="XXE"/>
+  <int value="239" label="ZIPX"/>
+  <int value="240" label="ZPAQ"/>
 </enum>
 
 <enum name="SBClientDownloadIsSignedBinary" type="int">
diff --git a/ui/base/win/shell.cc b/ui/base/win/shell.cc
index 4a48018..2a5bd29 100644
--- a/ui/base/win/shell.cc
+++ b/ui/base/win/shell.cc
@@ -97,17 +97,15 @@
 }
 
 bool PreventWindowFromPinning(HWND hwnd) {
-  DCHECK(hwnd);
-
   // This functionality is only available on Win7+. It also doesn't make sense
   // to do this for Chrome Metro.
   if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
       base::win::IsMetroProcess())
     return false;
-
   base::win::ScopedComPtr<IPropertyStore> pps;
-  if (FAILED(SHGetPropertyStoreForWindow(hwnd,
-                                         IID_PPV_ARGS(pps.Receive()))))
+  HRESULT result = SHGetPropertyStoreForWindow(
+      hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive()));
+  if (FAILED(result))
     return false;
 
   return base::win::SetBooleanValueForPropertyStore(
@@ -121,34 +119,31 @@
                             const base::string16& relaunch_command,
                             const base::string16& relaunch_display_name,
                             HWND hwnd) {
-  DCHECK(hwnd);
-
   // This functionality is only available on Win7+. It also doesn't make sense
   // to do this for Chrome Metro.
   if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
       base::win::IsMetroProcess())
     return;
-
   base::win::ScopedComPtr<IPropertyStore> pps;
-  if (FAILED(SHGetPropertyStoreForWindow(hwnd,
-                                         IID_PPV_ARGS(pps.Receive()))))
-    return;
-
-  if (!app_id.empty())
-    base::win::SetAppIdForPropertyStore(pps.get(), app_id.c_str());
-  if (!app_icon.empty()) {
-    base::win::SetStringValueForPropertyStore(
-        pps.get(), PKEY_AppUserModel_RelaunchIconResource, app_icon.c_str());
-  }
-  if (!relaunch_command.empty()) {
-    base::win::SetStringValueForPropertyStore(
-        pps.get(), PKEY_AppUserModel_RelaunchCommand,
-        relaunch_command.c_str());
-  }
-  if (!relaunch_display_name.empty()) {
-    base::win::SetStringValueForPropertyStore(
-        pps.get(), PKEY_AppUserModel_RelaunchDisplayNameResource,
-        relaunch_display_name.c_str());
+  HRESULT result = SHGetPropertyStoreForWindow(
+      hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive()));
+  if (S_OK == result) {
+    if (!app_id.empty())
+      base::win::SetAppIdForPropertyStore(pps.get(), app_id.c_str());
+    if (!app_icon.empty()) {
+      base::win::SetStringValueForPropertyStore(
+          pps.get(), PKEY_AppUserModel_RelaunchIconResource, app_icon.c_str());
+    }
+    if (!relaunch_command.empty()) {
+      base::win::SetStringValueForPropertyStore(
+          pps.get(), PKEY_AppUserModel_RelaunchCommand,
+          relaunch_command.c_str());
+    }
+    if (!relaunch_display_name.empty()) {
+      base::win::SetStringValueForPropertyStore(
+          pps.get(), PKEY_AppUserModel_RelaunchDisplayNameResource,
+          relaunch_display_name.c_str());
+    }
   }
 }
 
@@ -178,34 +173,6 @@
                          hwnd);
 }
 
-void ClearWindowPropertyStore(HWND hwnd) {
-  DCHECK(hwnd);
-
-  // This functionality is only available on Win7+. It also doesn't make sense
-  // to do this for Chrome Metro.
-  if (base::win::GetVersion() < base::win::VERSION_WIN7 ||
-      base::win::IsMetroProcess())
-    return;
-
-  base::win::ScopedComPtr<IPropertyStore> pps;
-  if (FAILED(SHGetPropertyStoreForWindow(hwnd,
-                                         IID_PPV_ARGS(pps.Receive()))))
-    return;
-
-  DWORD property_count;
-  if (FAILED(pps->GetCount(&property_count)))
-    return;
-
-  PROPVARIANT empty_property_variant = {};
-  for (DWORD i = 0; i < property_count; i++) {
-    PROPERTYKEY key;
-    if (SUCCEEDED(pps->GetAt(i, &key)))
-      pps->SetValue(key, empty_property_variant);
-  }
-
-  pps->Commit();
-}
-
 bool IsAeroGlassEnabled() {
   // For testing in Win8 (where it is not possible to disable composition) the
   // user can specify this command line switch to mimic the behavior.  In this
diff --git a/ui/base/win/shell.h b/ui/base/win/shell.h
index 458074c6..4031de6 100644
--- a/ui/base/win/shell.h
+++ b/ui/base/win/shell.h
@@ -76,9 +76,6 @@
     const base::string16& display_name,
     HWND hwnd);
 
-// Clears the Window Property Store on an HWND.
-UI_BASE_EXPORT void ClearWindowPropertyStore(HWND hwnd);
-
 // Returns true if composition is available and turned on on the current
 // platform.
 UI_BASE_EXPORT bool IsAeroGlassEnabled();
diff --git a/ui/file_manager/audio_player/assets/100/player_button_next.png b/ui/file_manager/audio_player/assets/100/player_button_next.png
index ed4d407e..f717fe8 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_next.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_next.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_pause.png b/ui/file_manager/audio_player/assets/100/player_button_pause.png
index 5225482..709c215 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_pause.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_pause.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_play.png b/ui/file_manager/audio_player/assets/100/player_button_play.png
index 1174fd6..298eadc 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_play.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_play.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_playlist.png b/ui/file_manager/audio_player/assets/100/player_button_playlist.png
index 9be8e7b..335703b 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_playlist.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_playlist.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_playlist_active.png b/ui/file_manager/audio_player/assets/100/player_button_playlist_active.png
new file mode 100644
index 0000000..39de0b2c
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_button_playlist_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_pressed.png b/ui/file_manager/audio_player/assets/100/player_button_pressed.png
new file mode 100644
index 0000000..162bec4
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_button_pressed.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_previous.png b/ui/file_manager/audio_player/assets/100/player_button_previous.png
index c562d5c..373afd5 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_previous.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_previous.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_repeat.png b/ui/file_manager/audio_player/assets/100/player_button_repeat.png
index d3b87379..86b51ca 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_repeat.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_repeat.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_repeat_active.png b/ui/file_manager/audio_player/assets/100/player_button_repeat_active.png
new file mode 100644
index 0000000..bd1dd46b
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_button_repeat_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_shuffle.png b/ui/file_manager/audio_player/assets/100/player_button_shuffle.png
index 862f66a..0e13f1f 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_shuffle.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_shuffle.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_shuffle_active.png b/ui/file_manager/audio_player/assets/100/player_button_shuffle_active.png
new file mode 100644
index 0000000..f533c53
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_button_shuffle_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_volume.png b/ui/file_manager/audio_player/assets/100/player_button_volume.png
index aa716ff..175ee6d 100644
--- a/ui/file_manager/audio_player/assets/100/player_button_volume.png
+++ b/ui/file_manager/audio_player/assets/100/player_button_volume.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_button_volume_active.png b/ui/file_manager/audio_player/assets/100/player_button_volume_active.png
new file mode 100644
index 0000000..d958503
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_button_volume_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_base_center.png b/ui/file_manager/audio_player/assets/100/player_timeline_base_center.png
new file mode 100644
index 0000000..f5dd2ac
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_base_center.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_base_left.png b/ui/file_manager/audio_player/assets/100/player_timeline_base_left.png
new file mode 100644
index 0000000..35ab5a4c
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_base_left.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_base_right.png b/ui/file_manager/audio_player/assets/100/player_timeline_base_right.png
new file mode 100644
index 0000000..35ab5a4c
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_base_right.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_handler_pressed.png b/ui/file_manager/audio_player/assets/100/player_timeline_handler_pressed.png
new file mode 100644
index 0000000..fa8526a0
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_handler_pressed.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_played_center.png b/ui/file_manager/audio_player/assets/100/player_timeline_played_center.png
new file mode 100644
index 0000000..b7ab78c5
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_played_center.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_played_left.png b/ui/file_manager/audio_player/assets/100/player_timeline_played_left.png
new file mode 100644
index 0000000..9116014a
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_played_left.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/player_timeline_played_right.png b/ui/file_manager/audio_player/assets/100/player_timeline_played_right.png
new file mode 100644
index 0000000..9116014a
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/100/player_timeline_played_right.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/playlist_now_playing.png b/ui/file_manager/audio_player/assets/100/playlist_now_playing.png
deleted file mode 100644
index a4588679..0000000
--- a/ui/file_manager/audio_player/assets/100/playlist_now_playing.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/100/playlist_play.png b/ui/file_manager/audio_player/assets/100/playlist_play.png
deleted file mode 100644
index 416c85a..0000000
--- a/ui/file_manager/audio_player/assets/100/playlist_play.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_next.png b/ui/file_manager/audio_player/assets/200/player_button_next.png
index c65f059..53a9252 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_next.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_next.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_pause.png b/ui/file_manager/audio_player/assets/200/player_button_pause.png
index 883ca6e..2fc73a40 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_pause.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_pause.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_play.png b/ui/file_manager/audio_player/assets/200/player_button_play.png
index d2413af..dd9d393 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_play.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_play.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_playlist.png b/ui/file_manager/audio_player/assets/200/player_button_playlist.png
index bc5576b2..5740a256 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_playlist.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_playlist.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_playlist_active.png b/ui/file_manager/audio_player/assets/200/player_button_playlist_active.png
new file mode 100644
index 0000000..fc9714d
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_button_playlist_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_pressed.png b/ui/file_manager/audio_player/assets/200/player_button_pressed.png
new file mode 100644
index 0000000..c21edae
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_button_pressed.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_previous.png b/ui/file_manager/audio_player/assets/200/player_button_previous.png
index 001c1f7..d09ec3b 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_previous.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_previous.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_repeat.png b/ui/file_manager/audio_player/assets/200/player_button_repeat.png
index c448f2b2..0f0679f 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_repeat.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_repeat.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_repeat_active.png b/ui/file_manager/audio_player/assets/200/player_button_repeat_active.png
new file mode 100644
index 0000000..e73a8e9
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_button_repeat_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_shuffle.png b/ui/file_manager/audio_player/assets/200/player_button_shuffle.png
index 61958e78..cee76639 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_shuffle.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_shuffle.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_shuffle_active.png b/ui/file_manager/audio_player/assets/200/player_button_shuffle_active.png
new file mode 100644
index 0000000..9dbf309
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_button_shuffle_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_volume.png b/ui/file_manager/audio_player/assets/200/player_button_volume.png
index 27edb81..b08c9e5 100644
--- a/ui/file_manager/audio_player/assets/200/player_button_volume.png
+++ b/ui/file_manager/audio_player/assets/200/player_button_volume.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_button_volume_active.png b/ui/file_manager/audio_player/assets/200/player_button_volume_active.png
new file mode 100644
index 0000000..ece8ce98
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_button_volume_active.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_base_center.png b/ui/file_manager/audio_player/assets/200/player_timeline_base_center.png
new file mode 100644
index 0000000..2154855f
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_base_center.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_base_left.png b/ui/file_manager/audio_player/assets/200/player_timeline_base_left.png
new file mode 100644
index 0000000..4a11dd2
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_base_left.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_base_right.png b/ui/file_manager/audio_player/assets/200/player_timeline_base_right.png
new file mode 100644
index 0000000..76279c4
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_base_right.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_handler_pressed.png b/ui/file_manager/audio_player/assets/200/player_timeline_handler_pressed.png
new file mode 100644
index 0000000..c27d9481
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_handler_pressed.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_played_center.png b/ui/file_manager/audio_player/assets/200/player_timeline_played_center.png
new file mode 100644
index 0000000..f113bbd
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_played_center.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_played_left.png b/ui/file_manager/audio_player/assets/200/player_timeline_played_left.png
new file mode 100644
index 0000000..9c63b735
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_played_left.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/player_timeline_played_right.png b/ui/file_manager/audio_player/assets/200/player_timeline_played_right.png
new file mode 100644
index 0000000..abcc959
--- /dev/null
+++ b/ui/file_manager/audio_player/assets/200/player_timeline_played_right.png
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/playlist_now_playing.png b/ui/file_manager/audio_player/assets/200/playlist_now_playing.png
deleted file mode 100644
index 72e87bf..0000000
--- a/ui/file_manager/audio_player/assets/200/playlist_now_playing.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/audio_player/assets/200/playlist_play.png b/ui/file_manager/audio_player/assets/200/playlist_play.png
deleted file mode 100644
index 1ae3fb51..0000000
--- a/ui/file_manager/audio_player/assets/200/playlist_play.png
+++ /dev/null
Binary files differ
diff --git a/ui/file_manager/audio_player/css/audio_player.css b/ui/file_manager/audio_player/css/audio_player.css
index 06c01630..56accad 100644
--- a/ui/file_manager/audio_player/css/audio_player.css
+++ b/ui/file_manager/audio_player/css/audio_player.css
@@ -23,7 +23,6 @@
 }
 
 div.audio-player {
-  border-top: 4px solid white;
   color: #3d3d3d;
   cursor: default;
   flex: 1 1 auto;
diff --git a/ui/file_manager/audio_player/elements/audio_player.css b/ui/file_manager/audio_player/elements/audio_player.css
index bc6d7aa..4f614f2 100644
--- a/ui/file_manager/audio_player/elements/audio_player.css
+++ b/ui/file_manager/audio_player/elements/audio_player.css
@@ -3,8 +3,10 @@
  * found in the LICENSE file. */
 
 control-panel {
+  border-top: 1px solid rgba(0, 0, 0, 0.1);
   bottom: 0;
   left: 0;
+  margin-bottom: 8px;
   position: fixed;
   right: 0;
 }
diff --git a/ui/file_manager/audio_player/elements/audio_player.html b/ui/file_manager/audio_player/elements/audio_player.html
index 1a68e14..133b260 100644
--- a/ui/file_manager/audio_player/elements/audio_player.html
+++ b/ui/file_manager/audio_player/elements/audio_player.html
@@ -15,8 +15,7 @@
         expanded$="[[expanded]]"
         shuffle="[[shuffle]]"
         current-track-index="{{currentTrackIndex}}"
-        on-replay="onReplayCurrentTrack"
-        on-play="onPlayCurrentTrack"></track-list>
+        on-replay="onReplayCurrentTrack"></track-list>
     <control-panel id="audioController"
         playing="{{playing}}"
         time="{{time}}"
@@ -25,8 +24,6 @@
         repeat="{{repeat}}"
         volume="{{volume}}"
         expanded="{{expanded}}"
-        volume-slider-shown="{{volumeSliderShown}}"
-        aria-labels="[[ariaLabels]]"
         on-next-clicked="onControllerNextClicked"
         on-previous-clicked="onControllerPreviousClicked"></control-panel>
     <audio id="audio"
diff --git a/ui/file_manager/audio_player/elements/audio_player.js b/ui/file_manager/audio_player/elements/audio_player.js
index 7fd0866..3d5fc01 100644
--- a/ui/file_manager/audio_player/elements/audio_player.js
+++ b/ui/file_manager/audio_player/elements/audio_player.js
@@ -57,14 +57,6 @@
     },
 
     /**
-     * Whether the volume slider is shown.
-     */
-    volumeSliderShown: {
-      type: Boolean,
-      observer: 'volumeSliderShownChanged'
-    },
-
-    /**
      * Track index of the current track.
      */
     currentTrackIndex: {
@@ -98,20 +90,10 @@
       type: Number,
       value: 0,
       reflectToAttribute: true
-    },
-
-    ariaLabels: {
-      type: Object
     }
   },
 
   /**
-   * The last playing state when user starts dragging the seek bar.
-   * @private {boolean}
-   */
-  wasPlayingOnDragStart_: false,
-
-  /**
    * Handles change event for shuffle mode.
    * @param {boolean} shuffle
    */
@@ -147,23 +129,12 @@
   },
 
   /**
-   * Handles change event for volumeSliderShown state.
-   */
-  volumeSliderShownChanged: function(volumeSliderShown) {
-    if (this.model)
-      this.model.volumeSliderShown = volumeSliderShown;
-  },
-
-  /**
    * Initializes an element. This method is called automatically when the
    * element is ready.
    */
   ready: function() {
     this.addEventListener('keydown', this.onKeyDown_.bind(this));
 
-    this.$.audioController.addEventListener('dragging-changed',
-        this.onDraggingChanged_.bind(this));
-
     this.$.audio.volume = 0;  // Temporary initial volume.
     this.$.audio.addEventListener('ended', this.onAudioEnded.bind(this));
     this.$.audio.addEventListener('error', this.onAudioError.bind(this));
@@ -242,7 +213,6 @@
       this.repeat = newModel.repeat;
       this.volume = newModel.volume;
       this.expanded = newModel.expanded;
-      this.volumeSliderShown = newModel.volumeSliderShown;
     }
   },
 
@@ -305,13 +275,6 @@
   },
 
   /**
-   * Invoked when receivig a request to start playing the current music.
-   */
-  onPlayCurrentTrack: function() {
-    this.$.audio.play();
-  },
-
-  /**
    * Invoked when receiving a request to replay the current music from the track
    * list element.
    */
@@ -433,24 +396,6 @@
   },
 
   /**
-   * Invoked when dragging state of seek bar on control panel is changed.
-   * During the user is dragging it, audio playback is paused temporalily.
-   */
-  onDraggingChanged_: function() {
-    if (this.$.audioController.dragging) {
-      if (this.playing) {
-        this.wasPlayingOnDragStart_ = true;
-        this.$.audio.pause();
-      }
-    } else {
-      if (this.wasPlayingOnDragStart_) {
-        this.$.audio.play();
-        this.wasPlayingOnDragStart_ = false;
-      }
-    }
-  },
-
-  /**
    * Invoked when the 'keydown' event is fired.
    * @param {Event} event The event object.
    */
diff --git a/ui/file_manager/audio_player/elements/compiled_resources.gyp b/ui/file_manager/audio_player/elements/compiled_resources.gyp
new file mode 100644
index 0000000..7e42019
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/compiled_resources.gyp
@@ -0,0 +1,55 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'targets': [
+    {
+      'target_name': 'volume_controller',
+      'variables': {
+        'depends': [],
+        'externs': []
+      },
+      'includes': [
+        '../../compile_js.gypi'
+      ]
+    },
+    {
+      'target_name': 'track_list',
+      'variables': {
+        'depends': [],
+        'externs': [
+          '../../externs/es7_workaround.js'
+        ]
+      },
+      'includes': [
+        '../../compile_js.gypi'
+      ]
+    },
+    {
+      'target_name': 'control_panel',
+      'variables': {
+        'depends': [],
+        'externs': []
+      },
+      'includes': [
+        '../../compile_js.gypi'
+      ]
+    },
+    {
+      'target_name': 'audio_player',
+      'variables': {
+        'depends': [
+          '../js/audio_player_model.js',
+          'track_list.js',
+        ],
+        'externs': [
+          '<(EXTERNS_DIR)/chrome_extensions.js',
+          '../../externs/es7_workaround.js',
+        ]
+      },
+      'includes': [
+        '../../compile_js.gypi'
+      ]
+    }
+  ],
+}
diff --git a/ui/file_manager/audio_player/elements/control_panel.css b/ui/file_manager/audio_player/elements/control_panel.css
index de868107..3dbc878 100644
--- a/ui/file_manager/audio_player/elements/control_panel.css
+++ b/ui/file_manager/audio_player/elements/control_panel.css
@@ -5,23 +5,22 @@
 /* Controls bar. */
 .controls {
   align-items: center;
-  background-color: white;
+  background-color: #fff;
   display: flex;
   flex-direction: column;
-  height: 96px;
+  height: 64px;
   justify-content: center;
   padding: 0;
 }
 
-:host([volume-slider-shown]) .controls {
-  height: 144px;
+.controls .upper-controls {
+  height: 32px;
+  width: 100%
 }
 
-.controls .control-row {
-  box-sizing: border-box;
-  height: 48px;
-  padding: 8px;
-  width: 100%;
+.controls .lower-controls {
+  height: 32px;
+  width: 100%
 }
 
 .audio-controls {
@@ -35,7 +34,7 @@
 /* Customized scrollbar for the playlist. */
 
 .media-button {
-  background-color: transparent;
+  background-color: #fff;
   border: 0;
   height: 32px;
   outline: none;  /* TODO(yoshiki): Show outline only on keyboard focus. */
@@ -44,10 +43,14 @@
   width: 32px;
 }
 
+.media-button:active {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_pressed.png) 1x,
+      url(../assets/200/player_button_pressed.png) 2x);
+}
+
 .media-button > div,
 .media-button.toggle > label > span {
-  background-position: center;
-  background-repeat: no-repeat;
   display: inline-block;
   height: 100%;
   pointer-events: none;
@@ -62,6 +65,13 @@
   top: 0;
 }
 
+.media-button[state='default']:not(.disabled) > .default,
+.media-button[state='ended']:not(.disabled) > .ended,
+.media-button[state='playing']:not(.disabled) > .playing,
+.media-button.disabled > .disabled {
+  opacity: 1;
+}
+
 /* Custom sliders for progress and volume. */
 
 /* Customize the standard input[type='range']. */
@@ -76,40 +86,173 @@
   justify-content: center;
 }
 
-.time-controls > .time-container {
-  color: rgb(51, 51, 51);
-  cursor: default;
-  flex: none;
-  font-size: 12px;
-  padding: 8px;
+.custom-slider.progress {
+  display: flex;
+  flex: 1 1 auto;
+  height: 100%;
   position: relative;
+  z-index: 0;  /* Make a layer which includes the thumb on slider. */
 }
 
-.time-container > .time {
-  position: absolute;
-  right: 8px; /* Should be same as time-container's right padding. */
-  top: 8px; /* Should be same as time-container's top padding. */
+.custom-slider.progress > input[type='range']::-webkit-slider-thumb {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_handler.png) 1x,
+      url(../assets/200/player_timeline_handler.png) 2x);
+  width: 28px;
 }
 
-.time-container > .time.disabled {
+.custom-slider.progress > input[type='range']::-webkit-slider-thumb:hover {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_handler.png) 1x,
+      url(../assets/200/player_timeline_handler.png) 2x);
+}
+
+.custom-slider.progress > input[type='range']::-webkit-slider-thumb:active {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_handler_pressed.png) 1x,
+      url(../assets/200/player_timeline_handler_pressed.png) 2x);
+}
+
+.custom-slider.progress.disabled > input[type='range']::-webkit-slider-thumb {
+  background-image: none;
+}
+
+.time-controls > .time {
+  cursor: default;
+  height: 100%;
+  position: relative;
+  width: 53px;
+}
+
+.time-controls > .time.disabled {
   opacity: 0;
 }
 
-.time-container > .time-spacer {
-  opacity: 0; /* This class is intended to be used as invisible spacer. */
+.custom-slider > input[type='range'] {
+  -webkit-appearance: none !important;  /* Hide the default thumb icon. */
+  background: transparent;  /* Hide the standard slider bar */
+  height: 100%;
+  left: -2px;  /* Required to align the input element with the parent. */
+  outline: none;
+  position: absolute;
+  top: -2px;
+  width: 100%;
 }
 
-paper-slider {
-  --paper-slider-active-color: rgb(66, 133, 244);
-  --paper-slider-knob-color: rgb(64, 138, 241);
-  flex: auto;
+/* Custom thumb icon. */
+.custom-slider > input[type='range']::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  background-position: center center;
+  background-repeat: no-repeat;
+  height: 24px;
+  position: relative;
+  z-index: 2;
+}
+
+/* Custom slider bar (we hide the standard one). */
+.custom-slider > .bar {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_base_center.png) 1x,
+      url(../assets/200/player_timeline_base_center.png) 2x);
+  /* In order to match the horizontal position of the standard slider bar
+     left and right must be equal to 1/2 of the thumb icon width. */
+  bottom: 15px;
+  left: 14px;  /* Exactly 1/2 of the thumb width */
+  pointer-events: none;  /* Mouse events pass through to the standard input. */
+  position: absolute;
+  right: 14px;
+  top: 15px;
+}
+
+.custom-slider > .bar > .filled,
+.custom-slider > .bar > .cap {
+  bottom: 0;
+  position: absolute;
+  top: 0;
+}
+
+/* The filled portion of the slider bar to the left of the thumb. */
+.custom-slider > .bar > .filled {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_played_center.png) 1x,
+      url(../assets/200/player_timeline_played_center.png) 2x);
+  border-left-style: none;
+  border-right-style: none;
+  left: 0;
+  width: 0; /* The element style.width is manipulated from the code. */
+}
+
+/* Rounded caps to the left and right of the slider bar. */
+.custom-slider > .bar > .cap {
+  width: 1px;
+}
+
+/* Left cap is always filled, should be the same color as .filled. */
+.custom-slider > .bar > .cap.left {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_played_left.png) 1x,
+      url(../assets/200/player_timeline_played_left.png) 2x);
+  right: 100%;
+}
+
+/* Right cap is always not filled. */
+.custom-slider > .bar > .cap.right {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_base_right.png) 1x,
+      url(../assets/200/player_timeline_base_right.png) 2x);
+  left: 100%;
 }
 
 .media-button.disabled,
-paper-slider.disabled {
+.custom-slider.disabled,
+.custom-slider.readonly {
   pointer-events: none;
 }
 
+/* Progress seek marker (precise time shown on mouse hover. */
+
+/* Thin vertical line across the slider bar */
+.custom-slider > .bar > .seek-mark {
+  background-color: #202020;
+  bottom: -1px;
+  left: 0;
+  position: absolute;
+  top: -1px;
+  width: 0;
+}
+
+.custom-slider > .bar > .seek-mark.visible {
+  width: 1px;
+}
+
+.custom-slider > .bar > .seek-mark.inverted {
+  background-color: #808080;
+}
+
+/* Text label giving the precise time corresponding to the hover position. */
+.custom-slider > .bar > .seek-mark > .seek-label {
+  align-items: center;
+  background: #202020;
+  border-top-left-radius: 2px;
+  border-top-right-radius: 2px;
+  bottom: 19px;
+  color: white;
+  display: flex;
+  flex-direction: row;
+  font-size: 12px;
+  height: 15px;
+  justify-content: center;
+  left: 0;
+  opacity: 0;
+  overflow: hidden;
+  position: absolute;
+  transition: opacity 150ms ease;
+}
+
+.custom-slider > .bar > .seek-mark.visible > .seek-label {
+  opacity: 1;
+}
+
 /* Media controls in order of appearance. */
 
 .audio-controls {
@@ -128,91 +271,156 @@
 }
 
 .media-button.shuffle-mode {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+
+.media-button.shuffle-mode > label > .icon {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_shuffle.png) 1x,
       url(../assets/200/player_button_shuffle.png) 2x);
   pointer-events: auto;
 }
 
-.media-button.repeat {
-  margin-left: 8px;
-  margin-right: 0;
+.media-button.shuffle-mode > label > input:checked + .icon {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_shuffle_active.png) 1x,
+      url(../assets/200/player_button_shuffle_active.png) 2x);
 }
 
 .media-button.repeat {
+  margin-left: 5px;
+  margin-right: 0;
+}
+
+.media-button.repeat > label > .icon {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_repeat.png) 1x,
       url(../assets/200/player_button_repeat.png) 2x);
   pointer-events: auto;
 }
 
-.media-button.play {
-  margin-left: 4px;
-  margin-right: 4px;
+.media-button.repeat > label > input:checked + .icon {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_repeat_active.png) 1x,
+      url(../assets/200/player_button_repeat_active.png) 2x);
 }
 
 .media-button.play {
+  margin-left: 0;
+  margin-right: 0;
+}
+
+.media-button.play > .ended {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_play.png) 1x,
       url(../assets/200/player_button_play.png) 2x);
 }
 
-:host([playing]) .media-button.play {
+.media-button.play > .playing {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_pause.png) 1x,
       url(../assets/200/player_button_pause.png) 2x);
 }
 
 .media-button.previous {
-  background-image: -webkit-image-set(
-      url(../assets/100/player_button_previous.png) 1x,
-      url(../assets/200/player_button_previous.png) 2x);
-  margin-left: 8px;
+  margin-left: 5px;
   margin-right: 0;
 }
 
+.media-button.previous > .normal {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_previous.png) 1x,
+      url(../assets/200/player_button_previous.png) 2x);
+}
+
 .media-button.next {
+  margin-left: 0;
+  margin-right: 5px;
+}
+
+.media-button.next > .normal {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_next.png) 1x,
       url(../assets/200/player_button_next.png) 2x);
-  margin-left: 0;
-  margin-right: 8px;
 }
 
 .media-button.volume {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+
+.media-button.volume > .normal {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_volume.png) 1x,
       url(../assets/200/player_button_volume.png) 2x);
-  margin-left: 0;
-  margin-right: 8px;
+}
+
+.media-button.volume > label > .icon {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_volume.png) 1x,
+      url(../assets/200/player_button_volume.png) 2x);
   pointer-events: auto;
 }
 
+.media-button.volume > label > input:checked + .icon {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_volume_active.png) 1x,
+      url(../assets/200/player_button_volume_active.png) 2x);
+}
+
 .media-button.playlist {
+  margin-left: 5px;
+  margin-right: 5px;
+}
+
+.media-button.playlist > label > .icon {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_playlist.png) 1x,
       url(../assets/200/player_button_playlist.png) 2x);
   pointer-events: auto;
 }
 
+.media-button.playlist > label > input:checked + .icon {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_playlist_active.png) 1x,
+      url(../assets/200/player_button_playlist_active.png) 2x);
+}
+
+
 /* Invisible div used to compute the width required for the elapsed time. */
+.time-controls > .time > .duration,
 .time-controls > .time > .current {
   align-items: center;
+  color: #3d3d3d;
   display: flex;
   flex-direction: row;
+  font-size: 12px;
   height: 100%;
   justify-content: flex-end;
   position: absolute;
   top: -1px;
 }
 
-.volume-controls {
-  align-items: center;
-  background-color: rgb(235, 235, 235);
-  display: flex;
-  flex-direction: row;
+.time-controls > .time > .duration {
+  left: 0;
 }
 
-.volume-controls paper-slider {
-  width: 100%;
+.time-controls > .time > .current {
+  right: 0;
+}
+
+/* Volume controls: sound button and volume slider */
+
+#volumeContainer {
+  border: 1px solid #ddd;
+  border-radius: 2px;
+  box-shadow: 0 2px 4px #777;
+  height: 110px;
+  position: fixed;
+  width: 32px;
+}
+
+#volumeContainer.default-hidden {
+  visibility: hidden;
 }
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html
index ee8b518..735d115 100644
--- a/ui/file_manager/audio_player/elements/control_panel.html
+++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -5,74 +5,105 @@
   -->
 
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/font-roboto/roboto.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html">
-<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html">
+<link rel="import" href="volume_controller.html">
 
 <dom-module id="control-panel">
   <link rel="import" type="css" href="control_panel.css">
   <template>
     <div class="controls">
-      <div class="control-row volume-controls" hidden="[[!volumeSliderShown]]">
-        <paper-slider id="volumeSlider" value="{{volume::change}}"></paper-slider>
+      <div class="upper-controls time-controls">
+        <div class="time media-control">
+          <div class="current">[[time2string_(time)]]</div>
+        </div>
+        <div class="progress media-control custom-slider">
+          <input id="timeInput" name="timeInput" type="range" touch-action="manipulation"
+                 min="0" max="[[duration]]" value="{{time::input}}">
+          <div class="bar">
+            <div class="filled" style$="[[computeProgressBarStyle_(time, duration)]]"></div>
+            <div class="cap left"></div>
+            <div class="cap right"></div>
+          </div>
+        </div>
+        <div class="time media-control">
+          <div class="duration">[[time2string_(duration)]]</div>
+        </div>
       </div>
-      <div class="control-row audio-controls">
+      <div class="lower-controls audio-controls">
         <!-- Shuffle toggle button in the bottom line. -->
-        <files-icon-button toggles
-            id="shuffle"
-            class="shuffle-mode media-button toggle"
-            active="{{shuffle}}">
-        </files-icon-button>
+        <button class="shuffle-mode media-button toggle" state="default">
+          <label>
+            <input id="shuffleCheckbox"
+                   type="checkbox"
+                   checked="{{shuffle::change}}">
+            <span class="icon"></span>
+          </label>
+        </button>
 
         <!-- Repeat toggle button in the bottom line. -->
-        <files-icon-button toggles
-            id="repeat"
-            class="repeat media-button toggle"
-            active="{{repeat}}">
-        </files-icon-button>
+        <button class="repeat media-button toggle" state="default">
+          <label>
+            <input id="repeatCheckbox"
+                   type="checkbox"
+                   checked="{{repeat::change}}">
+            <span class="icon"></span>
+          </label>
+        </button>
 
         <!-- Prev button in the bottom line. -->
-        <files-icon-button
-            id="previous"
-            class="previous media-button"
-            on-click="previousClick">
-        </files-icon-button>
+        <button class="previous media-button"
+               state="default"
+               on-click="previousClick">
+          <div class="normal default"></div>
+          <div class="disabled"></div>
+        </button>
 
         <!-- Play button in the bottom line. -->
-        <files-icon-button
-            id="play"
-            class="play media-button"
-            on-click="playClick">
-        </files-icon-button>
+        <button class="play media-control media-button"
+                state$="[[computePlayState_(playing)]]"
+                on-click="playClick">
+          <div class="normal playing"></div>
+          <div class="normal ended"></div>
+          <div class="disabled"></div>
+        </button>
 
         <!-- Next button in the bottom line. -->
-        <files-icon-button
-            id="next"
-            class="next media-button"
-            on-click="nextClick">
-        </files-icon-button>
+        <button class="next media-button"
+                state="default"
+                on-click="nextClick">
+          <div class="normal default"></div>
+          <div class="disabled"></div>
+        </button>
+
+        <div id="volumeContainer"
+             class="default-hidden"
+             anchor-point="bottom center">
+          <volume-controller id="volumeSlider" value="{{volume}}"
+                             width="32" height="85" value="50">
+          </volume-controller>
+
+          <polymer-anchor-point id="anchorHelper"></polymer-anchor-point>
+        </div>
 
         <!-- Volume button in the bottom line. -->
-        <files-icon-button toggles
-            id="volume"
-            class="volume media-button toggle"
-            anchor-point="bottom center"
-            active="{{volumeSliderShown}}">
-        </files-icon-button>
+        <button id="volumeButton"
+                class="volume media-button toggle"
+                state="default"
+                anchor-point="bottom center">
+          <label>
+            <input type="checkbox" checked="{{volumeSliderShown::change}}">
+            <span class="icon"></span>
+          </label>
+        </button>
 
         <!-- Playlist button in the bottom line. -->
-        <files-icon-button toggles
-            id="playList"
-            class="playlist media-button toggle"
-            active="{{expanded}}">
-        </files-toggle-ripple>
-      </div>
-      <div class="control-row time-controls">
-        <div class="time-container">
-          <div class="time-spacer">[[computeTimeString_(duration, duration)]]</div>
-          <div class="time">[[computeTimeString_(time, duration)]]</div>
-        </div>
-        <paper-slider id="timeSlider" max="[[duration]]" value="{{time::change}}"></paper-slider>
+        <button id="playlistButton"
+                class="playlist media-button toggle"
+                state="default">
+          <label>
+            <input type="checkbox" checked="{{expanded::change}}">
+            <span class="icon"></span>
+          </label>
+        </button>
       </div>
     </div>
   </template>
diff --git a/ui/file_manager/audio_player/elements/control_panel.js b/ui/file_manager/audio_player/elements/control_panel.js
index d67253c..ca7ea240 100644
--- a/ui/file_manager/audio_player/elements/control_panel.js
+++ b/ui/file_manager/audio_player/elements/control_panel.js
@@ -5,6 +5,26 @@
 (function() {
   'use strict';
 
+  /**
+   * Moves |target| element above |anchor| element, in order to match the
+   * bottom lines.
+   * @param {HTMLElement} target Target element.
+   * @param {HTMLElement} anchor Anchor element.
+   */
+  function matchBottomLine(target, anchor) {
+    var targetRect = target.getBoundingClientRect();
+    var anchorRect = anchor.getBoundingClientRect();
+
+    var pos = {
+      left: anchorRect.left + anchorRect.width / 2 - targetRect.width / 2,
+      bottom: window.innerHeight - anchorRect.bottom,
+    };
+
+    target.style.position = 'fixed';
+    target.style.left = pos.left + 'px';
+    target.style.bottom = pos.bottom + 'px';
+  }
+
   Polymer({
     is: 'control-panel',
 
@@ -16,9 +36,7 @@
       playing: {
         type: Boolean,
         value: false,
-        notify: true,
-        reflectToAttribute: true,
-        observer: 'playingChanged_'
+        notify: true
       },
 
       /**
@@ -79,25 +97,8 @@
       volumeSliderShown: {
         type: Boolean,
         value: false,
-        notify: true,
-        reflectToAttribute: true
-      },
-
-      /**
-       * Whether the knob of time slider is being dragged.
-       */
-      dragging: {
-        type: Boolean,
-        value: false,
+        observer: 'volumeSliderShownChanged',
         notify: true
-      },
-
-      /**
-       * Dictionary which contains aria-labels for each controls.
-       */
-      ariaLabels: {
-        type: Object,
-        observer: 'ariaLabelsChanged_'
       }
     },
 
@@ -106,14 +107,22 @@
      * element is ready.
      */
     ready: function() {
-      this.$.timeSlider.addEventListener('value-change', function() {
-        if (this.dragging)
-          this.dragging = false;
-      }.bind(this));
-      this.$.timeSlider.addEventListener('immediate-value-change', function() {
-        if (!this.dragging)
-          this.dragging = true;
-      }.bind(this));
+      var onFocusoutBound = this.onVolumeControllerFocusout_.bind(this);
+
+      this.$.volumeSlider.addEventListener('focusout', onFocusoutBound);
+      this.$.volumeButton.addEventListener('focusout', onFocusoutBound);
+
+      // Prevent the time slider from being moved by arrow keys.
+      this.$.timeInput.addEventListener('keydown', function(event) {
+        switch (event.keyCode) {
+          case 37:  // Left arrow
+          case 38:  // Up arrow
+          case 39:  // Right arrow
+          case 40:  // Down arrow
+            event.preventDefault();
+            break;
+        };
+      });
     },
 
     /**
@@ -138,6 +147,44 @@
     },
 
     /**
+     * Invoked when the property 'volumeSliderShown' changes.
+     * @param {boolean} shown
+     */
+    volumeSliderShownChanged: function(shown) {
+      this.showVolumeController_(shown);
+    },
+
+    /**
+     * Invoked when the focus goes out of the volume elements.
+     * @param {!UIEvent} event The focusout event.
+     * @private
+     */
+    onVolumeControllerFocusout_: function(event) {
+      if (this.volumeSliderShown) {
+        // If the focus goes out of the volume, hide the volume control.
+        if (!event.relatedTarget ||
+            (!this.$.volumeButton.contains(event.relatedTarget) &&
+             !this.$.volumeSlider.contains(event.relatedTarget))) {
+          this.volumeSliderShown = false;
+        }
+      }
+    },
+
+    /**
+     * Shows/hides the volume controller.
+     * @param {boolean} show True to show the controller, false to hide.
+     * @private
+     */
+    showVolumeController_: function(show) {
+      if (show) {
+        matchBottomLine(this.$.volumeContainer, this.$.volumeButton);
+        this.$.volumeContainer.style.visibility = 'visible';
+      } else {
+        this.$.volumeContainer.style.visibility = 'hidden';
+      }
+    },
+
+    /**
      * Converts the time into human friendly string.
      * @param {number} time Time to be converted.
      * @return {string} String representation of the given time
@@ -147,45 +194,19 @@
     },
 
     /**
-     * Converts the time and duration into human friendly string.
-     * @param {number} time Time to be converted.
-     * @param {number} duration Duration to be converted.
-     * @return {string} String representation of the given time
+     * Computes state for play button based on 'playing' property.
+     * @return {string}
      */
-    computeTimeString_: function(time, duration) {
-      return this.time2string_(time) + ' / ' + this.time2string_(duration);
+    computePlayState_: function(playing) {
+      return playing ? "playing" : "ended";
     },
 
     /**
-     * Invoked when the playing property is changed.
-     * @param {boolean} playing
-     * @private
+     * Computes style for '.filled' element of progress bar.
+     * @return {string}
      */
-    playingChanged_: function(playing) {
-      if (this.ariaLabels) {
-        this.$.play.setAttribute('aria-label',
-            playing ? this.ariaLabels.pause : this.ariaLabels.play);
-      }
-    },
-
-    /**
-     * Invoked when the ariaLabels property is changed.
-     * @param {Object} ariaLabels
-     * @private
-     */
-    ariaLabelsChanged_: function(ariaLabels) {
-      assert(ariaLabels);
-      // TODO(fukino): Use data bindings.
-      this.$.volumeSlider.setAttribute('aria-label', ariaLabels.volumeSlider);
-      this.$.shuffle.setAttribute('aria-label', ariaLabels.shuffle);
-      this.$.repeat.setAttribute('aria-label', ariaLabels.repeat);
-      this.$.previous.setAttribute('aria-label', ariaLabels.previous);
-      this.$.play.setAttribute('aria-label',
-          this.playing ? ariaLabels.pause : ariaLabels.play);
-      this.$.next.setAttribute('aria-label', ariaLabels.next);
-      this.$.volume.setAttribute('aria-label', ariaLabels.volume);
-      this.$.playList.setAttribute('aria-label', ariaLabels.playList);
-      this.$.timeSlider.setAttribute('aria-label', ariaLabels.seekSlider);
+    computeProgressBarStyle_: function(time, duration) {
+      return 'width: ' + (time / duration * 100) + '%;';
     }
   });
 })();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/elements/track_list.css b/ui/file_manager/audio_player/elements/track_list.css
index a2f31a29..1b3f3d5 100644
--- a/ui/file_manager/audio_player/elements/track_list.css
+++ b/ui/file_manager/audio_player/elements/track_list.css
@@ -4,9 +4,9 @@
 
 :host {
   align-items: center;
-  background: rgb(245, 245, 245);
+  background: #f5f5f5;
   bottom: 72px;  /* Room for the controls bar. */
-  color: rgb(51, 51, 51);
+  color: #3d3d3d;
   cursor: default;
   display: flex;
   flex-direction: column;
@@ -26,8 +26,9 @@
   display: flex;
   flex: 0 0 auto;
   flex-direction: row;
-  height: 48px;
+  height: 44px;
   justify-content: flex-start;
+  padding-left: 20px;
   width: 100%;
 }
 
@@ -35,32 +36,9 @@
   display: none;
 }
 
-:host([expanded]) > .track:hover {
-  background-color: rgba(0, 0, 0, 0.08);
-}
-
-/* Track icon. */
-.track .icon {
-  background-position: center;
-  background-repeat: no-repeat;
-  flex: none;
-  height: 32px;
-  margin: 8px;
-  pointer-events: none;
-  width: 32px;
-}
-
-.track:hover .icon {
-  background-image: -webkit-image-set(
-      url(../assets/100/playlist_play.png) 1x,
-      url(../assets/200/playlist_play.png) 2x);
-  pointer-events: auto;
-}
-
-.track[active] .icon {
-  background-image: -webkit-image-set(
-      url(../assets/100/playlist_now_playing.png) 1x,
-      url(../assets/200/playlist_now_playing.png) 2x);
+/* In the expanded mode the selected track is highlighted. */
+.track[active] {
+  background-color: rgb(66, 129, 244);
 }
 
 /* Track data. */
@@ -76,18 +54,22 @@
 
 .track .data .data-title,
 .track .data .data-artist {
+  font-size: 12px;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
 }
 
 .track .data .data-title {
-  color: rgb(51, 51, 51);
-  font-size: 13px;
-  font-weight: 500;
+  color: #343434;
+  font-weight: bold;
 }
 
 .track .data .data-artist {
-  color: rgb(100, 100, 100);
-  font-size: 12px;
+  color: #969696;
+}
+
+.track[active] .data .data-title,
+.track[active] .data .data-artist {
+  color: #fff;
 }
diff --git a/ui/file_manager/audio_player/elements/track_list.html b/ui/file_manager/audio_player/elements/track_list.html
index 23f91bc..b31e45f 100644
--- a/ui/file_manager/audio_player/elements/track_list.html
+++ b/ui/file_manager/audio_player/elements/track_list.html
@@ -5,14 +5,12 @@
   -->
 
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/font-roboto/roboto.html">
 
 <dom-module id="track-list">
   <link rel="import" type="css" href="track_list.css">
   <template>
     <template is="dom-repeat" id="tracks" items="[[tracks]]">
       <div class="track" active$="[[item.active]]" index$="[[index]]" on-click="trackClicked">
-        <div class="icon"></div>
         <div class="data">
           <div class="data-title">[[item.title]]</div>
           <div class="data-artist">[[item.artist]]</div>
diff --git a/ui/file_manager/audio_player/elements/track_list.js b/ui/file_manager/audio_player/elements/track_list.js
index c611ce64..95894ed 100644
--- a/ui/file_manager/audio_player/elements/track_list.js
+++ b/ui/file_manager/audio_player/elements/track_list.js
@@ -166,15 +166,8 @@
     trackClicked: function(event) {
       var index = ~~event.currentTarget.getAttribute('index');
       var track = this.tracks[index];
-      if (track) {
-        if (event.target.classList.contains('icon')) {
-          // If the play icon on the track is clicked, change the current track
-          // and start playing it regardless of current play state.
-          this.selectTrack(track, true /* force to play */);
-        } else {
-          this.selectTrack(track, false /* force to play */);
-        }
-      }
+      if (track)
+        this.selectTrack(track);
     },
 
     /**
@@ -257,10 +250,8 @@
      * Sets the current track.
      * @param {!TrackInfo} track TrackInfo to be set as the current
      *     track.
-     * @param {boolean} forcePlay True if the track should be played regardless
-     *     of the current play state (paused/played).
      */
-    selectTrack: function(track, forcePlay) {
+    selectTrack: function(track) {
       var index = -1;
       for (var i = 0; i < this.tracks.length; i++) {
         if (this.tracks[i].url === track.url) {
@@ -270,13 +261,10 @@
       }
       if (index >= 0) {
         // TODO(yoshiki): Clean up the flow and the code around here.
-        if (this.currentTrackIndex === index) {
+        if (this.currentTrackIndex == index)
           this.replayCurrentTrack();
-        } else {
+        else
           this.currentTrackIndex = index;
-          if (forcePlay)
-            this.fire('play');
-        }
       }
     },
 
diff --git a/ui/file_manager/audio_player/elements/volume_controller.css b/ui/file_manager/audio_player/elements/volume_controller.css
new file mode 100644
index 0000000..4e6880e
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/volume_controller.css
@@ -0,0 +1,52 @@
+/* Copyright 2014 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  background: white;
+  display: block;
+  height: 100px;
+  position: relative;
+  width: 32px;
+}
+
+#background {
+  height: 100%;  /* will be overridden by javascript */
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+
+input[type='range'] {
+  -webkit-appearance: none !important;
+  -webkit-transform: rotate(90deg);
+  background: transparent;
+  outline: none;
+  position: absolute;
+  z-index: 1;
+}
+
+input[type='range']::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  -webkit-transform: rotate(-90deg);
+  background-image: -webkit-image-set(
+      url(../assets/100/player_timeline_handler.png) 1x,
+      url(../assets/200/player_timeline_handler.png) 2x);
+  background-position: 50% 50%;
+  background-repeat: no-repeat no-repeat;
+  height: 24px;
+  position: relative;
+  width: 24px;
+}
+
+#bar {
+  background: #000;
+  bottom: 14px;
+  position: absolute;
+  top: 14px;
+}
+
+#bar .filled {
+  background: #aaa;
+}
diff --git a/ui/file_manager/audio_player/elements/volume_controller.html b/ui/file_manager/audio_player/elements/volume_controller.html
new file mode 100644
index 0000000..1431716
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/volume_controller.html
@@ -0,0 +1,23 @@
+<!--
+  -- Copyright 2015 The Chromium Authors. All rights reserved.
+  -- Use of this source code is governed by a BSD-style license that can be
+  -- found in the LICENSE file.
+  -->
+
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+
+<dom-module id="volume-controller">
+  <link rel="import" type="css" href="volume_controller.css">
+  <template>
+    <div id="background"></div>
+    <input name="rawValueInput" id="rawValueInput" touch-action="manipulation"
+           type="range" min="0" max="100" value="{{rawValue::input}}">
+    <div id="bar">
+      <div class="filled" style$="[[computeFilledStyle_(rawValue)]]"></div>
+      <div class="cap left"></div>
+      <div class="cap right"></div>
+    </div>
+  </template>
+</dom-module>
+
+<script src="volume_controller.js"></script>
diff --git a/ui/file_manager/audio_player/elements/volume_controller.js b/ui/file_manager/audio_player/elements/volume_controller.js
new file mode 100644
index 0000000..ed00080
--- /dev/null
+++ b/ui/file_manager/audio_player/elements/volume_controller.js
@@ -0,0 +1,124 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+(function() {
+  'use strict';
+
+  Polymer({
+    is: 'volume-controller',
+
+    properties: {
+      /**
+       * Width of the element in pixels. Must be specified before ready() is
+       * called. Dynamic change is not supported.
+       * @type {number}
+       */
+      width: {
+        type: Number,
+        value: 32
+      },
+
+      /**
+       * Height of the element in pixels. Must be specified before ready() is
+       * called. Dynamic change is not supported.
+       * @type {number}
+       */
+      height: {
+        type: Number,
+        value: 100
+      },
+
+      /**
+       * Volume. 0 is silent, and 100 is maximum.
+       * @type {number}
+       */
+      value: {
+        type: Number,
+        value: 50,
+        observer: 'valueChanged',
+        notify: true
+      },
+
+      /**
+       * Volume. 100 is silent, and 0 is maximum.
+       * @type {number}
+       */
+      rawValue: {
+        type: Number,
+        value: 0,
+        observer: 'rawValueChanged',
+        notify: true
+      }
+    },
+
+    /**
+     * Initializes an element. This method is called automatically when the
+     * element is ready.
+     */
+    ready: function() {
+      this.style.width = this.width + 'px';
+      this.style.height = this.height + 'px';
+
+      this.rawValueInput = this.$.rawValueInput;
+      this.bar = this.$.bar;
+
+      this.rawValueInput.style.width = this.height + 'px';
+      this.rawValueInput.style.height = this.width + 'px';
+      this.rawValueInput.style.webkitTransformOrigin =
+          (this.width / 2) + 'px ' +
+          (this.width / 2 - 2) + 'px';
+
+      var barLeft = (this.width / 2 - 1);
+      this.bar.style.left = barLeft + 'px';
+      this.bar.style.right = barLeft + 'px';
+
+      this.addEventListener('keydown', this.onKeyDown_.bind(this));
+    },
+
+    /**
+     * Invoked when the 'volume' value is changed.
+     * @param {number} newValue New value.
+     * @param {number} oldValue Old value.
+     */
+    valueChanged: function(newValue, oldValue) {
+      if (oldValue != newValue)
+        this.rawValue = 100 - newValue;
+    },
+
+    /**
+     * Invoked when the 'rawValue' property is changed.
+     * @param {number} newValue New value.
+     * @param {number} oldValue Old value.
+     */
+    rawValueChanged: function(newValue, oldValue) {
+      if (oldValue !== newValue)
+        this.value = 100 - newValue;
+    },
+
+    /**
+     * Invoked when the 'keydown' event is fired.
+     * @param {Event} event The event object.
+     */
+    onKeyDown_: function(event) {
+      switch (event.keyIdentifier) {
+        // Prevents the default behavior. These key should be handled in
+        // <audio-player> element.
+        case 'Up':
+        case 'Down':
+        case 'PageUp':
+        case 'PageDown':
+          event.preventDefault();
+          break;
+      }
+    },
+
+    /**
+     * Computes style for '.filled' element based on raw value.
+     * @return {string}
+     */
+    computeFilledStyle_: function(rawValue) {
+      return 'height: ' + rawValue + '%;';
+    }
+  });
+})();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/icons/audio-player-128.png b/ui/file_manager/audio_player/icons/audio-player-128.png
index 5954c60..15b7772 100644
--- a/ui/file_manager/audio_player/icons/audio-player-128.png
+++ b/ui/file_manager/audio_player/icons/audio-player-128.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-256.png b/ui/file_manager/audio_player/icons/audio-player-256.png
index 2dd439c..e1202a8 100644
--- a/ui/file_manager/audio_player/icons/audio-player-256.png
+++ b/ui/file_manager/audio_player/icons/audio-player-256.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-32.png b/ui/file_manager/audio_player/icons/audio-player-32.png
index e32a22a7..b22e5f62 100644
--- a/ui/file_manager/audio_player/icons/audio-player-32.png
+++ b/ui/file_manager/audio_player/icons/audio-player-32.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-48.png b/ui/file_manager/audio_player/icons/audio-player-48.png
index d7f41c69..305a3a97a 100644
--- a/ui/file_manager/audio_player/icons/audio-player-48.png
+++ b/ui/file_manager/audio_player/icons/audio-player-48.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-64.png b/ui/file_manager/audio_player/icons/audio-player-64.png
index 5ace5c8..724ee20 100644
--- a/ui/file_manager/audio_player/icons/audio-player-64.png
+++ b/ui/file_manager/audio_player/icons/audio-player-64.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-96.png b/ui/file_manager/audio_player/icons/audio-player-96.png
index 8b1f007..d866c35 100644
--- a/ui/file_manager/audio_player/icons/audio-player-96.png
+++ b/ui/file_manager/audio_player/icons/audio-player-96.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-favicon-16.png b/ui/file_manager/audio_player/icons/audio-player-favicon-16.png
index ace23a2..90168b8 100644
--- a/ui/file_manager/audio_player/icons/audio-player-favicon-16.png
+++ b/ui/file_manager/audio_player/icons/audio-player-favicon-16.png
Binary files differ
diff --git a/ui/file_manager/audio_player/icons/audio-player-favicon-32.png b/ui/file_manager/audio_player/icons/audio-player-favicon-32.png
index 7ff6fd3..50c7c87 100644
--- a/ui/file_manager/audio_player/icons/audio-player-favicon-32.png
+++ b/ui/file_manager/audio_player/icons/audio-player-favicon-32.png
Binary files differ
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index fb09c33..216bb44 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -24,14 +24,10 @@
   Object.observe(this.model_, function(changes) {
     for (var i = 0; i < changes.length; i++) {
       var change = changes[i];
-      if (change.name === 'expanded' &&
-          (change.type === 'add' || change.type === 'update')) {
+      if (change.name == 'expanded' &&
+          (change.type == 'add' || change.type == 'update')) {
         this.onModelExpandedChanged(change.oldValue, change.object.expanded);
         break;
-      } else if (change.name === 'volumeSliderShown' &&
-          (change.type === 'add' || change.type === 'update')) {
-        this.onModelVolumeSliderShownChanged();
-        break;
       }
     }
   }.bind(this));
@@ -68,19 +64,6 @@
       this.offlineString_ = strings['AUDIO_OFFLINE'];
       AudioPlayer.TrackInfo.DEFAULT_ARTIST =
           strings['AUDIO_PLAYER_DEFAULT_ARTIST'];
-      // Pass translated labels to the AudioPlayerElement.
-      this.player_.ariaLabels = {
-        volumeSlider: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'],
-        shuffle: strings['AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL'],
-        repeat: strings['AUDIO_PLAYER_REPEAT_BUTTON_LABEL'],
-        previous: strings['MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL'],
-        play: strings['MEDIA_PLAYER_PLAY_BUTTON_LABEL'],
-        pause: strings['MEDIA_PLAYER_PAUSE_BUTTON_LABEL'],
-        next: strings['MEDIA_PLAYER_NEXT_BUTTON_LABEL'],
-        volume: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'],
-        playList: strings['AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL'],
-        seekSlider: strings['MEDIA_PLAYER_SEEK_SLIDER_LABEL']
-      };
     }.bind(this));
 
     this.volumeManager_.addEventListener('externally-unmounted',
@@ -301,11 +284,11 @@
  */
 AudioPlayer.prototype.onResize_ = function(event) {
   if (!this.isExpanded_ &&
-      window.innerHeight >= this.getExpandedModeMinHeight_()) {
+      window.innerHeight >= AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
     this.isExpanded_ = true;
     this.player_.expanded = true;
   } else if (this.isExpanded_ &&
-      window.innerHeight < this.getExpandedModeMinHeight_()) {
+             window.innerHeight < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
     this.isExpanded_ = false;
     this.player_.expanded = false;
   }
@@ -342,35 +325,21 @@
  * @type {number}
  * @const
  */
-AudioPlayer.HEADER_HEIGHT = 36;  // 32px + border 4px
+AudioPlayer.HEADER_HEIGHT = 33;  // 32px + border 1px
 
 /**
  * Track height in pixels.
  * @type {number}
  * @const
  */
-AudioPlayer.TRACK_HEIGHT = 48;
+AudioPlayer.TRACK_HEIGHT = 44;
 
 /**
- * Volume slider's height in pixels.
+ * Controls bar height in pixels.
  * @type {number}
  * @const
  */
-AudioPlayer.VOLUME_SLIDER_HEIGHT = 48;
-
-/**
- * Height of the control which has buttons such as play, next, shffule, etc...
- * @type {number}
- * @const
- */
-AudioPlayer.BUTTONS_CONTROL_HEIGHT = 48;
-
-/**
- * Height of the control which has progress slider, time, and duration.
- * @type {number}
- * @const
- */
-AudioPlayer.TIME_CONTROL_HEIGHT = 48;
+AudioPlayer.CONTROLS_HEIGHT = 73;  // 72px + border 1px
 
 /**
  * Default number of items in the expanded mode.
@@ -380,6 +349,14 @@
 AudioPlayer.DEFAULT_EXPANDED_ITEMS = 5;
 
 /**
+ * Minimum size of the window in the expanded mode in pixels.
+ * @type {number}
+ * @const
+ */
+AudioPlayer.EXPANDED_MODE_MIN_HEIGHT = AudioPlayer.CONTROLS_HEIGHT +
+                                       AudioPlayer.TRACK_HEIGHT * 2;
+
+/**
  * Invoked when the 'expanded' property in the model is changed.
  * @param {boolean} oldValue Old value.
  * @param {boolean} newValue New value.
@@ -403,13 +380,6 @@
 };
 
 /**
- * Invoked when the 'volumeSliderShown' property in the model is changed.
- */
-AudioPlayer.prototype.onModelVolumeSliderShownChanged = function() {
-  this.syncHeight_();
-};
-
-/**
  * @private
  */
 AudioPlayer.prototype.syncHeight_ = function() {
@@ -418,49 +388,24 @@
   if (this.player_.expanded) {
     // Expanded.
     if (!this.lastExpandedHeight_ ||
-        this.lastExpandedHeight_ < this.getExpandedModeMinHeight_()) {
+        this.lastExpandedHeight_ < AudioPlayer.EXPANDED_MODE_MIN_HEIGHT) {
       var expandedListHeight =
           Math.min(this.entries_.length, AudioPlayer.DEFAULT_EXPANDED_ITEMS) *
               AudioPlayer.TRACK_HEIGHT;
-      targetHeight = this.getControlsHeight_() + expandedListHeight;
+      targetHeight = AudioPlayer.CONTROLS_HEIGHT + expandedListHeight;
       this.lastExpandedHeight_ = targetHeight;
     } else {
       targetHeight = this.lastExpandedHeight_;
     }
   } else {
     // Not expanded.
-    targetHeight = this.getControlsHeight_() + AudioPlayer.TRACK_HEIGHT;
+    targetHeight = AudioPlayer.CONTROLS_HEIGHT + AudioPlayer.TRACK_HEIGHT;
   }
 
   window.resizeTo(window.innerWidth, targetHeight + AudioPlayer.HEADER_HEIGHT);
 };
 
 /**
- * Calculates the height of control panel.
- * @return {number} Current height of control panel in pixels.
- * @private
- */
-AudioPlayer.prototype.getControlsHeight_ = function() {
-  var height = AudioPlayer.BUTTONS_CONTROL_HEIGHT +
-               AudioPlayer.TIME_CONTROL_HEIGHT;
-  if (this.player_.volumeSliderShown)
-    height += AudioPlayer.VOLUME_SLIDER_HEIGHT;
-
-  return height;
-};
-
-/**
- * Calculates the minium height of the app to show the playlist in expanded
- * mode.
- * @return {number} The minimum height of audio app window in which we can show
- *     the playlist in expanded mode.
- * @private
- */
-AudioPlayer.prototype.getExpandedModeMinHeight_ = function() {
-  return this.getControlsHeight_() + AudioPlayer.TRACK_HEIGHT * 2;
-};
-
-/**
  * Create a TrackInfo object encapsulating the information about one track.
  *
  * @param {FileEntry} entry FileEntry to be retrieved the track info from.
diff --git a/ui/file_manager/audio_player/js/audio_player_model.js b/ui/file_manager/audio_player/js/audio_player_model.js
index 42c7e844..7bbef274 100644
--- a/ui/file_manager/audio_player/js/audio_player_model.js
+++ b/ui/file_manager/audio_player/js/audio_player_model.js
@@ -26,7 +26,6 @@
       repeat: false,
       volume: 100,
       expanded: false,
-      volumeSliderShown: false
     };
 
   /**
diff --git a/ui/file_manager/audio_player/js/background.js b/ui/file_manager/audio_player/js/background.js
index 587c0816..600c15b9 100644
--- a/ui/file_manager/audio_player/js/background.js
+++ b/ui/file_manager/audio_player/js/background.js
@@ -21,13 +21,10 @@
 var audioPlayerCreateOptions = {
   id: 'audio-player',
   type: 'panel',
-  minHeight: 4 + 48 + 96,  // 4px: border-top, 48px: track, 96px: controller
-  minWidth: 280,
-  height: 4 + 48 + 96,  // collapsed
-  width: 280,
-  frame: {
-    color: '#fafafa'
-  }
+  minHeight: 44 + 73,  // 44px: track, 73px: controller
+  minWidth: 292,
+  height: 44 + 73,  // collapsed
+  width: 292
 };
 
 /**
diff --git a/ui/file_manager/audio_player/js/compiled_resources.gyp b/ui/file_manager/audio_player/js/compiled_resources.gyp
index 4c4486d..232d181 100644
--- a/ui/file_manager/audio_player/js/compiled_resources.gyp
+++ b/ui/file_manager/audio_player/js/compiled_resources.gyp
@@ -77,9 +77,6 @@
           '../../file_manager/foreground/js/metadata/thumbnail_model.js',
           '../../file_manager/background/js/volume_manager.js',
           '../../file_manager/foreground/js/volume_manager_wrapper.js',
-          '../elements/control_panel.js',
-          '../elements/track_list.js',
-          '../elements/audio_player.js',
           'audio_player_model.js',
         ],
         'externs': [
@@ -92,6 +89,7 @@
           '../../externs/chrome_test.js',
           '../../externs/es6_workaround.js',
           '../../externs/es7_workaround.js',
+          '../../externs/files_elements.js',
           '../../externs/platform.js',
         ],
       },
diff --git a/ui/file_manager/audio_player/manifest.json b/ui/file_manager/audio_player/manifest.json
index 64bb318..c8db5587 100644
--- a/ui/file_manager/audio_player/manifest.json
+++ b/ui/file_manager/audio_player/manifest.json
@@ -71,6 +71,6 @@
         "js/background.js"
       ]
     },
-    "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources chrome-extension://boadgeojelhgndaghljhdicfkmllpafd chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj chrome-extension://enhhojjnijigcajfphajepfemndkmdlo; style-src 'self' blob: filesystem: chrome://resources 'unsafe-inline'; img-src 'self' blob: filesystem: chrome://theme chrome://resources data: https://www.googledrive.com; media-src 'self' blob: filesystem:; object-src 'self' blob: filesystem:; font-src chrome://resources;"
+    "content_security_policy": "default-src 'none'; script-src 'self' blob: filesystem: chrome://resources chrome-extension://boadgeojelhgndaghljhdicfkmllpafd chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj chrome-extension://enhhojjnijigcajfphajepfemndkmdlo; style-src 'self' blob: filesystem: chrome://resources 'unsafe-inline'; img-src 'self' blob: filesystem: chrome://theme chrome://resources data: https://www.googledrive.com; media-src 'self' blob: filesystem:; object-src 'self' blob: filesystem:"
   }
 }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_toast.js b/ui/file_manager/file_manager/foreground/elements/files_toast.js
index 32e047f..2a539a6e 100644
--- a/ui/file_manager/file_manager/foreground/elements/files_toast.js
+++ b/ui/file_manager/file_manager/foreground/elements/files_toast.js
@@ -31,7 +31,7 @@
    */
   created: function() {
     /**
-     * @private {?{text: string, callback: function()}}
+     * @private {{text: string, callback: function()}}
      */
     this.action_ = null;
 
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index 44f50c2..f1cd789 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -69,7 +69,6 @@
           '../../background/js/background.js',
           '../../../image_loader/image_loader_client.js',
           '../elements/files_ripple.js',
-          '../elements/files_toggle_ripple.js',
           '../elements/files_tooltip.js',
           './metrics_start.js',
           './ui/combobutton.js',
@@ -161,6 +160,7 @@
           '../../../externs/connection.js',
           '../../../externs/css_rule.js',
           '../../../externs/es6_workaround.js',
+          '../../../externs/files_elements.js',
           '../../../externs/html_menu_item_element.js',
           '../../../externs/launcher_search_provider.js',
           '../../../externs/webview_tag.js',
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index fcfb9d99..c38c41c 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -185,26 +185,32 @@
  * @private
  */
 TaskController.prototype.changeDefaultTask_ = function(selection, task) {
-  chrome.fileManagerPrivate.setDefaultTask(
-      task.taskId,
-      selection.entries,
-      assert(selection.mimeTypes),
-      util.checkAPIError);
-  this.metadataUpdateController_.refreshCurrentDirectoryMetadata();
+  var entries = selection.entries;
 
-  // Update task menu button unless the task button was updated other selection.
-  if (this.selectionHandler_.selection === selection) {
-    this.tasks_ = null;
-    this.getFileTasks()
-        .then(function(tasks) {
-          tasks.display(this.ui_.taskMenuButton);
-        }.bind(this))
-        .catch(function(error) {
-          if (error)
-            console.error(error.stack || error);
-        });
-  }
-  this.selectionHandler_.onFileSelectionChanged();
+  Promise.all(entries.map((entry) => this.getMimeType_(entry))).then(function(
+      mimeTypes) {
+    chrome.fileManagerPrivate.setDefaultTask(
+        task.taskId,
+        entries,
+        mimeTypes,
+        util.checkAPIError);
+    this.metadataUpdateController_.refreshCurrentDirectoryMetadata();
+
+    // Update task menu button unless the task button was updated other
+    // selection.
+    if (this.selectionHandler_.selection === selection) {
+      this.tasks_ = null;
+      this.getFileTasks()
+          .then(function(tasks) {
+            tasks.display(this.ui_.taskMenuButton);
+          }.bind(this))
+          .catch(function(error) {
+            if (error)
+              console.error(error.stack || error);
+          });
+    }
+    this.selectionHandler_.onFileSelectionChanged();
+  }.bind(this));
 };
 
 /**
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index 8826ebc..48bd372 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -170,6 +170,9 @@
       <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_CSS" file="audio_player/elements/track_list.css" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_HTML" file="audio_player/elements/track_list.html" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ELEMENTS_TRACK_LIST_JS" file="audio_player/elements/track_list.js" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_CSS" file="audio_player/elements/volume_controller.css" flattenhtml="true" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_HTML" file="audio_player/elements/volume_controller.html" type="BINDATA" />
+      <include name="IDR_AUDIO_PLAYER_ELEMENTS_VOLUME_CONTROLLER_JS" file="audio_player/elements/volume_controller.js" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_METADATA_WORKER_JS" file="audio_player/js/metadata_worker.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_ERROR_UTIL_JS" file="audio_player/js/error_util.js" flattenhtml="false" type="BINDATA" />
       <include name="IDR_AUDIO_PLAYER_TEST_UTIL_JS" file="audio_player/js/test_util.js" flattenhtml="false" type="BINDATA" />
diff --git a/ui/file_manager/integration_tests/file_manager/open_audio_files.js b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
index f75cbf8..3a3c4c69 100644
--- a/ui/file_manager/integration_tests/file_manager/open_audio_files.js
+++ b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
@@ -268,7 +268,7 @@
       audioPlayerApp.callRemoteTestUtil(
           'fakeMouseClick',
           audioAppId,
-          ['audio-player /deep/ files-icon-button.repeat'],
+          ['audio-player /deep/ button.repeat input'],
           this.next);
     },
     function(result) {
@@ -404,7 +404,7 @@
       audioPlayerApp.callRemoteTestUtil(
           'fakeMouseClick',
           audioAppId,
-          ['audio-player /deep/ files-icon-button.repeat'],
+          ['audio-player /deep/ button.repeat input'],
           this.next);
     },
     function(result) {