diff --git a/DEPS b/DEPS
index 6a93a209..837694af 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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': '403eccb02dc501ac8f04a1e856e5c2094afb6b57',
+  'v8_revision': '228237cf81b29d4f3b67aa8bd8172442726b4d1f',
   # 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.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'c62980ec7539fa5ae2065ba5f287aada3a814173',
+  'pdfium_revision': '02759102cf998c9e937b3b65b64ed6b4c3b104bc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '852f85163d54de6b721860a94ae23c608a3efa64',
+  'catapult_revision': 'da3aa694af9729a870e1837d7cbeebb38bd64063',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -224,7 +224,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' + '@' + '61e42daeed24f321ca66a0a566c53e39485dcd39', # commit position 15323
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '42ad2d474da82fbcb90a432d463a765dee22fad1', # commit position 15358
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/ash/wm/toplevel_window_event_handler.cc b/ash/wm/toplevel_window_event_handler.cc
index 5c4d9578..067e238 100644
--- a/ash/wm/toplevel_window_event_handler.cc
+++ b/ash/wm/toplevel_window_event_handler.cc
@@ -5,7 +5,9 @@
 #include "ash/wm/toplevel_window_event_handler.h"
 
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/wm/window_state.h"
 #include "ash/shell.h"
+#include "ash/wm/window_state_aura.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "ui/aura/client/cursor_client.h"
@@ -87,11 +89,19 @@
   base::MessageLoop* loop = base::MessageLoop::current();
   base::MessageLoop::ScopedNestableTaskAllower allow_nested(loop);
 
+  // Disable window position auto management while dragging and restore it
+  // aftrewards.
+  wm::WindowState* window_state = wm::GetWindowState(source);
+  const bool window_position_managed = window_state->window_position_managed();
+  window_state->set_window_position_managed(false);
+
   run_loop.Run();
 
   if (!weak_ptr)
     return aura::client::MOVE_CANCELED;
 
+  window_state->set_window_position_managed(window_position_managed);
+
   in_move_loop_ = false;
   return result == wm::WmToplevelWindowEventHandler::DragResult::SUCCESS
              ? aura::client::MOVE_SUCCESSFUL
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc
index 06610b6..ba89155 100644
--- a/ash/wm/toplevel_window_event_handler_unittest.cc
+++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -113,6 +113,67 @@
 
 namespace {
 
+void ContinueAndCompleteDrag(ui::test::EventGenerator* generator,
+                             wm::WindowState* window_state,
+                             aura::Window* window) {
+  ASSERT_TRUE(window->HasCapture());
+  ASSERT_FALSE(window_state->window_position_managed());
+  generator->DragMouseBy(100, 100);
+  generator->ReleaseLeftButton();
+}
+
+}  // namespace
+
+// Tests dragging restores expected window position auto manage property
+// correctly.
+TEST_F(ToplevelWindowEventHandlerTest, WindowPositionAutoManagement) {
+  std::unique_ptr<aura::Window> w1(CreateWindow(HTNOWHERE));
+  const gfx::Size size = w1->bounds().size();
+  wm::WindowState* window_state = ash::wm::GetWindowState(w1.get());
+  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), w1.get());
+
+  // Explicitly enable window position auto management, and expect it to be
+  // restored after drag completes.
+  window_state->set_window_position_managed(true);
+  generator.PressLeftButton();
+  aura::client::WindowMoveClient* move_client =
+      aura::client::GetWindowMoveClient(w1->GetRootWindow());
+  // generator.PressLeftButton();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ContinueAndCompleteDrag, base::Unretained(&generator),
+                 base::Unretained(window_state), base::Unretained(w1.get())));
+  EXPECT_EQ(aura::client::MOVE_SUCCESSFUL,
+            move_client->RunMoveLoop(w1.get(), gfx::Vector2d(100, 100),
+                                     aura::client::WINDOW_MOVE_SOURCE_MOUSE));
+  // Window position auto manage property should be restored to true.
+  EXPECT_TRUE(window_state->window_position_managed());
+  // Position should have been offset by 100,100.
+  EXPECT_EQ("100,100", w1->bounds().origin().ToString());
+  // Size should remain the same.
+  EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
+
+  // Explicitly disable window position auto management, and expect it to be
+  // restored after drag completes.
+  window_state->set_window_position_managed(false);
+  generator.PressLeftButton();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&ContinueAndCompleteDrag, base::Unretained(&generator),
+                 base::Unretained(window_state), base::Unretained(w1.get())));
+  EXPECT_EQ(aura::client::MOVE_SUCCESSFUL,
+            move_client->RunMoveLoop(w1.get(), gfx::Vector2d(100, 100),
+                                     aura::client::WINDOW_MOVE_SOURCE_MOUSE));
+  // Window position auto manage property should be restored to true.
+  EXPECT_FALSE(window_state->window_position_managed());
+  // Position should have been offset by 100,100.
+  EXPECT_EQ("200,200", w1->bounds().origin().ToString());
+  // Size should remain the same.
+  EXPECT_EQ(size.ToString(), w1->bounds().size().ToString());
+}
+
+namespace {
+
 class CancelDragObserver : public aura::WindowObserver {
  public:
   CancelDragObserver() {}
diff --git a/base/android/jni_generator/BUILD.gn b/base/android/jni_generator/BUILD.gn
index 1741e51..12c0c39 100644
--- a/base/android/jni_generator/BUILD.gn
+++ b/base/android/jni_generator/BUILD.gn
@@ -11,7 +11,7 @@
     "jni_generator.py",
     "jni_generator_tests.py",
     "java/src/org/chromium/example/jni_generator/SampleForTests.java",
-    "golden_sample_for_tests_jni.h",
+    "SampleForTests_jni.golden",
   ]
   outputs = [
     _stamp,
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/SampleForTests_jni.golden
similarity index 94%
rename from base/android/jni_generator/golden_sample_for_tests_jni.h
rename to base/android/jni_generator/SampleForTests_jni.golden
index 94fc6b0..6fdced2 100644
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ b/base/android/jni_generator/SampleForTests_jni.golden
@@ -50,19 +50,17 @@
     jcaller,
     const base::android::JavaParamRef<jstring>& param);
 
-extern "C" __attribute__((visibility("default")))
-jlong Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
+JNI_GENERATOR_EXPORT jlong
+    Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
     env, jobject jcaller,
     jstring param) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller),
       base::android::JavaParamRef<jstring>(env, param));
 }
 
-extern "C" __attribute__((visibility("default")))
-void
+JNI_GENERATOR_EXPORT void
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
@@ -73,8 +71,7 @@
 static jdouble GetDoubleFunction(JNIEnv* env, const
     base::android::JavaParamRef<jobject>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jdouble
+JNI_GENERATOR_EXPORT jdouble
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetDoubleFunction(JNIEnv*
     env, jobject jcaller) {
   return GetDoubleFunction(env, base::android::JavaParamRef<jobject>(env,
@@ -84,8 +81,7 @@
 static jfloat GetFloatFunction(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jfloat
+JNI_GENERATOR_EXPORT jfloat
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetFloatFunction(JNIEnv*
     env, jclass jcaller) {
   return GetFloatFunction(env, base::android::JavaParamRef<jclass>(env,
@@ -96,8 +92,7 @@
     base::android::JavaParamRef<jobject>& jcaller,
     const base::android::JavaParamRef<jobject>& rect);
 
-extern "C" __attribute__((visibility("default")))
-void
+JNI_GENERATOR_EXPORT void
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype(JNIEnv*
     env, jobject jcaller,
     jobject rect) {
@@ -108,19 +103,16 @@
 static base::android::ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jobject
+JNI_GENERATOR_EXPORT jobject
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeGetNonPODDatatype(JNIEnv*
     env, jobject jcaller) {
   return GetNonPODDatatype(env, base::android::JavaParamRef<jobject>(env,
       jcaller)).Release();
 }
 
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
@@ -128,11 +120,9 @@
       jcaller));
 }
 
-extern "C" __attribute__((visibility("default")))
-jdouble
+JNI_GENERATOR_EXPORT jdouble
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativePtr) {
   CPPClass::InnerClass* native =
       reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
@@ -141,11 +131,9 @@
       jcaller));
 }
 
-extern "C" __attribute__((visibility("default")))
-void
+JNI_GENERATOR_EXPORT void
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeAddStructB(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeCPPClass,
     jobject b) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
@@ -154,11 +142,9 @@
       jcaller), base::android::JavaParamRef<jobject>(env, b));
 }
 
-extern "C" __attribute__((visibility("default")))
-void
+JNI_GENERATOR_EXPORT void
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeIterateAndDoSomethingWithStructB(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
@@ -166,11 +152,9 @@
       base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-extern "C" __attribute__((visibility("default")))
-jstring
+JNI_GENERATOR_EXPORT jstring
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeReturnAString(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeCPPClass) {
   CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
   CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
@@ -181,8 +165,7 @@
 static jint GetInnerIntFunction(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024InnerClass_nativeGetInnerIntFunction(JNIEnv*
     env, jclass jcaller) {
   return GetInnerIntFunction(env, base::android::JavaParamRef<jclass>(env,
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 428c493..0173a2c 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -1031,9 +1031,7 @@
           'P0_TYPE': native.p0_type,
       })
       template = Template("""\
-extern "C" __attribute__((visibility("default")))
-${RETURN} ${STUB_NAME}(JNIEnv* env,
-    ${PARAMS_IN_STUB}) {
+JNI_GENERATOR_EXPORT ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
   ${PROFILING_ENTERED_NATIVE}
   ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
   CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
@@ -1044,8 +1042,7 @@
       template = Template("""
 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS});
 
-extern "C" __attribute__((visibility("default")))
-${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
+JNI_GENERATOR_EXPORT ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) {
   ${PROFILING_ENTERED_NATIVE}
   return ${NAME}(${PARAMS_IN_CALL})${POST_CALL};
 }
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
index 56a2ec8..4c159c0 100644
--- a/base/android/jni_generator/jni_generator_helper.h
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-
 #ifndef BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
 #define BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
 
@@ -11,26 +10,37 @@
 #include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/logging.h"
+#include "build/build_config.h"
 
 // Project-specific macros used by the header files generated by
 // jni_generator.py. Different projects can then specify their own
 // implementation for this file.
 #define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
-    DCHECK(native_ptr) << method_name;
+  DCHECK(native_ptr) << method_name;
 
-#define CHECK_CLAZZ(env, jcaller, clazz, ...) \
-    DCHECK(clazz);
+#define CHECK_CLAZZ(env, jcaller, clazz, ...) DCHECK(clazz);
+
+#if defined(ARCH_CPU_X86)
+// Dalvik JIT generated code doesn't guarantee 16-byte stack alignment on
+// x86 - use force_align_arg_pointer to realign the stack at the JNI
+// boundary. crbug.com/655248
+#define JNI_GENERATOR_EXPORT \
+  extern "C" __attribute__((visibility("default"), force_align_arg_pointer))
+#else
+#define JNI_GENERATOR_EXPORT extern "C" __attribute__((visibility("default")))
+#endif
 
 namespace jni_generator {
 
-  inline void HandleRegistrationError(JNIEnv* env, jclass clazz,
-                                      const char* filename) {
-    LOG(ERROR) << "RegisterNatives failed in " << filename;
-  }
+inline void HandleRegistrationError(JNIEnv* env,
+                                    jclass clazz,
+                                    const char* filename) {
+  LOG(ERROR) << "RegisterNatives failed in " << filename;
+}
 
-  inline void CheckException(JNIEnv* env) {
-    base::android::CheckException(env);
-  }
+inline void CheckException(JNIEnv* env) {
+  base::android::CheckException(env);
+}
 
 }  // namespace jni_generator
 
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 9c066ce..022f043 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -834,7 +834,7 @@
     content = file(os.path.join(script_dir,
         'java/src/org/chromium/example/jni_generator/SampleForTests.java')
         ).read()
-    golden_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h')
+    golden_file = os.path.join(script_dir, 'SampleForTests_jni.golden')
     golden_content = file(golden_file).read()
     jni_from_java = jni_generator.JNIFromJavaSource(
         content, 'org/chromium/example/jni_generator/SampleForTests',
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index fc68bc8..68ed943 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -34,8 +34,8 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
+JNI_GENERATOR_EXPORT jint
+    Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
     jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index 554b37a..0d7b93e 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -35,16 +35,16 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env,
+    jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
+JNI_GENERATOR_EXPORT jint
+    Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
     jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index 9ad94db8..8f37c68 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -39,8 +39,8 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
+JNI_GENERATOR_EXPORT jint
+    Java_org_chromium_TestJni_00024MyInnerClass_nativeInit(JNIEnv* env, jobject
     jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
@@ -48,8 +48,8 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
+JNI_GENERATOR_EXPORT jint
+    Java_org_chromium_TestJni_00024MyOtherInnerClass_nativeInit(JNIEnv* env,
     jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index bf4679c0..dfeebc11 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -32,8 +32,8 @@
     const base::android::JavaParamRef<jobject>& callback1,
     const base::android::JavaParamRef<jobject>& callback2);
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass jcaller,
+JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv*
+    env, jclass jcaller,
     jobject callback1,
     jobject callback2) {
   return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
diff --git a/base/android/jni_generator/testNativeExportsOnlyOption.golden b/base/android/jni_generator/testNativeExportsOnlyOption.golden
index 901816c9..6a50619 100644
--- a/base/android/jni_generator/testNativeExportsOnlyOption.golden
+++ b/base/android/jni_generator/testNativeExportsOnlyOption.golden
@@ -27,11 +27,9 @@
 }  // namespace
 
 // Step 2: method stubs.
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeTest,
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
@@ -40,11 +38,9 @@
       jcaller), arg1);
 }
 
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
-    env,
-    jobject jcaller,
+    env, jobject jcaller,
     jlong nativeTest,
     jint arg1) {
   Test* native = reinterpret_cast<Test*>(nativeTest);
@@ -56,8 +52,7 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
     env, jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
@@ -66,8 +61,7 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint
+JNI_GENERATOR_EXPORT jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
     env, jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index e2f64cd..2399cd7 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -30,13 +30,12 @@
 static jint Init(JNIEnv* env, const base::android::JavaParamRef<jobject>&
     jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env, jobject jcaller) {
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeInit(JNIEnv* env,
+    jobject jcaller) {
   return Init(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
     jobject jcaller,
     jint nativeChromeBrowserProvider) {
   ChromeBrowserProvider* native =
@@ -46,9 +45,8 @@
       jcaller));
 }
 
-extern "C" __attribute__((visibility("default")))
-jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv* env,
-    jobject jcaller,
+JNI_GENERATOR_EXPORT jlong Java_org_chromium_TestJni_nativeAddBookmark(JNIEnv*
+    env, jobject jcaller,
     jint nativeChromeBrowserProvider,
     jstring url,
     jstring title,
@@ -66,8 +64,8 @@
     env, const base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jstring>& url);
 
-extern "C" __attribute__((visibility("default")))
-jstring Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env, jclass
+JNI_GENERATOR_EXPORT jstring
+    Java_org_chromium_TestJni_nativeGetDomainAndRegistry(JNIEnv* env, jclass
     jcaller,
     jstring url) {
   return GetDomainAndRegistry(env, base::android::JavaParamRef<jclass>(env,
@@ -79,8 +77,8 @@
     const base::android::JavaParamRef<jbyteArray>& state,
     jint tab_index);
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState(JNIEnv* env,
+JNI_GENERATOR_EXPORT void
+    Java_org_chromium_TestJni_nativeCreateHistoricalTabFromState(JNIEnv* env,
     jclass jcaller,
     jbyteArray state,
     jint tab_index) {
@@ -93,9 +91,9 @@
     env, const base::android::JavaParamRef<jobject>& jcaller,
     const base::android::JavaParamRef<jobject>& view);
 
-extern "C" __attribute__((visibility("default")))
-jbyteArray Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv* env,
-    jobject jcaller,
+JNI_GENERATOR_EXPORT jbyteArray
+    Java_org_chromium_TestJni_nativeGetStateAsByteArray(JNIEnv* env, jobject
+    jcaller,
     jobject view) {
   return GetStateAsByteArray(env, base::android::JavaParamRef<jobject>(env,
       jcaller), base::android::JavaParamRef<jobject>(env, view)).Release();
@@ -105,9 +103,9 @@
     GetAutofillProfileGUIDs(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jobjectArray Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs(JNIEnv*
-    env, jclass jcaller) {
+JNI_GENERATOR_EXPORT jobjectArray
+    Java_org_chromium_TestJni_nativeGetAutofillProfileGUIDs(JNIEnv* env, jclass
+    jcaller) {
   return GetAutofillProfileGUIDs(env, base::android::JavaParamRef<jclass>(env,
       jcaller)).Release();
 }
@@ -117,8 +115,8 @@
     jint sessionId,
     const base::android::JavaParamRef<jobjectArray>& results);
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env, jobject
+JNI_GENERATOR_EXPORT void
+    Java_org_chromium_TestJni_nativeSetRecognitionResults(JNIEnv* env, jobject
     jcaller,
     jint sessionId,
     jobjectArray results) {
@@ -127,9 +125,9 @@
       results));
 }
 
-extern "C" __attribute__((visibility("default")))
-jlong Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env,
-    jobject jcaller,
+JNI_GENERATOR_EXPORT jlong
+    Java_org_chromium_TestJni_nativeAddBookmarkFromAPI(JNIEnv* env, jobject
+    jcaller,
     jint nativeChromeBrowserProvider,
     jstring url,
     jobject created,
@@ -156,8 +154,8 @@
     jcaller,
     const base::android::JavaParamRef<jstring>& find);
 
-extern "C" __attribute__((visibility("default")))
-jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env, jobject jcaller,
+JNI_GENERATOR_EXPORT jint Java_org_chromium_TestJni_nativeFindAll(JNIEnv* env,
+    jobject jcaller,
     jstring find) {
   return FindAll(env, base::android::JavaParamRef<jobject>(env, jcaller),
       base::android::JavaParamRef<jstring>(env, find));
@@ -166,16 +164,14 @@
 static base::android::ScopedJavaLocalRef<jobject> GetInnerClass(JNIEnv* env,
     const base::android::JavaParamRef<jclass>& jcaller);
 
-extern "C" __attribute__((visibility("default")))
-jobject Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass
-    jcaller) {
+JNI_GENERATOR_EXPORT jobject
+    Java_org_chromium_TestJni_nativeGetInnerClass(JNIEnv* env, jclass jcaller) {
   return GetInnerClass(env, base::android::JavaParamRef<jclass>(env,
       jcaller)).Release();
 }
 
-extern "C" __attribute__((visibility("default")))
-jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv* env,
-    jobject jcaller,
+JNI_GENERATOR_EXPORT jobject Java_org_chromium_TestJni_nativeQueryBitmap(JNIEnv*
+    env, jobject jcaller,
     jint nativeChromeBrowserProvider,
     jobjectArray projection,
     jstring selection,
@@ -191,9 +187,8 @@
       base::android::JavaParamRef<jstring>(env, sortOrder)).Release();
 }
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv* env,
-    jobject jcaller,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeGotOrientation(JNIEnv*
+    env, jobject jcaller,
     jint nativeDataFetcherImplAndroid,
     jdouble alpha,
     jdouble beta,
@@ -210,9 +205,9 @@
     base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jthrowable>& e);
 
-extern "C" __attribute__((visibility("default")))
-jthrowable Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv* env,
-    jclass jcaller,
+JNI_GENERATOR_EXPORT jthrowable
+    Java_org_chromium_TestJni_nativeMessWithJavaException(JNIEnv* env, jclass
+    jcaller,
     jthrowable e) {
   return MessWithJavaException(env, base::android::JavaParamRef<jclass>(env,
       jcaller), base::android::JavaParamRef<jthrowable>(env, e)).Release();
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index 9dddf2fe4..12a153e 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -26,8 +26,7 @@
 }  // namespace
 
 // Step 2: method stubs.
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
+JNI_GENERATOR_EXPORT void Java_org_chromium_TestJni_nativeDestroy(JNIEnv* env,
     jobject jcaller,
     jlong nativeChromeBrowserProvider) {
   ChromeBrowserProvider* native =
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index cd11925..1f5ac11 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -31,8 +31,8 @@
     jcaller,
     const base::android::JavaParamRef<jobject>& callback);
 
-extern "C" __attribute__((visibility("default")))
-void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv* env, jclass jcaller,
+JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeDoSomething(JNIEnv*
+    env, jclass jcaller,
     jobject callback) {
   return DoSomething(env, base::android::JavaParamRef<jclass>(env, jcaller),
       base::android::JavaParamRef<jobject>(env, callback));
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 7b346cf..926f275f 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -4,6 +4,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import distutils.spawn
 import optparse
 import os
 import shutil
@@ -319,6 +320,13 @@
   for arg in options.bootclasspath:
     bootclasspath += build_utils.ParseGnList(arg)
   options.bootclasspath = bootclasspath
+  if options.java_version == '1.8' and options.bootclasspath:
+    # Android's boot jar doesn't contain all java 8 classes.
+    # See: https://github.com/evant/gradle-retrolambda/issues/23.
+    javac_path = os.path.realpath(distutils.spawn.find_executable('javac'))
+    jdk_dir = os.path.dirname(os.path.dirname(javac_path))
+    rt_jar = os.path.join(jdk_dir, 'jre', 'lib', 'rt.jar')
+    options.bootclasspath.append(rt_jar)
 
   classpath = []
   for arg in options.classpath:
diff --git a/build/android/gyp/retrolambda.py b/build/android/gyp/retrolambda.py
new file mode 100755
index 0000000..158ed52
--- /dev/null
+++ b/build/android/gyp/retrolambda.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+#
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import os
+import shutil
+import sys
+import tempfile
+
+from util import build_utils
+
+
+_SRC_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__),
+                                         '..', '..', '..'))
+_RETROLAMBDA_JAR_PATH = os.path.normpath(os.path.join(
+    _SRC_ROOT, 'third_party', 'retrolambda', 'retrolambda-2.3.0.jar'))
+
+
+def _OnStaleMd5(input_jar, output_jar, classpath, android_sdk_jar):
+  with build_utils.TempDir() as temp_dir:
+    build_utils.ExtractAll(input_jar, path=temp_dir)
+    cmd = [
+        'java',
+        '-Dretrolambda.inputDir=' + temp_dir,
+        '-Dretrolambda.classpath=' +
+            ':'.join([temp_dir] + classpath + [android_sdk_jar]),
+        '-javaagent:' + _RETROLAMBDA_JAR_PATH,
+        '-jar',
+        _RETROLAMBDA_JAR_PATH,
+    ]
+
+    build_utils.CheckOutput(cmd, print_stdout=False)
+    build_utils.ZipDir(output_jar + '.tmp', temp_dir)
+    shutil.move(output_jar + '.tmp', output_jar)
+
+
+def main():
+  args = build_utils.ExpandFileArgs(sys.argv[1:])
+  parser = argparse.ArgumentParser()
+  build_utils.AddDepfileOption(parser)
+  parser.add_argument('--input-jar', required=True,
+                      help='Jar input path to include .class files from.')
+  parser.add_argument('--output-jar', required=True,
+                      help='Jar output path.')
+  parser.add_argument('--classpath', required=True,
+                      help='Classpath.')
+  parser.add_argument('--android-sdk-jar', required=True,
+                      help='Android sdk jar path.')
+  options = parser.parse_args(args)
+
+  options.classpath = build_utils.ParseGnList(options.classpath)
+  input_paths = options.classpath + [options.input_jar]
+  output_paths = [options.output_jar]
+
+  build_utils.CallAndWriteDepfileIfStale(
+      lambda: _OnStaleMd5(options.input_jar, options.output_jar,
+                          options.classpath, options.android_sdk_jar),
+      options,
+      input_paths=input_paths,
+      input_strings=[],
+      output_paths=output_paths)
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 74c66118..d5948f2 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -132,7 +132,7 @@
     # Required for Android M+ due to SELinux policies (stronger sandboxing).
     disable_incremental_isolated_processes = false
 
-    # Speed up incremental compiles by compiling only changed files.
+    # Speeds up incremental compiles by compiling only changed files.
     enable_incremental_javac = false
 
     # Adds intrumentation to each function. Writes a file with the order that
@@ -142,6 +142,10 @@
     # Builds secondary abi for APKs, supports build 32-bit arch as secondary
     # abi in 64-bit Monochrome and WebView.
     build_apk_secondary_abi = true
+
+    # Enables java8 language features (via retrolambda).
+    # work-in-progress (http://crbug.com/642600)
+    use_java8 = false
   }
 
   # We need a second declare_args block to make sure we are using the overridden
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index f08b6cd3..27b736f3 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -418,7 +418,7 @@
   }
 }
 
-# Generates a script in the output bin directory which runs the test
+# Generates a script in the build bin directory which runs the test
 # target using the test runner script in build/android/test_runner.py.
 template("test_runner_script") {
   testonly = true
@@ -823,10 +823,10 @@
     }
   }
 
-  # Generates a script in the output bin.java directory to run a java binary.
+  # Generates a script in the build bin directory to run a java binary.
   #
   # Variables
-  #   main_class: The class containing the progam entry point.
+  #   main_class: The class containing the program entry point.
   #   jar_path: The path to the jar to run.
   #   script_name: Name of the script to generate.
   #   build_config: Path to .build_config for the jar (contains classpath).
@@ -1004,9 +1004,6 @@
     _input_jar_path = invoker.input_jar_path
     _output_jar_path = invoker.output_jar_path
 
-    _proguard_preprocess =
-        defined(invoker.proguard_preprocess) && invoker.proguard_preprocess
-
     _jar_excluded_patterns = []
     if (defined(invoker.jar_excluded_patterns)) {
       _jar_excluded_patterns = invoker.jar_excluded_patterns
@@ -1015,56 +1012,65 @@
                               invoker.strip_resource_classes
     _filter_jar = _jar_excluded_patterns != [] || _strip_resource_classes
 
+    _proguard_preprocess =
+        defined(invoker.proguard_preprocess) && invoker.proguard_preprocess
+
     _enable_assert =
         defined(invoker.supports_android) && invoker.supports_android &&
         (is_java_debug || dcheck_always_on)
-    assert(_enable_assert || true)  # Mark used.
+
+    _retrolambda = defined(invoker.supports_android) &&
+                   invoker.supports_android && use_java8
+
+    _deps = []
+    _previous_output_jar = _input_jar_path
 
     if (_filter_jar) {
       _filter_target = "${target_name}__filter"
+      _filter_input_jar = _previous_output_jar
+      _filter_output_jar = "$target_out_dir/$target_name-filtered.jar"
 
-      _filter_jar_path = "$target_out_dir/$target_name-filtered.jar"
       action(_filter_target) {
         script = "//build/android/gyp/jar.py"
-        forward_variables_from(invoker,
-                               [
-                                 "deps",
-                                 "public_deps",
-                               ])
+        deps = _deps
+        if (defined(invoker.deps)) {
+          deps += invoker.deps
+        }
+        if (defined(invoker.public_deps)) {
+          public_deps = invoker.public_deps
+        }
         inputs = [
           _build_config,
-          _input_jar_path,
+          _filter_input_jar,
         ]
         outputs = [
-          _filter_jar_path,
+          _filter_output_jar,
         ]
         args = [
           "--input-jar",
-          rebase_path(_input_jar_path, root_build_dir),
+          rebase_path(_filter_input_jar, root_build_dir),
           "--jar-path",
-          rebase_path(_filter_jar_path, root_build_dir),
+          rebase_path(_filter_output_jar, root_build_dir),
           "--excluded-classes=$_jar_excluded_patterns",
         ]
         if (_strip_resource_classes) {
           args += [ "--strip-resource-classes-for=@FileArg($_rebased_build_config:javac:resource_packages)" ]
         }
       }
+
+      _deps = []
+      _deps = [ ":$_filter_target" ]
+      _previous_output_jar = _filter_output_jar
     }
 
     if (_proguard_preprocess) {
-      _output_jar_target = "${target_name}__proguard_process"
-      _proguard_output_jar = _output_jar_path
+      _proguard_target = "${target_name}__proguard_process"
+      _proguard_input_jar = _previous_output_jar
+      _proguard_output_jar = "$target_out_dir/$target_name-proguarded.jar"
       _proguard_config_path = invoker.proguard_preprocess_config
-      proguard(_output_jar_target) {
-        if (_filter_jar) {
-          _proguard_input_jar = _filter_jar_path
-          deps = [
-            ":$_filter_target",
-          ]
-        } else {
-          _proguard_input_jar = _input_jar_path
-          deps = []
-        }
+
+      proguard(_proguard_target) {
+        deps = _deps
         if (defined(invoker.deps)) {
           deps += invoker.deps
         }
@@ -1088,20 +1094,23 @@
           "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
         ]
       }
-    } else if (_enable_assert) {
-      _output_jar_target = "${target_name}__assert"
-      _assert_output_jar = _output_jar_path
-      action(_output_jar_target) {
-        script = "$root_out_dir/bin/helper/java_assertion_enabler"
+
+      _deps = []
+      _deps = [ ":$_proguard_target" ]
+      _previous_output_jar = _proguard_output_jar
+    }
+
+    if (_enable_assert) {
+      _assert_target = "${target_name}__assert"
+      _assert_input_jar = _previous_output_jar
+      _assert_output_jar = "$target_out_dir/$target_name-asserted.jar"
+
+      action(_assert_target) {
+        script = "$root_build_dir/bin/helper/java_assertion_enabler"
         deps = [
           "//build/android/java_assertion_enabler($default_toolchain)",
         ]
-        if (_filter_jar) {
-          _assert_input_jar = _filter_jar_path
-          deps += [ ":$_filter_target" ]
-        } else {
-          _assert_input_jar = _input_jar_path
-        }
+        deps += _deps
         if (defined(invoker.deps)) {
           deps += invoker.deps
         }
@@ -1119,31 +1128,65 @@
           rebase_path(_assert_output_jar, root_build_dir),
         ]
       }
-    } else {
-      _output_jar_target = "${target_name}__copy"
-      copy(_output_jar_target) {
-        if (_filter_jar) {
-          _copy_input_jar = _filter_jar_path
-          public_deps = [
-            ":$_filter_target",
-          ]
-        } else {
-          _copy_input_jar = _input_jar_path
-          public_deps = []
-        }
+
+      _deps = []
+      _deps = [ ":$_assert_target" ]
+      _previous_output_jar = _assert_output_jar
+    }
+
+    if (_retrolambda) {
+      _retrolambda_target = "${target_name}__retrolambda"
+      _retrolambda_input_jar = _previous_output_jar
+      _retrolambda_output_jar = "$target_out_dir/$target_name-retrolambda.jar"
+
+      android_sdk_jar = "$android_sdk/android.jar"
+      action(_retrolambda_target) {
+        script = "//build/android/gyp/retrolambda.py"
+        deps = _deps
         if (defined(invoker.deps)) {
-          deps = invoker.deps
+          deps += invoker.deps
         }
         if (defined(invoker.public_deps)) {
-          public_deps += invoker.public_deps
+          public_deps = invoker.public_deps
         }
-        sources = [
-          _copy_input_jar,
+        inputs = [
+          _build_config,
+          _retrolambda_input_jar,
         ]
         outputs = [
-          _output_jar_path,
+          _retrolambda_output_jar,
+        ]
+        args = [
+          "--input-jar",
+          rebase_path(_retrolambda_input_jar, root_build_dir),
+          "--output-jar",
+          rebase_path(_retrolambda_output_jar, root_build_dir),
+          "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
+          "--android-sdk-jar",
+          rebase_path(android_sdk_jar, root_build_dir),
         ]
       }
+
+      _deps = []
+      _deps = [ ":$_retrolambda_target" ]
+      _previous_output_jar = _retrolambda_output_jar
+    }
+
+    _output_jar_target = "${target_name}__copy"
+    copy(_output_jar_target) {
+      deps = _deps
+      if (defined(invoker.deps)) {
+        deps += invoker.deps
+      }
+      if (defined(invoker.public_deps)) {
+        public_deps = invoker.public_deps
+      }
+      sources = [
+        _previous_output_jar,
+      ]
+      outputs = [
+        _output_jar_path,
+      ]
     }
 
     group(target_name) {
@@ -2083,7 +2126,9 @@
             rebase_path(_android_sdk_ijar, root_build_dir)
         args += [ "--bootclasspath=$_rebased_android_sdk_ijar" ]
       }
-      if (_supports_android) {
+      if (use_java8) {
+        args += [ "--java-version=1.8" ]
+      } else if (_supports_android) {
         args += [ "--java-version=1.7" ]
       }
       foreach(e, _manifest_entries) {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 89197fa..0f18914 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1160,6 +1160,9 @@
   #     will be added to the javac classpath.
   #   jar_path: Path to the prebuilt jar.
   #   jar_dep: Target that builds jar_path (optional).
+  #   main_class: When specified, a wrapper script is created within
+  #     $root_build_dir/bin to launch the binary with the given class as the
+  #     entrypoint.
   #   output_name: File name for the output .jar (not including extension).
   #     Defaults to the input .jar file name.
   #   proguard_preprocess: If true, proguard preprocessing will be run. This can
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
index 99cd55d..fdeb00f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
@@ -473,6 +473,9 @@
     }
 
     private void startMarginAnimation(boolean enter, boolean showIncognito) {
+        // Any outstanding animations must be cancelled to avoid race condition.
+        cancelAnimation(this, Property.INNER_MARGIN_PERCENT);
+
         float start = mInnerMarginPercent;
         float end = enter && showIncognito ? 1.0f : 0.0f;
         if (start != end) {
@@ -481,6 +484,9 @@
     }
 
     private void startYOffsetAnimation(boolean enter) {
+        // Any outstanding animations must be cancelled to avoid race condition.
+        cancelAnimation(this, Property.STACK_OFFSET_Y_PERCENT);
+
         float start = mStackOffsetYPercent;
         float end = enter ? 1.f : 0.f;
         if (start != end) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index d98be03c..d58f31f9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -51,13 +51,9 @@
  * Chrome gets killed.
  */
 public class DownloadNotificationService extends Service {
-    static final String EXTRA_DOWNLOAD_NOTIFICATION_ID = "DownloadNotificationId";
     static final String EXTRA_DOWNLOAD_GUID = "DownloadGuid";
-    static final String EXTRA_DOWNLOAD_FILE_NAME = "DownloadFileName";
     static final String EXTRA_DOWNLOAD_FILE_PATH = "DownloadFilePath";
     static final String EXTRA_NOTIFICATION_DISMISSED = "NotificationDismissed";
-    static final String EXTRA_DOWNLOAD_IS_OFF_THE_RECORD = "DownloadIsOffTheRecord";
-    static final String EXTRA_DOWNLOAD_IS_OFFLINE_PAGE = "DownloadIsOfflinePage";
     static final String EXTRA_IS_SUPPORTED_MIME_TYPE = "IsSupportedMimeType";
     static final String ACTION_DOWNLOAD_CANCEL =
             "org.chromium.chrome.browser.download.DOWNLOAD_CANCEL";
@@ -297,12 +293,12 @@
                 isOffTheRecord, canDownloadWhileMetered, downloadGuid, fileName, itemType, true));
         if (startTime > 0) builder.setWhen(startTime);
         Intent cancelIntent = buildActionIntent(
-                ACTION_DOWNLOAD_CANCEL, notificationId, downloadGuid, fileName, isOfflinePage);
+                ACTION_DOWNLOAD_CANCEL, downloadGuid, fileName, isOfflinePage);
         builder.addAction(R.drawable.btn_close_white,
                 mContext.getResources().getString(R.string.download_notification_cancel_button),
                 buildPendingIntent(cancelIntent, notificationId));
         Intent pauseIntent = buildActionIntent(
-                ACTION_DOWNLOAD_PAUSE, notificationId, downloadGuid, fileName, isOfflinePage);
+                ACTION_DOWNLOAD_PAUSE, downloadGuid, fileName, isOfflinePage);
         builder.addAction(R.drawable.ic_media_control_pause,
                 mContext.getResources().getString(R.string.download_notification_pause_button),
                 buildPendingIntent(pauseIntent, notificationId));
@@ -362,8 +358,7 @@
         NotificationCompat.Builder builder = buildNotification(
                 android.R.drawable.ic_media_pause, entry.fileName, contentText);
         Intent cancelIntent = buildActionIntent(
-                ACTION_DOWNLOAD_CANCEL, entry.notificationId, entry.downloadGuid, entry.fileName,
-                entry.isOfflinePage());
+                ACTION_DOWNLOAD_CANCEL, entry.downloadGuid, entry.fileName, entry.isOfflinePage());
         Intent dismissIntent = new Intent(cancelIntent);
         dismissIntent.putExtra(EXTRA_NOTIFICATION_DISMISSED, true);
         builder.setDeleteIntent(buildPendingIntent(dismissIntent, entry.notificationId));
@@ -371,9 +366,7 @@
                 mContext.getResources().getString(R.string.download_notification_cancel_button),
                 buildPendingIntent(cancelIntent, entry.notificationId));
         Intent resumeIntent = buildActionIntent(
-                ACTION_DOWNLOAD_RESUME, entry.notificationId, entry.downloadGuid, entry.fileName,
-                entry.isOfflinePage());
-        resumeIntent.putExtra(EXTRA_DOWNLOAD_IS_OFF_THE_RECORD, entry.isOffTheRecord);
+                ACTION_DOWNLOAD_RESUME, entry.downloadGuid, entry.fileName, entry.isOfflinePage());
         builder.addAction(R.drawable.ic_get_app_white_24dp,
                 mContext.getResources().getString(R.string.download_notification_resume_button),
                 buildPendingIntent(resumeIntent, entry.notificationId));
@@ -407,8 +400,7 @@
                 mContext.getPackageName(), DownloadBroadcastReceiver.class.getName());
         Intent intent;
         if (isOfflinePage) {
-            intent = buildActionIntent(ACTION_DOWNLOAD_OPEN, notificationId, downloadGuid, fileName,
-                    isOfflinePage);
+            intent = buildActionIntent(ACTION_DOWNLOAD_OPEN, downloadGuid, fileName, isOfflinePage);
         } else {
             intent = new Intent(DownloadManager.ACTION_NOTIFICATION_CLICKED);
             long[] idArray = {systemDownloadId};
@@ -490,22 +482,17 @@
     /**
      * Helper method to build an download action Intent from the provided information.
      * @param action Download action to perform.
-     * @param notificationId ID of the notification.
      * @param downloadGuid GUID of the download.
      * @param fileName Name of the download file.
      * @param isOfflinePage Whether the intent is for offline page download.
      */
     private Intent buildActionIntent(
-            String action, int notificationId, String downloadGuid, String fileName,
-            boolean isOfflinePage) {
+            String action, String downloadGuid, String fileName, boolean isOfflinePage) {
         ComponentName component = new ComponentName(
                 mContext.getPackageName(), DownloadBroadcastReceiver.class.getName());
         Intent intent = new Intent(action);
         intent.setComponent(component);
-        intent.putExtra(EXTRA_DOWNLOAD_NOTIFICATION_ID, notificationId);
         intent.putExtra(EXTRA_DOWNLOAD_GUID, downloadGuid);
-        intent.putExtra(EXTRA_DOWNLOAD_FILE_NAME, fileName);
-        intent.putExtra(EXTRA_DOWNLOAD_IS_OFFLINE_PAGE, isOfflinePage);
         return intent;
     }
 
@@ -560,19 +547,7 @@
     private DownloadSharedPreferenceEntry getDownloadEntryFromIntent(Intent intent) {
         if (intent.getAction() == ACTION_DOWNLOAD_RESUME_ALL) return null;
         String guid = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_GUID);
-        DownloadSharedPreferenceEntry entry = getDownloadSharedPreferenceEntry(guid);
-        if (entry != null) return entry;
-        int notificationId = IntentUtils.safeGetIntExtra(
-                intent, EXTRA_DOWNLOAD_NOTIFICATION_ID, -1);
-        String fileName = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_FILE_NAME);
-        boolean metered = DownloadManagerService.isActiveNetworkMetered(mContext);
-        boolean isOffTheRecord =  IntentUtils.safeGetBooleanExtra(
-                intent, EXTRA_DOWNLOAD_IS_OFF_THE_RECORD, false);
-        boolean isOfflinePage =  IntentUtils.safeGetBooleanExtra(
-                intent, EXTRA_DOWNLOAD_IS_OFFLINE_PAGE, false);
-        return new DownloadSharedPreferenceEntry(notificationId, isOffTheRecord, metered, guid,
-                fileName, isOfflinePage ? DownloadSharedPreferenceEntry.ITEM_TYPE_OFFLINE_PAGE
-                        : DownloadSharedPreferenceEntry.ITEM_TYPE_DOWNLOAD, true);
+        return getDownloadSharedPreferenceEntry(guid);
     }
 
     /**
@@ -582,6 +557,7 @@
      */
     private void handleDownloadOperation(final Intent intent) {
         final DownloadSharedPreferenceEntry entry = getDownloadEntryFromIntent(intent);
+        if (entry == null) return;
         if (intent.getAction() == ACTION_DOWNLOAD_PAUSE) {
             // If browser process already goes away, the download should have already paused. Do
             // nothing in that case.
@@ -708,16 +684,7 @@
                 && !ACTION_DOWNLOAD_OPEN.equals(intent.getAction())) {
             return false;
         }
-        if (!intent.hasExtra(EXTRA_DOWNLOAD_NOTIFICATION_ID)
-                || !intent.hasExtra(EXTRA_DOWNLOAD_FILE_NAME)
-                || !intent.hasExtra(EXTRA_DOWNLOAD_GUID)) {
-            return false;
-        }
-        final int notificationId =
-                IntentUtils.safeGetIntExtra(intent, EXTRA_DOWNLOAD_NOTIFICATION_ID, -1);
-        if (notificationId == -1) return false;
-        final String fileName = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_FILE_NAME);
-        if (fileName == null) return false;
+        if (!intent.hasExtra(EXTRA_DOWNLOAD_GUID)) return false;
         final String guid = IntentUtils.safeGetStringExtra(intent, EXTRA_DOWNLOAD_GUID);
         if (!DownloadSharedPreferenceEntry.isValidGUID(guid)) return false;
         return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
index b82a9099..3f34f3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gsa/GSAServiceClient.java
@@ -18,6 +18,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.RemoteException;
+import android.os.StrictMode;
 import android.util.Log;
 
 import org.chromium.base.Callback;
@@ -180,8 +181,16 @@
     boolean connect() {
         if (mService != null) Log.e(TAG, "Already connected.");
         Intent intent = new Intent(GSA_SERVICE).setPackage(GSAState.SEARCH_INTENT_PACKAGE);
-        return mContext.bindService(
-                intent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
+
+        // Third-party modifications to the framework lead to StrictMode violations in
+        // Context#bindService(). See crbug.com/670195.
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            return mContext.bindService(
+                    intent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
     }
 
     /**
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 81b674be..e135107 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -6530,7 +6530,7 @@
   </message>
   <message name="IDS_FLAGS_ENABLE_IME_MENU_NAME" desc="Name of the about: flag for enabling opt-in IME menu.">
     Enable opt-in IME menu
-    </message>
+  </message>
   <message name="IDS_FLAGS_ENABLE_IME_MENU_DESCRIPTION" desc="Description of the about: flag for enabling opt-in IME menu.">
     Enable access to the new IME menu in the Language Settings page.
   </message>
@@ -6584,4 +6584,34 @@
   <message name="IDS_PRINT_JOB_NOTIFICATION_GET_HELP_BUTTON" desc="Text on the button for the user to get help about the current print job.">
     Get help
   </message>
+
+  <!-- RequestPin dialog messages -->
+  <message name="IDS_REQUEST_PIN_DIALOG_HEADER" desc="The text displayed in the certificate provider PIN request dialog.">
+    "<ph name="EXTENSION_NAME">$1<ex>My Extension</ex></ph>" is requesting your <ph name="CODE_TYPE">$2<ex>PIN</ex></ph>
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_PROCESSING" desc="The text displayed while the certificate provider API is waiting for response from extension.">
+    Processing request...
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_INVALID_PIN_ERROR" desc="The error message displayed in the certificate provider PIN request dialog when an invalid PIN was entered.">
+    Invalid PIN.
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_INVALID_PUK_ERROR" desc="The error message displayed in the certificate provider PIN request dialog when an invalid PUK was entered.">
+    Invalid PUK.
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_MAX_ATTEMPTS_EXCEEDED_ERROR" desc="The error message displayed in the certificate provider PIN request dialog when maximum allowed attempts exceeded.">
+    Maximum allowed attempts exceeded.
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_UNKNOWN_ERROR" desc="The error message displayed in the certificate provider PIN request dialog when unknown error occurred in extension code.">
+    Unknown error.
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_ATTEMPTS_LEFT" desc="The text displayed in the certificate provider PIN request dialog about the number of attempts left">
+    Attempts left: $1
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_PIN" desc="The Provider Identification Number abbreviation">
+    PIN
+  </message>
+  <message name="IDS_REQUEST_PIN_DIALOG_PUK" desc="The Personal Unlocking Key (as used in mobile phones) abbreviation">
+    PUK
+  </message>
+
 </grit-part>
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index b9a99a6..c1beac6 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -105,12 +105,13 @@
 
     // When launching the browser process, ensure that we don't inherit the
     // --mash flag so it proceeds with the normal content/browser startup path.
-    base::CommandLine::StringVector argv(command_line->argv());
-    auto iter =
-        std::find(argv.begin(), argv.end(), FILE_PATH_LITERAL("--mash"));
-    if (iter != argv.end())
-      argv.erase(iter);
-    *command_line = base::CommandLine(argv);
+    // Eliminate all copies in case the developer passed more than one.
+    base::CommandLine::StringVector new_argv;
+    for (const base::CommandLine::StringType& arg : command_line->argv()) {
+      if (arg != FILE_PATH_LITERAL("--mash"))
+        new_argv.push_back(arg);
+    }
+    *command_line = base::CommandLine(new_argv);
   }
 
   DISALLOW_COPY_AND_ASSIGN(NativeRunnerDelegateImpl);
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 59393a2..f0bebec 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2007,6 +2007,7 @@
     deps += [
       "//chrome/browser/safe_browsing:chunk_proto",
       "//chrome/common/safe_browsing:proto",
+      "//components/safe_browsing/common:common",
       "//components/safe_browsing_db:metadata_proto",
     ]
     if (safe_browsing_mode == 1) {
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 5b4967e..5a63b9f 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -351,6 +351,9 @@
 }
 
 - (void)sendEvent:(NSEvent*)event {
+  base::debug::ScopedCrashKey crash_key(
+      crash_keys::mac::kNSEvent, base::SysNSStringToUTF8([event description]));
+
   base::mac::CallWithEHFrame(^{
     switch (event.type) {
       case NSLeftMouseDown:
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e75a72c..fc3ef093 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -303,6 +303,8 @@
     "certificate_provider/certificate_provider_service_factory.h",
     "certificate_provider/certificate_requests.cc",
     "certificate_provider/certificate_requests.h",
+    "certificate_provider/pin_dialog_manager.cc",
+    "certificate_provider/pin_dialog_manager.h",
     "certificate_provider/sign_requests.cc",
     "certificate_provider/sign_requests.h",
     "certificate_provider/thread_safe_certificate_map.cc",
@@ -1273,6 +1275,8 @@
     "ui/low_disk_notification.h",
     "ui/mobile_config_ui.cc",
     "ui/mobile_config_ui.h",
+    "ui/request_pin_view.cc",
+    "ui/request_pin_view.h",
     "ui/screen_capture_notification_ui_chromeos.cc",
     "ui/screen_capture_notification_ui_chromeos.h",
     "upgrade_detector_chromeos.cc",
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
index 806cac9..6726c97 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
@@ -400,6 +400,8 @@
 
   for (auto callback : sign_requests_.RemoveAllRequests(extension_id))
     callback.Run(net::ERR_FAILED, std::vector<uint8_t>());
+
+  pin_dialog_manager_.ExtensionUnloaded(extension_id);
 }
 
 void CertificateProviderService::GetCertificatesFromExtensions(
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
index dada1f225..41550f35 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.h
@@ -19,6 +19,7 @@
 #include "base/threading/thread_checker.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_info.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_requests.h"
+#include "chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h"
 #include "chrome/browser/chromeos/certificate_provider/sign_requests.h"
 #include "chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -150,6 +151,8 @@
   // corresponding notification of the ExtensionRegistry is triggered.
   void OnExtensionUnloaded(const std::string& extension_id);
 
+  PinDialogManager* pin_dialog_manager() { return &pin_dialog_manager_; }
+
  private:
   class CertKeyProviderImpl;
   class CertificateProviderImpl;
@@ -191,6 +194,10 @@
   // the net::ClientKeyStore singleton.
   std::unique_ptr<CertKeyProviderImpl> cert_key_provider_;
 
+  // The object to manage the dialog displayed when requestPin is called by the
+  // extension.
+  PinDialogManager pin_dialog_manager_;
+
   // State about all pending sign requests.
   certificate_provider::SignRequests sign_requests_;
 
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
index 2edf5e7..3da1d9a 100644
--- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
+++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.cc
@@ -112,6 +112,8 @@
     return false;
 
   api_cp::SignRequest request;
+  service_->pin_dialog_manager()->AddSignRequestId(extension_id, request_id);
+  request.sign_request_id = request_id;
   switch (hash) {
     case net::SSLPrivateKey::Hash::MD5_SHA1:
       request.hash = api_cp::HASH_MD5_SHA1;
diff --git a/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.cc b/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.cc
new file mode 100644
index 0000000..fbc943e
--- /dev/null
+++ b/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.cc
@@ -0,0 +1,186 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h"
+
+#include "ash/shell.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "ui/aura/window.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/views/window/dialog_client_view.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace {
+
+gfx::NativeWindow GetBrowserParentWindow() {
+  if (chromeos::LoginDisplayHost::default_host()) {
+    return chromeos::LoginDisplayHost::default_host()->GetNativeWindow();
+  }
+
+  Browser* browser =
+      chrome::FindTabbedBrowser(ProfileManager::GetPrimaryUserProfile(), true);
+  if (browser) {
+    return browser->window()->GetNativeWindow();
+  }
+
+  return nullptr;
+}
+
+}  // namespace
+
+namespace chromeos {
+
+// Define timeout for issued sign_request_id.
+const int SIGN_REQUEST_ID_TIMEOUT_MINS = 10;
+
+PinDialogManager::PinDialogManager() : weak_factory_(this) {}
+
+PinDialogManager::~PinDialogManager() {
+  // Close the active dialog if present to avoid leaking callbacks.
+  if (active_pin_dialog_) {
+    CloseDialog(active_dialog_extension_id_);
+  }
+}
+
+void PinDialogManager::AddSignRequestId(const std::string& extension_id,
+                                        int sign_request_id) {
+  ExtensionNameRequestIdPair key(extension_id, sign_request_id);
+  // Cache the ID with current timestamp.
+  base::Time current_time = base::Time::Now();
+  sign_request_times_[key] = current_time;
+}
+
+PinDialogManager::RequestPinResponse PinDialogManager::ShowPinDialog(
+    const std::string& extension_id,
+    const std::string& extension_name,
+    int sign_request_id,
+    RequestPinView::RequestPinCodeType code_type,
+    RequestPinView::RequestPinErrorType error_type,
+    int attempts_left,
+    const RequestPinView::RequestPinCallback& callback) {
+  bool accept_input = (attempts_left != 0);
+  // If active dialog exists already, we need to make sure it belongs to the
+  // same extension and the user submitted some input.
+  if (active_pin_dialog_ != nullptr) {
+    DCHECK(!active_dialog_extension_id_.empty());
+    if (extension_id != active_dialog_extension_id_) {
+      return OTHER_FLOW_IN_PROGRESS;
+    }
+
+    // Extension requests a PIN without having received any input from its
+    // previous request. Reject the new request.
+    if (!active_pin_dialog_->IsLocked()) {
+      return DIALOG_DISPLAYED_ALREADY;
+    }
+
+    // Set the new callback to be used by the view.
+    active_pin_dialog_->SetCallback(callback);
+    active_pin_dialog_->SetDialogParameters(code_type, error_type,
+                                            attempts_left, accept_input);
+    active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons();
+    return SUCCESS;
+  }
+
+  // Check the validity of sign_request_id
+  ExtensionNameRequestIdPair key(extension_id, sign_request_id);
+  if (sign_request_times_.find(key) == sign_request_times_.end()) {
+    return INVALID_ID;
+  }
+
+  base::Time current_time = base::Time::Now();
+  if ((current_time - sign_request_times_[key]).InMinutes() >
+      SIGN_REQUEST_ID_TIMEOUT_MINS) {
+    return INVALID_ID;
+  }
+
+  active_dialog_extension_id_ = extension_id;
+  active_pin_dialog_ = new RequestPinView(extension_name, code_type,
+                                          attempts_left, callback, this);
+
+  gfx::NativeWindow parent = GetBrowserParentWindow();
+  gfx::NativeWindow context =
+      parent ? nullptr : ash::Shell::GetPrimaryRootWindow();
+  active_window_ = views::DialogDelegate::CreateDialogWidget(active_pin_dialog_,
+                                                             context, parent);
+  active_window_->Show();
+
+  return SUCCESS;
+}
+
+void PinDialogManager::OnPinDialogInput() {
+  last_response_closed_[active_dialog_extension_id_] = false;
+}
+
+void PinDialogManager::OnPinDialogClosed() {
+  last_response_closed_[active_dialog_extension_id_] = true;
+  // |active_pin_dialog_| is managed by |active_window_|. This local copy of
+  // the pointer is reset here to allow a new dialog to be created when a new
+  // request comes.
+  active_pin_dialog_ = nullptr;
+}
+
+PinDialogManager::StopPinRequestResponse PinDialogManager::UpdatePinDialog(
+    const std::string& extension_id,
+    RequestPinView::RequestPinErrorType error_type,
+    bool accept_input,
+    const RequestPinView::RequestPinCallback& callback) {
+  if (active_pin_dialog_ == nullptr ||
+      extension_id != active_dialog_extension_id_) {
+    return NO_ACTIVE_DIALOG;
+  }
+
+  if (!active_pin_dialog_->IsLocked()) {
+    return NO_USER_INPUT;
+  }
+
+  active_pin_dialog_->SetCallback(callback);
+  active_pin_dialog_->SetDialogParameters(
+      RequestPinView::RequestPinCodeType::UNCHANGED, error_type, -1,
+      accept_input);
+  active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons();
+  return STOPPED;
+}
+
+bool PinDialogManager::LastPinDialogClosed(const std::string& extension_id) {
+  return last_response_closed_[extension_id];
+}
+
+bool PinDialogManager::CloseDialog(const std::string& extension_id) {
+  if (extension_id != active_dialog_extension_id_ ||
+      active_pin_dialog_ == nullptr) {
+    LOG(ERROR) << "StopPinRequest called by unexpected extension: "
+               << extension_id;
+    return false;
+  }
+
+  // Close the window. |active_pin_dialog_| gets deleted inside Close().
+  active_window_->Close();
+  active_pin_dialog_ = nullptr;
+
+  return true;
+}
+
+void PinDialogManager::ExtensionUnloaded(const std::string& extension_id) {
+  if (active_pin_dialog_ && active_dialog_extension_id_ == extension_id) {
+    CloseDialog(extension_id);
+  }
+
+  last_response_closed_[extension_id] = false;
+
+  for (auto it = sign_request_times_.cbegin();
+       it != sign_request_times_.cend();) {
+    if (it->first.first == extension_id) {
+      sign_request_times_.erase(it++);
+    } else {
+      ++it;
+    }
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h b/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h
new file mode 100644
index 0000000..6babe06
--- /dev/null
+++ b/chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h
@@ -0,0 +1,122 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/ui/request_pin_view.h"
+#include "ui/views/widget/widget.h"
+
+namespace chromeos {
+
+// Manages the state of the dialog that requests the PIN from user. Used by the
+// extensions that need to request the PIN. Implemented as requirement for
+// crbug.com/612886
+class PinDialogManager : RequestPinView::Delegate {
+ public:
+  enum RequestPinResponse {
+    SUCCESS,
+    INVALID_ID,
+    OTHER_FLOW_IN_PROGRESS,
+    DIALOG_DISPLAYED_ALREADY
+  };
+
+  enum StopPinRequestResponse { STOPPED, NO_ACTIVE_DIALOG, NO_USER_INPUT };
+
+  PinDialogManager();
+  ~PinDialogManager();
+
+  // Stores internally the |signRequestId| along with current timestamp.
+  void AddSignRequestId(const std::string& extension_id, int sign_request_id);
+
+  // Creates a new RequestPinView object and displays it in a dialog or reuses
+  // the old dialog if active one exists just updating the parameters.
+  // |extension_id| - the ID of the extension requesting the dialog.
+  // |extension_name| - the name of the extension requesting the dialog.
+  // |sign_request_id| - the ID given by Chrome when the extension was asked to
+  //     sign the data. It should be a valid, not expired ID at the time the
+  //     extension is requesting PIN the first time.
+  // |code_type| - the type of input requested: either "PIN" or "PUK".
+  // |error_type| - the error template to be displayed inside the dialog. If
+  //     NONE, no error is displayed.
+  // |attempts_left| - the number of attempts the user has to try the code. It
+  //     is informational only, and enforced on Chrome side only in case it's
+  //     zero. In that case the textfield is disabled and the user can't provide
+  //     any input to extension. If -1 the textfield from the dialog is enabled
+  //     but no information about the attepts left is not given to the user.
+  // |callback| - used to notify about the user input in the text_field from the
+  //     dialog.
+  // Returns SUCCESS if the dialog is displayed and extension owns it. Otherwise
+  // the specific error is returned.
+  RequestPinResponse ShowPinDialog(
+      const std::string& extension_id,
+      const std::string& extension_name,
+      int sign_request_id,
+      RequestPinView::RequestPinCodeType code_type,
+      RequestPinView::RequestPinErrorType error_type,
+      int attempts_left,
+      const RequestPinView::RequestPinCallback& callback);
+
+  // chromeos::RequestPinView::Delegate overrides.
+  void OnPinDialogInput() override;
+  void OnPinDialogClosed() override;
+
+  // Updates the existing dialog with new error message. Uses |callback| with
+  // empty string when user closes the dialog. Returns whether the provided
+  // |extension_id| matches the extension owning the active dialog.
+  PinDialogManager::StopPinRequestResponse UpdatePinDialog(
+      const std::string& extension_id,
+      RequestPinView::RequestPinErrorType error_type,
+      bool accept_input,
+      const RequestPinView::RequestPinCallback& callback);
+
+  // Returns whether the last PIN dialog from this extension was closed by the
+  // user.
+  bool LastPinDialogClosed(const std::string& extension_id);
+
+  // Called when extension calls the stopPinRequest method. The active dialog is
+  // closed if the |extension_id| matches the |active_dialog_extension_id_|.
+  // Returns whether the dialog was closed.
+  bool CloseDialog(const std::string& extension_id);
+
+  // Resets the manager data related to the extension.
+  void ExtensionUnloaded(const std::string& extension_id);
+
+  RequestPinView* active_view_for_testing() { return active_pin_dialog_; }
+  views::Widget* active_window_for_testing() { return active_window_; }
+
+ private:
+  using ExtensionNameRequestIdPair = std::pair<std::string, int>;
+
+  // Tells whether user closed the last request PIN dialog issued by an
+  // extension. The extension_id is the key and value is true if user closed the
+  // dialog. Used to determine if the limit of dialogs rejected by the user has
+  // been exceeded.
+  std::unordered_map<std::string, bool> last_response_closed_;
+
+  // The map with extension_id and sign request id issued by Chrome as key while
+  // the time when the id was generated is the value.
+  std::map<ExtensionNameRequestIdPair, base::Time> sign_request_times_;
+
+  // There can be only one active dialog to request the PIN at some point in
+  // time. Owned by |active_window_|.
+  RequestPinView* active_pin_dialog_ = nullptr;
+  std::string active_dialog_extension_id_;
+  views::Widget* active_window_ = nullptr;
+
+  base::WeakPtrFactory<PinDialogManager> weak_factory_;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_CERTIFICATE_PROVIDER_PIN_DIALOG_MANAGER_H_
diff --git a/chrome/browser/chromeos/ui/request_pin_view.cc b/chrome/browser/chromeos/ui/request_pin_view.cc
new file mode 100644
index 0000000..c89c4cb
--- /dev/null
+++ b/chrome/browser/chromeos/ui/request_pin_view.cc
@@ -0,0 +1,262 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/ui/request_pin_view.h"
+
+#include <stddef.h>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/options/passphrase_textfield.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/grit/theme_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/events/event.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_client_view.h"
+
+namespace chromeos {
+
+RequestPinView::RequestPinView(const std::string& extension_name,
+                               RequestPinView::RequestPinCodeType code_type,
+                               int attempts_left,
+                               const RequestPinCallback& callback,
+                               Delegate* delegate)
+    : callback_(callback), delegate_(delegate), weak_ptr_factory_(this) {
+  DCHECK(code_type != RequestPinCodeType::UNCHANGED);
+  DCHECK(delegate);
+  Init();
+  SetExtensionName(extension_name);
+  const bool accept_input = (attempts_left != 0);
+  SetDialogParameters(code_type, RequestPinErrorType::NONE, attempts_left,
+                      accept_input);
+}
+
+// When the parent window is closed while the dialog is active, this object is
+// destroyed without triggering Accept or Cancel. If the callback_ wasn't called
+// it needs to send the response.
+RequestPinView::~RequestPinView() {
+  if (!callback_.is_null()) {
+    base::ResetAndReturn(&callback_).Run(base::string16());
+  }
+
+  delegate_->OnPinDialogClosed();
+}
+
+void RequestPinView::ContentsChanged(views::Textfield* sender,
+                                     const base::string16& new_contents) {
+  GetDialogClientView()->UpdateDialogButtons();
+}
+
+bool RequestPinView::Cancel() {
+  // Destructor will be called after this which notifies the delegate.
+  return true;
+}
+
+bool RequestPinView::Accept() {
+  DCHECK(!callback_.is_null());
+
+  if (!textfield_->enabled()) {
+    return true;
+  }
+  DCHECK(!textfield_->text().empty());
+
+  error_label_->SetVisible(true);
+  error_label_->SetText(
+      l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_PROCESSING));
+  error_label_->SetTooltipText(error_label_->text());
+  error_label_->SetEnabledColor(SK_ColorGRAY);
+  error_label_->SizeToPreferredSize();
+  // The |textfield_| and OK button become disabled, but the user still can
+  // close the dialog.
+  SetAcceptInput(false);
+  base::ResetAndReturn(&callback_).Run(textfield_->text());
+  GetDialogClientView()->UpdateDialogButtons();
+  delegate_->OnPinDialogInput();
+
+  return false;
+}
+
+base::string16 RequestPinView::GetWindowTitle() const {
+  return window_title_;
+}
+
+views::View* RequestPinView::GetInitiallyFocusedView() {
+  return textfield_;
+}
+
+bool RequestPinView::IsDialogButtonEnabled(ui::DialogButton button) const {
+  switch (button) {
+    case ui::DialogButton::DIALOG_BUTTON_CANCEL:
+      return true;
+    case ui::DialogButton::DIALOG_BUTTON_OK:
+      if (callback_.is_null()) {
+        return false;
+      }
+      // Not locked but the |textfield_| is not enabled. It's just a
+      // notification to the user and [OK] button can be used to close the
+      // dialog.
+      if (!textfield_->enabled()) {
+        return true;
+      }
+      return textfield_->text().size() > 0;
+    case ui::DialogButton::DIALOG_BUTTON_NONE:
+      return true;
+  }
+
+  NOTREACHED();
+  return true;
+}
+
+bool RequestPinView::IsLocked() {
+  return callback_.is_null();
+}
+
+void RequestPinView::SetCallback(const RequestPinCallback& callback) {
+  DCHECK(callback_.is_null());
+  callback_ = callback;
+}
+
+void RequestPinView::SetDialogParameters(
+    RequestPinView::RequestPinCodeType code_type,
+    RequestPinView::RequestPinErrorType error_type,
+    int attempts_left,
+    bool accept_input) {
+  SetErrorMessage(error_type, attempts_left);
+  SetAcceptInput(accept_input);
+
+  switch (code_type) {
+    case RequestPinCodeType::PIN:
+      code_type_ = l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_PIN);
+      break;
+    case RequestPinCodeType::PUK:
+      code_type_ = l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_PUK);
+      break;
+    case RequestPinCodeType::UNCHANGED:
+      break;
+  }
+
+  UpdateHeaderText();
+}
+
+void RequestPinView::SetExtensionName(const std::string& extension_name) {
+  window_title_ = base::ASCIIToUTF16(extension_name);
+  UpdateHeaderText();
+}
+
+void RequestPinView::UpdateHeaderText() {
+  int label_text_id = IDS_REQUEST_PIN_DIALOG_HEADER;
+  base::string16 label_text =
+      l10n_util::GetStringFUTF16(label_text_id, window_title_, code_type_);
+  header_label_->SetText(label_text);
+  header_label_->SizeToPreferredSize();
+}
+
+void RequestPinView::Init() {
+  views::GridLayout* layout = views::GridLayout::CreatePanel(this);
+  SetLayoutManager(layout);
+
+  int column_view_set_id = 0;
+  views::ColumnSet* column_set = layout->AddColumnSet(column_view_set_id);
+
+  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
+                        views::GridLayout::USE_PREF, 0, 0);
+  layout->StartRow(0, column_view_set_id);
+
+  // Infomation label.
+  int label_text_id = IDS_REQUEST_PIN_DIALOG_HEADER;
+  base::string16 label_text = l10n_util::GetStringUTF16(label_text_id);
+  header_label_ = new views::Label(label_text);
+  header_label_->SetEnabled(true);
+  layout->AddView(header_label_);
+
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  column_view_set_id++;
+  column_set = layout->AddColumnSet(column_view_set_id);
+  column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 100,
+                        views::GridLayout::USE_PREF, 0, 0);
+
+  // Textfield to enter the PIN/PUK.
+  layout->StartRow(0, column_view_set_id);
+  textfield_ = new PassphraseTextfield();
+  textfield_->set_controller(this);
+  textfield_->SetEnabled(true);
+  layout->AddView(textfield_);
+
+  layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
+
+  column_view_set_id++;
+  column_set = layout->AddColumnSet(column_view_set_id);
+  column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
+                        views::GridLayout::USE_PREF, 0, 0);
+
+  // Error label.
+  layout->StartRow(0, column_view_set_id);
+  error_label_ = new views::Label();
+  error_label_->SetVisible(false);
+  error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  layout->AddView(error_label_);
+}
+
+void RequestPinView::SetAcceptInput(bool accept_input) {
+  if (accept_input) {
+    textfield_->SetEnabled(true);
+    textfield_->SetBackgroundColor(SK_ColorWHITE);
+    textfield_->RequestFocus();
+  } else {
+    textfield_->SetEnabled(false);
+    textfield_->SetBackgroundColor(SK_ColorGRAY);
+  }
+}
+
+void RequestPinView::SetErrorMessage(RequestPinErrorType error_type,
+                                     int attempts_left) {
+  base::string16 error_message;
+  switch (error_type) {
+    case RequestPinErrorType::INVALID_PIN:
+      error_message =
+          l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_INVALID_PIN_ERROR);
+      break;
+    case RequestPinErrorType::INVALID_PUK:
+      error_message =
+          l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_INVALID_PUK_ERROR);
+      break;
+    case RequestPinErrorType::MAX_ATTEMPTS_EXCEEDED:
+      error_message = l10n_util::GetStringUTF16(
+          IDS_REQUEST_PIN_DIALOG_MAX_ATTEMPTS_EXCEEDED_ERROR);
+      break;
+    case RequestPinErrorType::UNKNOWN_ERROR:
+      error_message =
+          l10n_util::GetStringUTF16(IDS_REQUEST_PIN_DIALOG_UNKNOWN_ERROR);
+      break;
+    case RequestPinErrorType::NONE:
+      if (attempts_left < 0) {
+        error_label_->SetVisible(false);
+        return;
+      }
+      break;
+  }
+
+  if (attempts_left >= 0) {
+    error_message.append(l10n_util::GetStringFUTF16(
+        IDS_REQUEST_PIN_DIALOG_ATTEMPTS_LEFT,
+        base::ASCIIToUTF16(std::to_string(attempts_left))));
+  }
+
+  error_label_->SetVisible(true);
+  error_label_->SetText(error_message);
+  error_label_->SetTooltipText(error_message);
+  error_label_->SetEnabledColor(SK_ColorRED);
+  error_label_->SizeToPreferredSize();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/ui/request_pin_view.h b/chrome/browser/chromeos/ui/request_pin_view.h
new file mode 100644
index 0000000..2884a75f
--- /dev/null
+++ b/chrome/browser/chromeos/ui/request_pin_view.h
@@ -0,0 +1,145 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_UI_REQUEST_PIN_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_UI_REQUEST_PIN_VIEW_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/view.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace views {
+class Label;
+}
+
+namespace chromeos {
+
+// A dialog box for requesting PIN code. Instances of this class are managed by
+// PinDialogManager.
+class RequestPinView : public views::DialogDelegateView,
+                       public views::TextfieldController {
+ public:
+  enum RequestPinCodeType { PIN, PUK, UNCHANGED };
+
+  enum RequestPinErrorType {
+    NONE,
+    INVALID_PIN,
+    INVALID_PUK,
+    MAX_ATTEMPTS_EXCEEDED,
+    UNKNOWN_ERROR
+  };
+
+  class Delegate {
+   public:
+    // Notification when user closes the PIN dialog.
+    virtual void OnPinDialogClosed() = 0;
+
+    // Notification when the user provided input to dialog.
+    virtual void OnPinDialogInput() = 0;
+  };
+
+  // Used to send the PIN/PUK entered by the user in the textfield to the
+  // extension that asked for the code.
+  using RequestPinCallback = base::Callback<void(const base::string16&)>;
+
+  // Creates the view to be embeded in the dialog that requests the PIN/PUK.
+  // |extension_name| - the name of the extension making the request. Displayed
+  //     in the title and in the header of the view.
+  // |code_type| - the type of code requested, PIN or PUK. UNCHANGED is not
+  //     accepted here.
+  // |attempts_left| - the number of attempts user has to try the code. When
+  //     zero the textfield is disabled and user cannot provide any input. When
+  //     -1 the user is allowed to provide the input and no information about
+  //     the attepts left is displayed in the view.
+  // |callback| - used to send the value of the PIN/PUK the user entered.
+  // |delegate| - used to notify that dialog was closed. Cannot be null.
+  RequestPinView(const std::string& extension_name,
+                 RequestPinCodeType code_type,
+                 int attempts_left,
+                 const RequestPinCallback& callback,
+                 Delegate* delegate);
+  ~RequestPinView() override;
+
+  // views::TextfieldController
+  void ContentsChanged(views::Textfield* sender,
+                       const base::string16& new_contents) override;
+
+  // views::DialogDelegateView
+  bool Cancel() override;
+  bool Accept() override;
+  base::string16 GetWindowTitle() const override;
+  views::View* GetInitiallyFocusedView() override;
+  bool IsDialogButtonEnabled(ui::DialogButton button) const override;
+
+  // Returns whether the view is locked while waiting the extension to process
+  // the user input data.
+  bool IsLocked();
+
+  // Set the new callback to be used when user will provide the input. The old
+  // callback must be used and reset to null at this point.
+  void SetCallback(const RequestPinCallback& callback);
+
+  // |code_type| - specifies whether the user is asked to enter PIN or PUK. If
+  //     UNCHANGED value is provided, the dialog displays the same value that
+  //     was last set.
+  // |error_type| - the error template to be displayed in red in the dialog. If
+  //     NONE, no error is displayed.
+  // |attempts_left| - included in the view as the number of attepts user can
+  //     have to enter correct code.
+  // |accept_input| - specifies whether the textfield is enabled. If disabled
+  //     the user is unable to provide input.
+  void SetDialogParameters(RequestPinCodeType code_type,
+                           RequestPinErrorType error_type,
+                           int attempts_left,
+                           bool accept_input);
+
+  // Set the name of extension that is using this view. The name is included in
+  // the header text displayed by the view.
+  void SetExtensionName(const std::string& extension_name);
+
+  views::Textfield* textfield_for_testing() { return textfield_; }
+  views::Label* error_label_for_testing() { return error_label_; }
+
+ private:
+  // This initializes the view, with all the UI components.
+  void Init();
+  void SetAcceptInput(bool accept_input);
+  void SetErrorMessage(RequestPinErrorType error_type, int attempts_left);
+  // Updates the header text |header_label_| based on values from
+  // |window_title_| and |code_type_|.
+  void UpdateHeaderText();
+
+  // Used to send the input when the view is not locked. If user closes the
+  // view, the provided input is empty. The |callback_| must be reset to null
+  // after being used, allowing to check that it was used when a new callback is
+  // set.
+  RequestPinCallback callback_;
+
+  // Owned by the caller.
+  Delegate* delegate_ = nullptr;
+
+  base::string16 window_title_;
+  views::Label* header_label_ = nullptr;
+  base::string16 code_type_;
+  views::Textfield* textfield_ = nullptr;
+  views::Label* error_label_ = nullptr;
+
+  base::WeakPtrFactory<RequestPinView> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RequestPinView);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_UI_REQUEST_PIN_VIEW_H_
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
index cdf49c4..8d1a2bb 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.cc
@@ -19,10 +19,35 @@
 #include "net/cert/x509_certificate.h"
 #include "net/ssl/ssl_private_key.h"
 
-namespace extensions {
+namespace api_cp = extensions::api::certificate_provider;
+namespace api_cpi = extensions::api::certificate_provider_internal;
 
-namespace api_cp = api::certificate_provider;
-namespace api_cpi = api::certificate_provider_internal;
+namespace {
+
+chromeos::RequestPinView::RequestPinErrorType GetErrorTypeForView(
+    api_cp::PinRequestErrorType error_type) {
+  switch (error_type) {
+    case api_cp::PinRequestErrorType::PIN_REQUEST_ERROR_TYPE_INVALID_PIN:
+      return chromeos::RequestPinView::RequestPinErrorType::INVALID_PIN;
+    case api_cp::PinRequestErrorType::PIN_REQUEST_ERROR_TYPE_INVALID_PUK:
+      return chromeos::RequestPinView::RequestPinErrorType::INVALID_PUK;
+    case api_cp::PinRequestErrorType::
+        PIN_REQUEST_ERROR_TYPE_MAX_ATTEMPTS_EXCEEDED:
+      return chromeos::RequestPinView::RequestPinErrorType::
+          MAX_ATTEMPTS_EXCEEDED;
+    case api_cp::PinRequestErrorType::PIN_REQUEST_ERROR_TYPE_UNKNOWN_ERROR:
+      return chromeos::RequestPinView::RequestPinErrorType::UNKNOWN_ERROR;
+    case api_cp::PinRequestErrorType::PIN_REQUEST_ERROR_TYPE_NONE:
+      return chromeos::RequestPinView::RequestPinErrorType::NONE;
+  }
+
+  NOTREACHED();
+  return chromeos::RequestPinView::RequestPinErrorType::NONE;
+}
+
+}  // namespace
+
+namespace extensions {
 
 namespace {
 
@@ -33,8 +58,17 @@
 const char kErrorAborted[] = "Request was aborted.";
 const char kErrorTimeout[] = "Request timed out, reply rejected.";
 
+// requestPin constants.
+const char kNoActiveDialog[] = "No active dialog from extension.";
+const char kInvalidId[] = "Invalid signRequestId";
+const char kOtherFlowInProgress[] = "Other flow in progress";
+const char kPreviousDialogActive[] = "Previous request not finished";
+const char kNoUserInput[] = "No user input received";
+
 }  // namespace
 
+const int api::certificate_provider::kMaxClosedDialogsPer10Mins = 2;
+
 CertificateProviderInternalReportCertificatesFunction::
     ~CertificateProviderInternalReportCertificatesFunction() {}
 
@@ -148,6 +182,152 @@
   return true;
 }
 
+CertificateProviderStopPinRequestFunction::
+    ~CertificateProviderStopPinRequestFunction() {}
+
+ExtensionFunction::ResponseAction
+CertificateProviderStopPinRequestFunction::Run() {
+  std::unique_ptr<api_cp::RequestPin::Params> params(
+      api_cp::RequestPin::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  chromeos::CertificateProviderService* const service =
+      chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+          browser_context());
+  DCHECK(service);
+  if (params->details.error_type ==
+      api_cp::PinRequestErrorType::PIN_REQUEST_ERROR_TYPE_NONE) {
+    bool dialog_closed =
+        service->pin_dialog_manager()->CloseDialog(extension_id());
+    if (!dialog_closed) {
+      // This might happen if the user closed the dialog while extension was
+      // processing the input.
+      return RespondNow(Error(kNoActiveDialog));
+    }
+
+    return RespondNow(NoArguments());
+  }
+
+  // Extension provided an error, which means it intends to notify the user with
+  // the error and not allow any more input.
+  chromeos::RequestPinView::RequestPinErrorType error_type =
+      GetErrorTypeForView(params->details.error_type);
+  chromeos::PinDialogManager::StopPinRequestResponse update_response =
+      service->pin_dialog_manager()->UpdatePinDialog(
+          extension()->id(), error_type,
+          false,  // Don't accept any input.
+          base::Bind(&CertificateProviderStopPinRequestFunction::DialogClosed,
+                     this));
+  switch (update_response) {
+    case chromeos::PinDialogManager::StopPinRequestResponse::NO_ACTIVE_DIALOG:
+      return RespondNow(Error(kNoActiveDialog));
+    case chromeos::PinDialogManager::StopPinRequestResponse::NO_USER_INPUT:
+      return RespondNow(Error(kNoUserInput));
+    case chromeos::PinDialogManager::StopPinRequestResponse::STOPPED:
+      return RespondLater();
+  }
+
+  NOTREACHED();
+  return RespondLater();
+}
+
+void CertificateProviderStopPinRequestFunction::DialogClosed(
+    const base::string16& value) {
+  chromeos::CertificateProviderService* const service =
+      chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+          browser_context());
+  DCHECK(service);
+
+  Respond(NoArguments());
+  service->pin_dialog_manager()->OnPinDialogClosed();
+}
+
+CertificateProviderRequestPinFunction::
+    ~CertificateProviderRequestPinFunction() {}
+
+bool CertificateProviderRequestPinFunction::ShouldSkipQuotaLimiting() const {
+  chromeos::CertificateProviderService* const service =
+      chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+          browser_context());
+  DCHECK(service);
+
+  return !service->pin_dialog_manager()->LastPinDialogClosed(extension_id());
+}
+
+void CertificateProviderRequestPinFunction::GetQuotaLimitHeuristics(
+    extensions::QuotaLimitHeuristics* heuristics) const {
+  QuotaLimitHeuristic::Config short_limit_config = {
+      api::certificate_provider::kMaxClosedDialogsPer10Mins,
+      base::TimeDelta::FromMinutes(10)};
+  heuristics->push_back(base::MakeUnique<QuotaService::TimedLimit>(
+      short_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
+      "MAX_PIN_DIALOGS_CLOSED_PER_10_MINUTES"));
+}
+
+ExtensionFunction::ResponseAction CertificateProviderRequestPinFunction::Run() {
+  std::unique_ptr<api_cp::RequestPin::Params> params(
+      api_cp::RequestPin::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params);
+
+  api_cp::PinRequestType pin_request_type =
+      params->details.request_type ==
+              api_cp::PinRequestType::PIN_REQUEST_TYPE_NONE
+          ? api_cp::PinRequestType::PIN_REQUEST_TYPE_PIN
+          : params->details.request_type;
+
+  chromeos::RequestPinView::RequestPinErrorType error_type =
+      GetErrorTypeForView(params->details.error_type);
+
+  chromeos::RequestPinView::RequestPinCodeType code_type =
+      (pin_request_type == api_cp::PinRequestType::PIN_REQUEST_TYPE_PIN)
+          ? chromeos::RequestPinView::RequestPinCodeType::PIN
+          : chromeos::RequestPinView::RequestPinCodeType::PUK;
+
+  chromeos::CertificateProviderService* const service =
+      chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+          browser_context());
+  DCHECK(service);
+
+  int attempts_left =
+      params->details.attempts_left ? *params->details.attempts_left : -1;
+  chromeos::PinDialogManager::RequestPinResponse result =
+      service->pin_dialog_manager()->ShowPinDialog(
+          extension()->id(), extension()->name(),
+          params->details.sign_request_id, code_type, error_type, attempts_left,
+          base::Bind(&CertificateProviderRequestPinFunction::OnInputReceived,
+                     this));
+  switch (result) {
+    case chromeos::PinDialogManager::RequestPinResponse::SUCCESS:
+      return RespondLater();
+    case chromeos::PinDialogManager::RequestPinResponse::INVALID_ID:
+      return RespondNow(Error(kInvalidId));
+    case chromeos::PinDialogManager::RequestPinResponse::OTHER_FLOW_IN_PROGRESS:
+      return RespondNow(Error(kOtherFlowInProgress));
+    case chromeos::PinDialogManager::RequestPinResponse::
+        DIALOG_DISPLAYED_ALREADY:
+      return RespondNow(Error(kPreviousDialogActive));
+  }
+
+  NOTREACHED();
+  return RespondNow(Error(kPreviousDialogActive));
+}
+
+void CertificateProviderRequestPinFunction::OnInputReceived(
+    const base::string16& value) {
+  std::unique_ptr<base::ListValue> create_results(new base::ListValue());
+  chromeos::CertificateProviderService* const service =
+      chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+          browser_context());
+  DCHECK(service);
+  if (!value.empty()) {
+    api::certificate_provider::PinResponseDetails details;
+    details.user_input.reset(new std::string(value.begin(), value.end()));
+    create_results->Append(details.ToValue());
+  }
+
+  Respond(ArgumentList(std::move(create_results)));
+}
+
 CertificateProviderInternalReportSignatureFunction::
     ~CertificateProviderInternalReportSignatureFunction() {}
 
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h
index bc4ec19..1f4686b 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h
@@ -17,6 +17,10 @@
 
 namespace api {
 namespace certificate_provider {
+// The maximum number of times per 10 minutes, extension is allowed to show PIN
+// dialog again after user closed the previous one.
+extern const int kMaxClosedDialogsPer10Mins;
+
 struct CertificateInfo;
 }
 }
@@ -45,6 +49,30 @@
                              CERTIFICATEPROVIDERINTERNAL_REPORTSIGNATURE);
 };
 
+class CertificateProviderRequestPinFunction : public UIThreadExtensionFunction {
+ private:
+  ~CertificateProviderRequestPinFunction() override;
+  ResponseAction Run() override;
+  bool ShouldSkipQuotaLimiting() const override;
+  void GetQuotaLimitHeuristics(
+      extensions::QuotaLimitHeuristics* heuristics) const override;
+  void OnInputReceived(const base::string16& value);
+
+  DECLARE_EXTENSION_FUNCTION("certificateProvider.requestPin",
+                             CERTIFICATEPROVIDER_REQUESTPIN);
+};
+
+class CertificateProviderStopPinRequestFunction
+    : public UIThreadExtensionFunction {
+ private:
+  ~CertificateProviderStopPinRequestFunction() override;
+  ResponseAction Run() override;
+  void DialogClosed(const base::string16& value);
+
+  DECLARE_EXTENSION_FUNCTION("certificateProvider.stopPinRequest",
+                             CERTIFICATEPROVIDER_STOPPINREQUEST);
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_CERTIFICATE_PROVIDER_CERTIFICATE_PROVIDER_API_H_
diff --git a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
index 407f6a9..bd24b95 100644
--- a/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
+++ b/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc
@@ -18,6 +18,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
+#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
+#include "chrome/browser/extensions/api/certificate_provider/certificate_provider_api.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -32,11 +35,16 @@
 #include "content/public/test/test_utils.h"
 #include "crypto/rsa_private_key.h"
 #include "extensions/common/extension.h"
+#include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
 #include "net/test/spawned_test_server/spawned_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/boringssl/src/include/openssl/evp.h"
 #include "third_party/boringssl/src/include/openssl/rsa.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_observer.h"
 
 using testing::Return;
 using testing::_;
@@ -121,6 +129,41 @@
   return res;
 }
 
+// Enters the code in the ShowPinDialog window and pushes the OK event.
+void EnterCode(chromeos::CertificateProviderService* service,
+               const base::string16& code) {
+  chromeos::RequestPinView* view =
+      service->pin_dialog_manager()->active_view_for_testing();
+  view->textfield_for_testing()->SetText(code);
+  view->Accept();
+  base::RunLoop().RunUntilIdle();
+}
+
+// Enters the valid code for extensions from local example folders, in the
+// ShowPinDialog window and waits for the window to close. The extension code
+// is expected to send "Success" message after the validation and request to
+// stopPinRequest is done.
+void EnterCorrectPin(chromeos::CertificateProviderService* service) {
+  ExtensionTestMessageListener listener("Success", false);
+  EnterCode(service, base::ASCIIToUTF16("1234"));
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+}
+
+// Enters an invalid code for extensions from local example folders, in the
+// ShowPinDialog window and waits for the window to update with the error. The
+// extension code is expected to send "Invalid PIN" message after the validation
+// and the new requestPin (with the error) is done.
+void EnterWrongPin(chromeos::CertificateProviderService* service) {
+  ExtensionTestMessageListener listener("Invalid PIN", false);
+  EnterCode(service, base::ASCIIToUTF16("567"));
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+
+  // Check that we have an error message displayed.
+  chromeos::RequestPinView* view =
+      service->pin_dialog_manager()->active_view_for_testing();
+  EXPECT_EQ(SK_ColorRED, view->error_label_for_testing()->enabled_color());
+}
+
 class CertificateProviderApiTest : public ExtensionApiTest {
  public:
   CertificateProviderApiTest() {}
@@ -157,6 +200,27 @@
   policy::MockConfigurationPolicyProvider provider_;
 };
 
+class CertificateProviderRequestPinTest : public CertificateProviderApiTest {
+ public:
+  // Loads certificate_provider extension from |folder| and |file_name|.
+  // Returns the CertificateProviderService object from browser context.
+  chromeos::CertificateProviderService* LoadRequestPinExtension(
+      const std::string& folder,
+      const std::string& file_name) {
+    const base::FilePath extension_path =
+        test_data_dir_.AppendASCII("certificate_provider/" + folder);
+    const extensions::Extension* const extension =
+        LoadExtension(extension_path);
+    chromeos::CertificateProviderService* service =
+        chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
+            profile());
+    service->pin_dialog_manager()->AddSignRequestId(extension->id(), 123);
+    ui_test_utils::NavigateToURL(browser(),
+                                 extension->GetResourceURL(file_name));
+    return service;
+  }
+};
+
 }  // namespace
 
 IN_PROC_BROWSER_TEST_F(CertificateProviderApiTest, Basic) {
@@ -268,3 +332,99 @@
     EXPECT_TRUE(result);
   }
 }
+
+// User enters the correct PIN.
+IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest, ShowPinDialogAccept) {
+  chromeos::CertificateProviderService* service =
+      LoadRequestPinExtension("request_pin", "basic.html");
+
+  // Enter the valid PIN.
+  EnterCorrectPin(service);
+
+  // The view should be set to nullptr when the window is closed.
+  EXPECT_EQ(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+}
+
+// User closes the dialog kMaxClosedDialogsPer10Mins times, and the extension
+// should be blocked from showing it again.
+IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest, ShowPinDialogClose) {
+  chromeos::CertificateProviderService* service =
+      LoadRequestPinExtension("request_pin", "basic.html");
+
+  views::Widget* window =
+      service->pin_dialog_manager()->active_window_for_testing();
+  for (int i = 0;
+       i < extensions::api::certificate_provider::kMaxClosedDialogsPer10Mins;
+       i++) {
+    ExtensionTestMessageListener listener("User closed the dialog", false);
+    window->Close();
+    ASSERT_TRUE(listener.WaitUntilSatisfied());
+    window = service->pin_dialog_manager()->active_window_for_testing();
+  }
+
+  ExtensionTestMessageListener close_listener("User closed the dialog", true);
+  window->Close();
+  ASSERT_TRUE(close_listener.WaitUntilSatisfied());
+  close_listener.Reply("GetLastError");
+  ExtensionTestMessageListener last_error_listener(
+      "This request exceeds the MAX_PIN_DIALOGS_CLOSED_PER_10_MINUTES quota.",
+      false);
+  ASSERT_TRUE(last_error_listener.WaitUntilSatisfied());
+  EXPECT_EQ(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+}
+
+// User enters a wrong PIN first and a correct PIN on the second try.
+IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest,
+                       ShowPinDialogWrongPin) {
+  chromeos::CertificateProviderService* service =
+      LoadRequestPinExtension("request_pin", "basic.html");
+  EnterWrongPin(service);
+
+  // The window should be active.
+  EXPECT_EQ(
+      service->pin_dialog_manager()->active_window_for_testing()->IsVisible(),
+      true);
+  EXPECT_NE(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+
+  // Enter the valid PIN.
+  EnterCorrectPin(service);
+
+  // The view should be set to nullptr when the window is closed.
+  EXPECT_EQ(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+}
+
+// User enters wrong PIN three times.
+IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest,
+                       ShowPinDialogWrongPinThreeTimes) {
+  chromeos::CertificateProviderService* service =
+      LoadRequestPinExtension("request_pin", "basic.html");
+  for (int i = 0; i < 3; i++) {
+    EnterWrongPin(service);
+  }
+
+  chromeos::RequestPinView* view =
+      service->pin_dialog_manager()->active_view_for_testing();
+
+  // The textfield has to be disabled, as extension does not allow input now.
+  EXPECT_EQ(view->textfield_for_testing()->enabled(), false);
+
+  // Close the dialog.
+  ExtensionTestMessageListener listener("No attempt left", false);
+  service->pin_dialog_manager()->active_window_for_testing()->Close();
+  ASSERT_TRUE(listener.WaitUntilSatisfied());
+  EXPECT_EQ(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+}
+
+// User closes the dialog while the extension is processing the request.
+IN_PROC_BROWSER_TEST_F(CertificateProviderRequestPinTest,
+                       ShowPinDialogCloseWhileProcessing) {
+  chromeos::CertificateProviderService* service =
+      LoadRequestPinExtension("request_pin", "basic_lock.html");
+
+  EnterCode(service, base::ASCIIToUTF16("123"));
+  service->pin_dialog_manager()->active_window_for_testing()->Close();
+  base::RunLoop().RunUntilIdle();
+
+  // The view should be set to nullptr when the window is closed.
+  EXPECT_EQ(service->pin_dialog_manager()->active_view_for_testing(), nullptr);
+}
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 662c9e7b..958a4958 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -251,6 +251,32 @@
   return value;
 }
 
+// This function is for forwarding metrics usage pref changes to the metrics
+// service on the appropriate thread.
+// TODO(gayane): Reduce the frequency of posting tasks from IO to UI thread.
+void UpdateMetricsUsagePrefsOnUIThread(const std::string& service_name,
+                                       int message_size,
+                                       bool is_cellular) {
+  BrowserThread::PostTask(
+      BrowserThread::UI,
+      FROM_HERE,
+      base::Bind([](const std::string& service_name,
+                    int message_size,
+                    bool is_cellular) {
+                   // Some unit tests use IOThread but do not initialize
+                   // MetricsService. In that case it's fine to skip the update.
+                   auto metrics_service = g_browser_process->metrics_service();
+                   if (metrics_service) {
+                     metrics_service->UpdateMetricsUsagePrefs(service_name,
+                                                              message_size,
+                                                              is_cellular);
+                   }
+                 },
+                 service_name,
+                 message_size,
+                 is_cellular));
+}
+
 }  // namespace
 
 class SystemURLRequestContextGetter : public net::URLRequestContextGetter {
@@ -405,14 +431,6 @@
   if (value)
     value->GetAsBoolean(&http_09_on_non_default_ports_enabled_);
 
-  // Some unit tests use IOThread but do not initialize MetricsService. In that
-  // case it is fine not to have |metrics_data_use_forwarder_|.
-  if (g_browser_process->metrics_service()) {
-    // Callback for updating data use prefs should be obtained on UI thread.
-    metrics_data_use_forwarder_ =
-        g_browser_process->metrics_service()->GetDataUseForwardingCallback();
-  }
-
   chrome_browser_net::SetGlobalSTHDistributor(
       std::unique_ptr<net::ct::STHDistributor>(new net::ct::STHDistributor()));
 
@@ -531,7 +549,7 @@
 
   globals_->system_network_delegate =
       globals_->data_use_ascriber->CreateNetworkDelegate(
-          std::move(chrome_network_delegate), metrics_data_use_forwarder_);
+          std::move(chrome_network_delegate), GetMetricsDataUseForwarder());
 
   globals_->host_resolver = CreateGlobalHostResolver(net_log_);
 
@@ -1078,7 +1096,6 @@
   return context;
 }
 
-const metrics::UpdateUsagePrefCallbackType&
-IOThread::GetMetricsDataUseForwarder() {
-  return metrics_data_use_forwarder_;
+metrics::UpdateUsagePrefCallbackType IOThread::GetMetricsDataUseForwarder() {
+  return base::Bind(&UpdateMetricsUsagePrefsOnUIThread);
 }
diff --git a/chrome/browser/io_thread.h b/chrome/browser/io_thread.h
index 78102bb..c958b64 100644
--- a/chrome/browser/io_thread.h
+++ b/chrome/browser/io_thread.h
@@ -239,7 +239,7 @@
   base::TimeTicks creation_time() const;
 
   // Returns the callback for updating data use prefs.
-  const metrics::UpdateUsagePrefCallbackType& GetMetricsDataUseForwarder();
+  metrics::UpdateUsagePrefCallbackType GetMetricsDataUseForwarder();
 
   // Registers the |observer| for new STH notifications.
   void RegisterSTHObserver(net::ct::STHObserver* observer);
@@ -399,10 +399,6 @@
 
   const base::TimeTicks creation_time_;
 
-  // Callback for updating data use prefs which needs to be initialized on UI
-  // thread and passed to |DataUseNetworkDelegate|.
-  metrics::UpdateUsagePrefCallbackType metrics_data_use_forwarder_;
-
   base::WeakPtrFactory<IOThread> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(IOThread);
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index dcb8b86..afa66a9 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -217,11 +217,12 @@
 content::ResourceType ResourcePrefetchPredictor::GetResourceType(
     content::ResourceType resource_type,
     const std::string& mime_type) {
-  // Restricts content::RESOURCE_TYPE_{PREFETCH,SUB_RESOURCE} to a small set of
-  // mime types, because these resource types don't communicate how the
+  // Restricts content::RESOURCE_TYPE_{PREFETCH,SUB_RESOURCE,XHR} to a small set
+  // of mime types, because these resource types don't communicate how the
   // resources will be used.
   if (resource_type == content::RESOURCE_TYPE_PREFETCH ||
-      resource_type == content::RESOURCE_TYPE_SUB_RESOURCE) {
+      resource_type == content::RESOURCE_TYPE_SUB_RESOURCE ||
+      resource_type == content::RESOURCE_TYPE_XHR) {
     return GetResourceTypeFromMimeType(mime_type,
                                        content::RESOURCE_TYPE_LAST_TYPE);
   }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 4ad1343e..bf1e160 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -1163,6 +1163,12 @@
       content::RESOURCE_TYPE_PREFETCH, "application/font-woff"));
   EXPECT_TRUE(ResourcePrefetchPredictor::IsHandledResourceType(
       content::RESOURCE_TYPE_PREFETCH, "font/woff2"));
+  EXPECT_FALSE(ResourcePrefetchPredictor::IsHandledResourceType(
+      content::RESOURCE_TYPE_XHR, ""));
+  EXPECT_FALSE(ResourcePrefetchPredictor::IsHandledResourceType(
+      content::RESOURCE_TYPE_XHR, "bogus/mime-type"));
+  EXPECT_TRUE(ResourcePrefetchPredictor::IsHandledResourceType(
+      content::RESOURCE_TYPE_XHR, "application/javascript"));
 }
 
 TEST_F(ResourcePrefetchPredictorTest, ShouldRecordRequestMainFrame) {
diff --git a/chrome/browser/printing/pdf_to_emf_converter.cc b/chrome/browser/printing/pdf_to_emf_converter.cc
index 0a0eb09..fb0be32 100644
--- a/chrome/browser/printing/pdf_to_emf_converter.cc
+++ b/chrome/browser/printing/pdf_to_emf_converter.cc
@@ -340,7 +340,7 @@
   if (!utility_process_host_ || !pdf)
     return OnFailed();
   // Should reply with OnPageCount().
-  Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Start(
+  Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
       IPC::GetPlatformFileForTransit(pdf->GetPlatformFile(), false), settings_,
       print_text_with_gdi));
 }
diff --git a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
index 034580a..3260bb9c 100644
--- a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
+++ b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
@@ -335,25 +335,25 @@
   // Converts the PDF to a PNG file so that the layout test can do an image
   // diff on this image and a reference image.
   void PdfToPng() {
-    std::string pdf_data;
-    ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data));
-
     int num_pages;
     double max_width_in_points = 0;
-    void* pdf_handle = nullptr;
+    std::vector<uint8_t> bitmap_data;
+    double total_height_in_pixels = 0;
+    std::string pdf_data;
+
+    ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data));
     ASSERT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_data.data(), pdf_data.size(),
-                                          &num_pages, &max_width_in_points,
-                                          &pdf_handle));
+                                          &num_pages, &max_width_in_points));
+
     ASSERT_GT(num_pages, 0);
     double max_width_in_pixels =
         ConvertUnitDouble(max_width_in_points, kPointsPerInch, kDpi);
 
-    std::vector<uint8_t> bitmap_data;
-    double total_height_in_pixels = 0;
     for (int i = 0; i < num_pages; ++i) {
       double width_in_points, height_in_points;
       ASSERT_TRUE(chrome_pdf::GetPDFPageSizeByIndex(
-          pdf_handle, i, &width_in_points, &height_in_points));
+          pdf_data.data(), pdf_data.size(), i, &width_in_points,
+          &height_in_points));
 
       double width_in_pixels = ConvertUnitDouble(
           width_in_points, kPointsPerInch, kDpi);
@@ -384,8 +384,9 @@
                                             settings.area.size().GetArea());
 
       ASSERT_TRUE(chrome_pdf::RenderPDFPageToBitmap(
-          pdf_handle, i, page_bitmap_data.data(), settings.area.size().width(),
-          settings.area.size().height(), settings.dpi, settings.autorotate));
+          pdf_data.data(), pdf_data.size(), i, page_bitmap_data.data(),
+          settings.area.size().width(), settings.area.size().height(),
+          settings.dpi, settings.autorotate));
       FillPng(&page_bitmap_data, width_in_pixels, max_width_in_pixels,
               settings.area.size().height());
       bitmap_data.insert(bitmap_data.end(),
@@ -393,7 +394,6 @@
                          page_bitmap_data.end());
     }
 
-    chrome_pdf::ReleasePDFHandle(pdf_handle);
     CreatePng(bitmap_data, max_width_in_pixels, total_height_in_pixels);
   }
 
diff --git a/chrome/browser/resources/settings/people_page/import_data_dialog.html b/chrome/browser/resources/settings/people_page/import_data_dialog.html
index b3a0420..dbe888f5 100644
--- a/chrome/browser/resources/settings/people_page/import_data_dialog.html
+++ b/chrome/browser/resources/settings/people_page/import_data_dialog.html
@@ -34,7 +34,7 @@
         width: 100%;
       }
     </style>
-    <dialog is="cr-dialog" id="dialog">
+    <dialog is="cr-dialog" id="dialog" ignore-popstate>
       <div class="title">$i18n{importTitle}</div>
       <div class="body">
         <div hidden$="[[!hasImportStatus_(
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index caed578f..ca88541 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -21,8 +21,8 @@
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
index bbe5c1a..c1af322 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host_unittest.cc
@@ -20,9 +20,9 @@
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/test_database_manager.h"
 #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/safe_browsing/client_side_detection_service.cc b/chrome/browser/safe_browsing/client_side_detection_service.cc
index b6ffc666..df4e6e5 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service.cc
@@ -22,9 +22,9 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/client_model.pb.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
diff --git a/chrome/browser/safe_browsing/client_side_model_loader.cc b/chrome/browser/safe_browsing/client_side_model_loader.cc
index 91bbddf..5519b4108 100644
--- a/chrome/browser/safe_browsing/client_side_model_loader.cc
+++ b/chrome/browser/safe_browsing/client_side_model_loader.cc
@@ -16,11 +16,11 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/browser/safe_browsing/protocol_manager.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/safe_browsing/client_model.pb.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/variations/variations_associated_data.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
@@ -195,7 +195,7 @@
 
 void ModelLoader::ScheduleFetch(int64_t delay_ms) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSbDisableAutoUpdate))
+          safe_browsing::switches::kSbDisableAutoUpdate))
     return;
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 4d882c2..1aa5e7f 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/safe_browsing/sandboxed_zip_analyzer.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
@@ -52,6 +51,7 @@
 #include "components/google/core/browser/google_util.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item.h"
@@ -1538,11 +1538,12 @@
 
 void DownloadProtectionService::ParseManualBlacklistFlag() {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  if (!command_line->HasSwitch(switches::kSbManualDownloadBlacklist))
+  if (!command_line->HasSwitch(
+          safe_browsing::switches::kSbManualDownloadBlacklist))
     return;
 
-  std::string flag_val =
-      command_line->GetSwitchValueASCII(switches::kSbManualDownloadBlacklist);
+  std::string flag_val = command_line->GetSwitchValueASCII(
+      safe_browsing::switches::kSbManualDownloadBlacklist);
   for (const std::string& hash_hex : base::SplitString(
            flag_val, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
     std::vector<uint8_t> bytes;
@@ -1551,7 +1552,7 @@
           std::string(bytes.begin(), bytes.end()));
     } else {
       LOG(FATAL) << "Bad sha256 hex value '" << hash_hex << "' found in --"
-                 << switches::kSbManualDownloadBlacklist;
+                 << safe_browsing::switches::kSbManualDownloadBlacklist;
     }
   }
 }
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index ab42fed4..1b44858b 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -33,13 +33,13 @@
 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
 #include "chrome/browser/safe_browsing/local_database_manager.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "chrome/common/safe_browsing/file_type_policies_test_util.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "components/safe_browsing_db/test_database_manager.h"
@@ -2252,7 +2252,7 @@
     blacklisted_hash_ = std::string(bytes.begin(), bytes.end());
 
     base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
-        switches::kSbManualDownloadBlacklist,
+        safe_browsing::switches::kSbManualDownloadBlacklist,
         blacklisted_hash_hex_);
 
     DownloadProtectionServiceTest::SetUp();
diff --git a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
index 181c88b..49b194f1 100644
--- a/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/last_download_finder_unittest.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
 #include "chrome/test/base/testing_browser_process.h"
diff --git a/chrome/browser/safe_browsing/local_database_manager.cc b/chrome/browser/safe_browsing/local_database_manager.cc
index 47a05bb..615a7b60 100644
--- a/chrome/browser/safe_browsing/local_database_manager.cc
+++ b/chrome/browser/safe_browsing/local_database_manager.cc
@@ -28,11 +28,11 @@
 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
-#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "components/safe_browsing_db/util.h"
 #include "components/safe_browsing_db/v4_protocol_manager_util.h"
@@ -287,20 +287,20 @@
   DCHECK(sb_service_.get() != NULL);
 
   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  enable_download_protection_ =
-      !cmdline->HasSwitch(switches::kSbDisableDownloadProtection);
+  enable_download_protection_ = !cmdline->HasSwitch(
+      safe_browsing::switches::kSbDisableDownloadProtection);
 
   // We only download the csd-whitelist if client-side phishing detection is
   // enabled.
   enable_csd_whitelist_ =
-      !cmdline->HasSwitch(switches::kDisableClientSidePhishingDetection);
+      !cmdline->HasSwitch(::switches::kDisableClientSidePhishingDetection);
 
   // We download the download-whitelist if download protection is enabled.
   enable_download_whitelist_ = enable_download_protection_;
 
   // TODO(kalman): there really shouldn't be a flag for this.
-  enable_extension_blacklist_ =
-      !cmdline->HasSwitch(switches::kSbDisableExtensionBlacklist);
+  enable_extension_blacklist_ = !cmdline->HasSwitch(
+      safe_browsing::switches::kSbDisableExtensionBlacklist);
 
   // The client-side IP blacklist feature is tightly integrated with client-side
   // phishing protection for now.
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index a5aa510..b755372d 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -29,14 +29,14 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/safe_browsing/ping_manager.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
-#include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
-#include "chrome/common/url_constants.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_constants.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/safe_browsing_prefs.h"
 #include "components/safe_browsing_db/v4_get_hash_protocol_manager.h"
@@ -269,7 +269,7 @@
   base::FilePath path;
   bool result = PathService::Get(chrome::DIR_USER_DATA, &path);
   DCHECK(result);
-  return path.Append(chrome::kSafeBrowsingBaseFilename);
+  return path.Append(safe_browsing::kSafeBrowsingBaseFilename);
 }
 
 
@@ -470,8 +470,8 @@
 
   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
   config.disable_auto_update =
-      cmdline->HasSwitch(switches::kSbDisableAutoUpdate) ||
-      cmdline->HasSwitch(switches::kDisableBackgroundNetworking);
+      cmdline->HasSwitch(safe_browsing::switches::kSbDisableAutoUpdate) ||
+      cmdline->HasSwitch(::switches::kDisableBackgroundNetworking);
   config.url_prefix = kSbDefaultURLPrefix;
   config.backup_connect_error_url_prefix = kSbBackupConnectErrorURLPrefix;
   config.backup_http_error_url_prefix = kSbBackupHttpErrorURLPrefix;
@@ -485,7 +485,7 @@
   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
   return V4ProtocolConfig(
       GetProtocolConfigClientName(),
-      cmdline->HasSwitch(switches::kDisableBackgroundNetworking),
+      cmdline->HasSwitch(::switches::kDisableBackgroundNetworking),
       google_apis::GetAPIKey(), SafeBrowsingProtocolManagerHelper::Version());
 }
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index cafd60320..de76e8f 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -43,13 +43,13 @@
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/bookmarks/browser/startup_task_runner_service.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "components/safe_browsing_db/database_manager.h"
 #include "components/safe_browsing_db/metadata.pb.h"
 #include "components/safe_browsing_db/test_database_manager.h"
@@ -545,7 +545,7 @@
     // Makes sure the auto update is not triggered during the test.
     // This test will fill up the database using testing prefixes
     // and urls.
-    command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
+    command_line->AppendSwitch(safe_browsing::switches::kSbDisableAutoUpdate);
 #if defined(OS_CHROMEOS)
     command_line->AppendSwitch(
         chromeos::switches::kIgnoreUserProfileMappingForTests);
diff --git a/chrome/browser/safe_browsing/threat_details.cc b/chrome/browser/safe_browsing/threat_details.cc
index faba4da..d134b30 100644
--- a/chrome/browser/safe_browsing/threat_details.cc
+++ b/chrome/browser/safe_browsing/threat_details.cc
@@ -17,7 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/safe_browsing/threat_details_cache.h"
 #include "chrome/browser/safe_browsing/threat_details_history.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 331ebda..301048e 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -18,11 +18,11 @@
 #include "chrome/browser/safe_browsing/threat_details_history.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/history/core/browser/history_backend.h"
 #include "components/history/core/browser/history_service.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/web_contents_tester.h"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 49a9555c..d6f6705 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3220,6 +3220,7 @@
       sources += [
         "app_list/arc/arc_app_context_menu.cc",
         "app_list/arc/arc_app_context_menu.h",
+        "app_list/arc/arc_app_dialog.h",
         "app_list/arc/arc_app_icon.cc",
         "app_list/arc/arc_app_icon.h",
         "app_list/arc/arc_app_icon_loader.cc",
@@ -3260,6 +3261,7 @@
         "ash/launcher/arc_launcher_context_menu.h",
         "ash/launcher/launcher_arc_app_updater.cc",
         "ash/launcher/launcher_arc_app_updater.h",
+        "views/arc_app_dialog_view.cc",
       ]
     }
     if (is_desktop_linux) {
diff --git a/chrome/browser/ui/app_list/arc/arc_app_context_menu.cc b/chrome/browser/ui/app_list/arc/arc_app_context_menu.cc
index ea1dd53e..961673c4 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_context_menu.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_context_menu.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/ui/app_list/arc/arc_app_context_menu.h"
 
+#include "base/bind.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/app_context_menu_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_dialog.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
@@ -82,7 +84,7 @@
           ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(app_id()));
       break;
     case UNINSTALL:
-      UninstallPackage();
+      arc::ShowArcAppUninstallDialog(profile(), controller(), app_id());
       break;
     case SHOW_APP_INFO:
       ShowPackageInfo();
@@ -92,23 +94,6 @@
   }
 }
 
-void ArcAppContextMenu::UninstallPackage() {
-  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile());
-  DCHECK(arc_prefs);
-  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
-      arc_prefs->GetApp(app_id());
-  if (!app_info) {
-    VLOG(2) << "Package being uninstalled does not exist: " << app_id() << ".";
-    return;
-  }
-  if (app_info->shortcut) {
-    // for shortcut we just remove the shortcut instead of the package
-    arc_prefs->RemoveApp(app_id());
-  } else {
-    arc::UninstallPackage(app_info->package_name);
-  }
-}
-
 void ArcAppContextMenu::ShowPackageInfo() {
   const ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile());
   DCHECK(arc_prefs);
diff --git a/chrome/browser/ui/app_list/arc/arc_app_context_menu.h b/chrome/browser/ui/app_list/arc/arc_app_context_menu.h
index 2cf39f4..e57352b 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_context_menu.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_context_menu.h
@@ -34,7 +34,6 @@
 
  private:
   void IsAppOpen();
-  void UninstallPackage();
   void ShowPackageInfo();
 
   DISALLOW_COPY_AND_ASSIGN(ArcAppContextMenu);
diff --git a/chrome/browser/ui/app_list/arc/arc_app_dialog.h b/chrome/browser/ui/app_list/arc/arc_app_dialog.h
new file mode 100644
index 0000000..e6e5476
--- /dev/null
+++ b/chrome/browser/ui/app_list/arc/arc_app_dialog.h
@@ -0,0 +1,31 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_DIALOG_H_
+#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_DIALOG_H_
+
+#include <string>
+
+#include "base/callback.h"
+
+class AppListControllerDelegate;
+class Profile;
+
+namespace arc {
+
+// Shows a dialog for user to confirm uninstallation of Arc app.
+// Currently, Arc app can only be manually uninstalled from AppList. But it
+// would be simple to enable the dialog to shown from other source.
+void ShowArcAppUninstallDialog(Profile* profile,
+                               AppListControllerDelegate* controller,
+                               const std::string& app_id);
+
+// Test purpose methods.
+bool IsArcAppDialogViewAliveForTest();
+
+bool CloseAppDialogViewAndConfirmForTest(bool confirm);
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_APP_DIALOG_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.cc b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
index 12b6727..2477258 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.cc
@@ -12,6 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/values.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -392,6 +393,22 @@
   app_instance->UninstallPackage(package_name);
 }
 
+void UninstallArcApp(const std::string& app_id, Profile* profile) {
+  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile);
+  DCHECK(arc_prefs);
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      arc_prefs->GetApp(app_id);
+  if (!app_info) {
+    VLOG(2) << "Package being uninstalled does not exist: " << app_id << ".";
+    return;
+  }
+  // For shortcut we just remove the shortcut instead of the package.
+  if (app_info->shortcut)
+    arc_prefs->RemoveApp(app_id);
+  else
+    UninstallPackage(app_info->package_name);
+}
+
 void RemoveCachedIcon(const std::string& icon_resource_id) {
   VLOG(2) << "Removing icon " << icon_resource_id;
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_utils.h b/chrome/browser/ui/app_list/arc/arc_app_utils.h
index 389a0537..103f208 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_utils.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_utils.h
@@ -11,6 +11,8 @@
 #include "components/arc/common/app.mojom.h"
 #include "ui/gfx/geometry/rect.h"
 
+class Profile;
+
 namespace content {
 class BrowserContext;
 }
@@ -70,6 +72,9 @@
 // Uninstalls the package in ARC.
 void UninstallPackage(const std::string& package_name);
 
+// Uninstalls Arc app or removes shortcut.
+void UninstallArcApp(const std::string& app_id, Profile* profile);
+
 // Removes cached app shortcut icon in ARC.
 void RemoveCachedIcon(const std::string& icon_resource_id);
 
diff --git a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
index 44c9f59..1373245 100644
--- a/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.mm
@@ -106,12 +106,12 @@
     case FullscreenToolbarStyle::TOOLBAR_NONE:
       return kHideFraction;
     case FullscreenToolbarStyle::TOOLBAR_HIDDEN:
-      if ([self mustShowFullscreenToolbar])
-        return kShowFraction;
-
       if (animationController_->IsAnimationRunning())
         return animationController_->GetToolbarFractionFromProgress();
 
+      if ([self mustShowFullscreenToolbar])
+        return kShowFraction;
+
       return [menubarTracker_ menubarFraction];
   }
 }
diff --git a/chrome/browser/ui/views/arc_app_dialog_view.cc b/chrome/browser/ui/views/arc_app_dialog_view.cc
new file mode 100644
index 0000000..e18be654
--- /dev/null
+++ b/chrome/browser/ui/views/arc_app_dialog_view.cc
@@ -0,0 +1,292 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_dialog.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/extensions/extension_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "chrome/browser/ui/native_window_tracker.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/image_view.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/layout_constants.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace arc {
+
+namespace {
+
+const int kRightColumnWidth = 210;
+const int kIconSize = 64;
+
+using ArcAppConfirmCallback =
+    base::Callback<void(const std::string& app_id, Profile* profile)>;
+
+class ArcAppDialogView : public views::DialogDelegateView,
+                         public AppIconLoaderDelegate {
+ public:
+  ArcAppDialogView(Profile* profile,
+                   AppListControllerDelegate* controller,
+                   const std::string& app_id,
+                   const base::string16& window_title,
+                   const base::string16& heading_text,
+                   const base::string16& confirm_button_text,
+                   const base::string16& cancel_button_text,
+                   ArcAppConfirmCallback confirm_callback);
+  ~ArcAppDialogView() override;
+
+  // Public method used for test only.
+  void ConfirmOrCancelForTest(bool confirm);
+
+ private:
+  // views::WidgetDelegate:
+  base::string16 GetWindowTitle() const override;
+  void DeleteDelegate() override;
+  ui::ModalType GetModalType() const override;
+
+  // views::View:
+  gfx::Size GetPreferredSize() const override;
+  void Layout() override;
+
+  // views::DialogDelegate:
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  bool Accept() override;
+
+  // AppIconLoaderDelegate:
+  void OnAppImageUpdated(const std::string& app_id,
+                         const gfx::ImageSkia& image) override;
+
+  // Constructs and shows the modal dialog widget.
+  void Show();
+
+  bool initial_setup_ = true;
+
+  views::ImageView* icon_view_ = nullptr;
+  views::Label* heading_view_ = nullptr;
+
+  std::unique_ptr<ArcAppIconLoader> icon_loader_;
+
+  Profile* const profile_;
+
+  AppListControllerDelegate* controller_;
+
+  gfx::NativeWindow parent_;
+
+  // Tracks whether |parent_| got destroyed.
+  std::unique_ptr<NativeWindowTracker> parent_window_tracker_;
+
+  const std::string app_id_;
+  const base::string16 window_title_;
+  const base::string16 confirm_button_text_;
+  const base::string16 cancel_button_text_;
+  ArcAppConfirmCallback confirm_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppDialogView);
+};
+
+// Browertest use only. Global pointer of ArcAppDialogView which is shown.
+ArcAppDialogView* g_current_arc_app_dialog_view = nullptr;
+
+ArcAppDialogView::ArcAppDialogView(Profile* profile,
+                                   AppListControllerDelegate* controller,
+                                   const std::string& app_id,
+                                   const base::string16& window_title,
+                                   const base::string16& heading_text,
+                                   const base::string16& confirm_button_text,
+                                   const base::string16& cancel_button_text,
+                                   ArcAppConfirmCallback confirm_callback)
+    : profile_(profile),
+      controller_(controller),
+      app_id_(app_id),
+      window_title_(window_title),
+      confirm_button_text_(confirm_button_text),
+      cancel_button_text_(cancel_button_text),
+      confirm_callback_(confirm_callback) {
+  DCHECK(controller);
+  parent_ = controller_->GetAppListWindow();
+  if (parent_)
+    parent_window_tracker_ = NativeWindowTracker::Create(parent_);
+
+  icon_view_ = new views::ImageView();
+  icon_view_->SetImageSize(gfx::Size(kIconSize, kIconSize));
+  AddChildView(icon_view_);
+
+  heading_view_ = new views::Label(heading_text);
+  heading_view_->SetMultiLine(true);
+  heading_view_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  heading_view_->SetAllowCharacterBreak(true);
+  AddChildView(heading_view_);
+
+  icon_loader_.reset(new ArcAppIconLoader(profile_, kIconSize, this));
+  // The dialog will show once the icon is loaded.
+  icon_loader_->FetchImage(app_id_);
+}
+
+ArcAppDialogView::~ArcAppDialogView() {
+  DCHECK_EQ(this, g_current_arc_app_dialog_view);
+  g_current_arc_app_dialog_view = nullptr;
+}
+
+void ArcAppDialogView::ConfirmOrCancelForTest(bool confirm) {
+  if (confirm)
+    Accept();
+  else
+    Cancel();
+  GetWidget()->Close();
+}
+
+base::string16 ArcAppDialogView::GetWindowTitle() const {
+  return window_title_;
+}
+
+void ArcAppDialogView::DeleteDelegate() {
+  if (controller_)
+    controller_->OnCloseChildDialog();
+  DialogDelegateView::DeleteDelegate();
+}
+
+ui::ModalType ArcAppDialogView::GetModalType() const {
+  return ui::MODAL_TYPE_WINDOW;
+}
+
+// TODO(lgcheng@) The code below is copied from
+// ExtensionUninstallDialogDelegateView sizing and layout code. Use
+// LayoutManager to relace these manual layout. See crbug.com/670110.
+gfx::Size ArcAppDialogView::GetPreferredSize() const {
+  int width = kRightColumnWidth;
+  width += kIconSize;
+  width += views::kButtonHEdgeMarginNew * 2;
+  width += views::kRelatedControlHorizontalSpacing;
+
+  int height = views::kPanelVertMargin * 2;
+  height += heading_view_->GetHeightForWidth(kRightColumnWidth);
+
+  return gfx::Size(width,
+                   std::max(height, kIconSize + views::kPanelVertMargin * 2));
+}
+
+void ArcAppDialogView::Layout() {
+  int x = views::kButtonHEdgeMarginNew;
+  int y = views::kPanelVertMargin;
+
+  heading_view_->SizeToFit(kRightColumnWidth);
+
+  if (heading_view_->height() <= kIconSize) {
+    icon_view_->SetBounds(x, y, kIconSize, kIconSize);
+    x += kIconSize;
+    x += views::kRelatedControlHorizontalSpacing;
+
+    heading_view_->SetX(x);
+    heading_view_->SetY(y + (kIconSize - heading_view_->height()) / 2);
+  } else {
+    icon_view_->SetBounds(x, y + (heading_view_->height() - kIconSize) / 2,
+                          kIconSize, kIconSize);
+    x += kIconSize;
+    x += views::kRelatedControlHorizontalSpacing;
+
+    heading_view_->SetX(x);
+    heading_view_->SetY(y);
+  }
+}
+
+base::string16 ArcAppDialogView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  return button == ui::DIALOG_BUTTON_CANCEL ? cancel_button_text_
+                                            : confirm_button_text_;
+}
+
+bool ArcAppDialogView::Accept() {
+  confirm_callback_.Run(app_id_, profile_);
+  return true;
+}
+
+void ArcAppDialogView::OnAppImageUpdated(const std::string& app_id,
+                                         const gfx::ImageSkia& image) {
+  DCHECK_EQ(app_id, app_id_);
+  DCHECK(!image.isNull());
+
+  icon_view_->SetImage(image);
+
+  if (initial_setup_)
+    Show();
+}
+
+void ArcAppDialogView::Show() {
+  initial_setup_ = false;
+
+  // The parent window was killed before the icon was loaded.
+  if (parent_ && parent_window_tracker_->WasNativeWindowClosed()) {
+    Cancel();
+    DialogDelegateView::DeleteDelegate();
+    return;
+  }
+
+  if (controller_)
+    controller_->OnShowChildDialog();
+
+  g_current_arc_app_dialog_view = this;
+  constrained_window::CreateBrowserModalDialogViews(this, parent_)->Show();
+}
+
+}  // namespace
+
+void ShowArcAppUninstallDialog(Profile* profile,
+                               AppListControllerDelegate* controller,
+                               const std::string& app_id) {
+  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile);
+  DCHECK(arc_prefs);
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
+      arc_prefs->GetApp(app_id);
+
+  if (!app_info)
+    return;
+
+  bool is_shortcut = app_info->shortcut;
+
+  base::string16 window_title = l10n_util::GetStringUTF16(
+      is_shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_TITLE
+                  : IDS_APP_UNINSTALL_PROMPT_TITLE);
+
+  base::string16 heading_text = base::UTF8ToUTF16(l10n_util::GetStringFUTF8(
+      is_shortcut ? IDS_EXTENSION_UNINSTALL_PROMPT_HEADING
+                  : IDS_ARC_APP_UNINSTALL_PROMPT_HEADING,
+      base::UTF8ToUTF16(app_info->name)));
+
+  base::string16 confirm_button_text = l10n_util::GetStringUTF16(
+      is_shortcut ? IDS_EXTENSION_PROMPT_UNINSTALL_BUTTON
+                  : IDS_EXTENSION_PROMPT_UNINSTALL_APP_BUTTON);
+
+  base::string16 cancel_button_text = l10n_util::GetStringUTF16(IDS_CANCEL);
+
+  new ArcAppDialogView(profile, controller, app_id, window_title, heading_text,
+                       confirm_button_text, cancel_button_text,
+                       base::Bind(UninstallArcApp));
+}
+
+bool IsArcAppDialogViewAliveForTest() {
+  return g_current_arc_app_dialog_view != nullptr;
+}
+
+bool CloseAppDialogViewAndConfirmForTest(bool confirm) {
+  if (!g_current_arc_app_dialog_view)
+    return false;
+
+  g_current_arc_app_dialog_view->ConfirmOrCancelForTest(confirm);
+  return true;
+}
+
+}  // namespace arc
diff --git a/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc
new file mode 100644
index 0000000..3fd3dc4
--- /dev/null
+++ b/chrome/browser/ui/views/arc_app_dialog_view_browsertest.cc
@@ -0,0 +1,183 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/app_list/arc/arc_app_dialog.h"
+
+#include "base/command_line.h"
+#include "base/macros.h"
+#include "chrome/browser/chromeos/arc/arc_session_manager.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
+#include "chrome/browser/ui/app_list/app_list_service.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/chromeos_switches.h"
+#include "components/arc/arc_bridge_service.h"
+#include "components/arc/common/app.mojom.h"
+#include "components/arc/test/fake_app_instance.h"
+#include "content/public/test/test_utils.h"
+
+namespace arc {
+
+class ArcAppUninstallDialogViewBrowserTest : public InProcessBrowserTest {
+ public:
+  ArcAppUninstallDialogViewBrowserTest() {}
+
+  // InProcessBrowserTest:
+  ~ArcAppUninstallDialogViewBrowserTest() override {}
+
+  void SetUpAppInstance() {
+    profile_ = browser()->profile();
+
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        chromeos::switches::kEnableArc);
+
+    // A valid |arc_app_list_prefs_| is needed for the Arc bridge service and
+    // the Arc session manager.
+    arc_app_list_pref_ = ArcAppListPrefs::Get(profile_);
+    if (!arc_app_list_pref_) {
+      ArcAppListPrefsFactory::GetInstance()->RecreateServiceInstanceForTesting(
+          profile_);
+    }
+
+    DCHECK(ArcBridgeService::Get());
+    ArcSessionManager* session_manager = ArcSessionManager::Get();
+    DCHECK(session_manager);
+    ArcSessionManager::DisableUIForTesting();
+    session_manager->OnPrimaryUserProfilePrepared(profile_);
+    session_manager->EnableArc();
+
+    arc_app_list_pref_ = ArcAppListPrefs::Get(profile_);
+    DCHECK(arc_app_list_pref_);
+
+    base::RunLoop run_loop;
+    arc_app_list_pref_->SetDefaltAppsReadyCallback(run_loop.QuitClosure());
+    run_loop.Run();
+
+    app_instance_.reset(new arc::FakeAppInstance(arc_app_list_pref_));
+    arc_app_list_pref_->app_instance_holder()->SetInstance(app_instance_.get());
+
+    // In this setup, we have one app and one shortcut which share one package.
+    mojom::AppInfo app;
+    app.name = base::StringPrintf("Fake App %d", 0);
+    app.package_name = base::StringPrintf("fake.package.%d", 0);
+    app.activity = base::StringPrintf("fake.app.%d.activity", 0);
+    app.sticky = false;
+    app_instance_->SendRefreshAppList(std::vector<mojom::AppInfo>(1, app));
+
+    mojom::ShortcutInfo shortcut;
+    shortcut.name = base::StringPrintf("Fake Shortcut %d", 0);
+    shortcut.package_name = base::StringPrintf("fake.package.%d", 0);
+    shortcut.intent_uri = base::StringPrintf("Fake Shortcut uri %d", 0);
+    app_instance_->SendInstallShortcut(shortcut);
+
+    mojom::ArcPackageInfo package;
+    package.package_name = base::StringPrintf("fake.package.%d", 0);
+    package.package_version = 0;
+    package.last_backup_android_id = 0;
+    package.last_backup_time = 0;
+    package.sync = false;
+    app_instance_->SendRefreshPackageList(
+        std::vector<mojom::ArcPackageInfo>(1, package));
+  }
+
+  void TearDownOnMainThread() override {
+    ArcSessionManager::Get()->Shutdown();
+    InProcessBrowserTest::TearDownOnMainThread();
+  }
+
+  // Ensures the ArcAppDialogView is destoryed.
+  void TearDown() override { ASSERT_FALSE(IsArcAppDialogViewAliveForTest()); }
+
+  ArcAppListPrefs* arc_app_list_pref() { return arc_app_list_pref_; }
+
+  FakeAppInstance* instance() { return app_instance_.get(); }
+
+ private:
+  ArcAppListPrefs* arc_app_list_pref_ = nullptr;
+
+  Profile* profile_ = nullptr;
+
+  std::unique_ptr<arc::FakeAppInstance> app_instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcAppUninstallDialogViewBrowserTest);
+};
+
+// User confirms/cancels Arc app uninstall. Note that the shortcut is removed
+// when the app and the package are uninstalled since the shortcut and the app
+// share same package.
+IN_PROC_BROWSER_TEST_F(ArcAppUninstallDialogViewBrowserTest,
+                       UserConfirmsUninstall) {
+  SetUpAppInstance();
+
+  std::vector<std::string> app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 2u);
+  std::string package_name = base::StringPrintf("fake.package.%d", 0);
+  std::string app_activity = base::StringPrintf("fake.app.%d.activity", 0);
+  std::string app_id =
+      arc_app_list_pref()->GetAppId(package_name, app_activity);
+
+  AppListService* service = AppListService::Get();
+  ASSERT_TRUE(service);
+  service->ShowForProfile(browser()->profile());
+  AppListControllerDelegate* controller(service->GetControllerDelegate());
+  ASSERT_TRUE(controller);
+  ShowArcAppUninstallDialog(browser()->profile(), controller, app_id);
+  content::RunAllPendingInMessageLoop();
+
+  EXPECT_TRUE(CloseAppDialogViewAndConfirmForTest(false));
+  content::RunAllPendingInMessageLoop();
+  app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 2u);
+
+  ShowArcAppUninstallDialog(browser()->profile(), controller, app_id);
+  content::RunAllPendingInMessageLoop();
+
+  EXPECT_TRUE(CloseAppDialogViewAndConfirmForTest(true));
+  content::RunAllPendingInMessageLoop();
+  app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 0u);
+  controller->DismissView();
+}
+
+// User confirms/cancels Arc app shortcut removal. Note that the app is not
+// uninstalled when the shortcut is removed.
+IN_PROC_BROWSER_TEST_F(ArcAppUninstallDialogViewBrowserTest,
+                       UserConfirmsUninstallShortcut) {
+  SetUpAppInstance();
+
+  std::vector<std::string> app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 2u);
+  std::string package_name = base::StringPrintf("fake.package.%d", 0);
+  std::string intent_uri = base::StringPrintf("Fake Shortcut uri %d", 0);
+  std::string app_id = arc_app_list_pref()->GetAppId(package_name, intent_uri);
+
+  AppListService* service = AppListService::Get();
+  ASSERT_TRUE(service);
+  service->ShowForProfile(browser()->profile());
+  AppListControllerDelegate* controller(service->GetControllerDelegate());
+  ASSERT_TRUE(controller);
+  ShowArcAppUninstallDialog(browser()->profile(), controller, app_id);
+  content::RunAllPendingInMessageLoop();
+
+  EXPECT_TRUE(CloseAppDialogViewAndConfirmForTest(false));
+  content::RunAllPendingInMessageLoop();
+  app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 2u);
+
+  ShowArcAppUninstallDialog(browser()->profile(), controller, app_id);
+  content::RunAllPendingInMessageLoop();
+
+  EXPECT_TRUE(CloseAppDialogViewAndConfirmForTest(true));
+  content::RunAllPendingInMessageLoop();
+  app_ids = arc_app_list_pref()->GetAppIds();
+  EXPECT_EQ(app_ids.size(), 1u);
+  controller->DismissView();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 52d3b4b..3cecca312 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -86,10 +86,6 @@
 const int kMaximizedWindowInset = 10;  // DIPs.
 
 #if defined(USE_ASH)
-void SetWindowPositionManaged(gfx::NativeWindow window, bool value) {
-  ash::wm::GetWindowState(window)->set_window_position_managed(value);
-}
-
 // Returns true if |tab_strip| browser window is docked.
 bool IsDockedOrSnapped(const TabStrip* tab_strip) {
   DCHECK(tab_strip);
@@ -98,9 +94,6 @@
   return window_state->IsDocked() || window_state->IsSnapped();
 }
 #else
-void SetWindowPositionManaged(gfx::NativeWindow window, bool value) {
-}
-
 bool IsDockedOrSnapped(const TabStrip* tab_strip) {
   return false;
 }
@@ -137,18 +130,6 @@
     (*rects)[i].set_x((*rects)[i].x() + x_offset);
 }
 
-// WidgetObserver implementation that resets the window position managed
-// property on Show.
-// We're forced to do this here since BrowserFrameAsh resets the 'window
-// position managed' property during a show and we need the property set to
-// false before WorkspaceLayoutManager sees the visibility change.
-class WindowPositionManagedUpdater : public views::WidgetObserver {
- public:
-  void OnWidgetVisibilityChanged(views::Widget* widget, bool visible) override {
-    SetWindowPositionManaged(widget->GetNativeWindow(), false);
-  }
-};
-
 // EscapeTracker installs an event monitor and runs a callback when it receives
 // the escape key.
 class EscapeTracker : public ui::EventHandler {
@@ -236,7 +217,6 @@
   if (move_loop_widget_) {
     if (added_observer_to_move_loop_widget_)
       move_loop_widget_->RemoveObserver(this);
-    SetWindowPositionManaged(move_loop_widget_->GetNativeWindow(), true);
   }
 
   if (source_tabstrip_)
@@ -616,10 +596,6 @@
     else
       target_tabstrip->GetWidget()->SetCapture(attached_tabstrip_);
 
-    // The window is going away. Since the drag is still on going we don't want
-    // that to effect the position of any windows.
-    SetWindowPositionManaged(browser_widget->GetNativeWindow(), false);
-
 #if !defined(OS_LINUX) || defined(OS_CHROMEOS)
     // EndMoveLoop is going to snap the window back to its original location.
     // Hide it so users don't see this. Hiding a window in Linux aura causes
@@ -1059,10 +1035,7 @@
   AdjustBrowserAndTabBoundsForDrag(last_tabstrip_width,
                                    point_in_screen,
                                    &drag_bounds);
-  WindowPositionManagedUpdater updater;
-  dragged_widget->AddObserver(&updater);
   browser->window()->Show();
-  dragged_widget->RemoveObserver(&updater);
   dragged_widget->SetVisibilityChangedAnimationsEnabled(true);
   // Activate may trigger a focus loss, destroying us.
   {
@@ -1113,7 +1086,7 @@
     return;
   if (move_loop_widget_) {
     move_loop_widget_->RemoveObserver(this);
-    move_loop_widget_ = NULL;
+    move_loop_widget_ = nullptr;
   }
   is_dragging_window_ = false;
   waiting_for_run_loop_to_exit_ = false;
@@ -1353,11 +1326,6 @@
   if (is_dragging_window_) {
     waiting_for_run_loop_to_exit_ = true;
 
-    if (type == NORMAL || (type == TAB_DESTROYED && drag_data_.size() > 1)) {
-      SetWindowPositionManaged(GetAttachedBrowserWidget()->GetNativeWindow(),
-                               true);
-    }
-
     // End the nested drag loop.
     GetAttachedBrowserWidget()->EndMoveLoop();
   }
@@ -1768,7 +1736,6 @@
   create_params.initial_bounds = new_bounds;
   Browser* browser = new Browser(create_params);
   is_dragging_new_browser_ = true;
-  SetWindowPositionManaged(browser->window()->GetNativeWindow(), false);
   // If the window is created maximized then the bounds we supplied are ignored.
   // We need to reset them again so they are honored.
   browser->window()->SetBounds(new_bounds);
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 10d8081..0ad1004 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -9,7 +9,9 @@
 #include <algorithm>
 
 #include "base/bind.h"
+#include "base/bind_helpers.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/macros.h"
@@ -796,18 +798,55 @@
 }
 #endif
 
+// Encapsulates waiting for the browser window to become maximized. This is
+// needed for example on Chrome desktop linux, where window maximization is done
+// asynchronously as an event received from a different process.
+class MaximizedBrowserWindowWaiter {
+ public:
+  explicit MaximizedBrowserWindowWaiter(BrowserWindow* window)
+      : window_(window) {}
+  ~MaximizedBrowserWindowWaiter() = default;
+
+  // Blocks until the browser window becomes maximized.
+  void Wait() {
+    if (CheckMaximized())
+      return;
+
+    base::RunLoop run_loop;
+    quit_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+ private:
+  bool CheckMaximized() {
+    if (!window_->IsMaximized()) {
+      base::MessageLoop::current()->task_runner()->PostTask(
+          FROM_HERE, base::Bind(
+              base::IgnoreResult(&MaximizedBrowserWindowWaiter::CheckMaximized),
+              base::Unretained(this)));
+      return false;
+    }
+
+    // Quit the run_loop to end the wait.
+    if (!quit_.is_null())
+      base::ResetAndReturn(&quit_).Run();
+    return true;
+  }
+
+  // The browser window observed by this waiter.
+  BrowserWindow* window_;
+
+  // The waiter's RunLoop quit closure.
+  base::Closure quit_;
+
+  DISALLOW_COPY_AND_ASSIGN(MaximizedBrowserWindowWaiter);
+};
+
 }  // namespace
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
-// TODO(sky,sad): Disabled as it fails due to resize locks with a real
-// compositor. crbug.com/331924
-#define MAYBE_DetachToOwnWindow DISABLED_DetachToOwnWindow
-#else
-#define MAYBE_DetachToOwnWindow DetachToOwnWindow
-#endif
 // Drags from browser to separate window and releases mouse.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
-                       MAYBE_DetachToOwnWindow) {
+                       DetachToOwnWindow) {
   const gfx::Rect initial_bounds(browser()->window()->GetBounds());
   // Add another tab.
   AddTabAndResetBrowser(browser());
@@ -860,9 +899,13 @@
   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX)
-// TODO(sky,sad): Disabled as it fails due to resize locks with a real
-// compositor. crbug.com/331924
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+// TODO(afakhry,varkha): Disabled on Linux as it fails on the bot because
+// setting the window bounds to the work area bounds in
+// DesktopWindowTreeHostX11::SetBounds() always insets it by one pixel in both
+// width and height. This results in considering the source browser window not
+// being full size, and the test is not as expected.
+// crbug.com/626761, crbug.com/331924.
 // TODO(tapted,mblsha): Disabled as the Mac IsMaximized() behavior is not
 // consistent with other platforms. crbug.com/603562
 #define MAYBE_DetachFromFullsizeWindow DISABLED_DetachFromFullsizeWindow
@@ -923,6 +966,7 @@
 
   // Only second window should be maximized.
   EXPECT_FALSE(browser()->window()->IsMaximized());
+  MaximizedBrowserWindowWaiter(new_browser->window()).Wait();
   EXPECT_TRUE(new_browser->window()->IsMaximized());
 
   // The tab strip should no longer have capture because the drag was ended and
@@ -931,9 +975,7 @@
   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX)
-// TODO(sky,sad): Disabled as it fails due to resize locks with a real
-// compositor. crbug.com/331924
+#if defined(OS_MACOSX)
 // TODO(tapted,mblsha): Disabled as the Mac IsMaximized() behavior is not
 // consistent with other platforms. crbug.com/603562
 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
@@ -947,6 +989,7 @@
                        MAYBE_DetachToOwnWindowFromMaximizedWindow) {
   // Maximize the initial browser window.
   browser()->window()->Maximize();
+  MaximizedBrowserWindowWaiter(browser()->window()).Wait();
   ASSERT_TRUE(browser()->window()->IsMaximized());
 
   // Add another tab.
@@ -990,6 +1033,7 @@
       new_browser->window()->GetNativeWindow()));
 
   // The new window should be maximized.
+  MaximizedBrowserWindowWaiter(new_browser->window()).Wait();
   EXPECT_TRUE(new_browser->window()->IsMaximized());
 }
 
@@ -2429,7 +2473,7 @@
 
 // Drags from browser to separate window, docks that window and releases mouse.
 IN_PROC_BROWSER_TEST_P(DetachToBrowserTabDragControllerTest,
-                       DISABLED_DetachToDockedWindowFromMaximizedWindow) {
+                       DetachToDockedWindowFromMaximizedWindow) {
   // Maximize the initial browser window.
   browser()->window()->Maximize();
   ASSERT_TRUE(browser()->window()->IsMaximized());
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index e016c77..4b762851 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -126,7 +126,6 @@
     "render_messages.h",
     "resource_usage_reporter_type_converters.cc",
     "resource_usage_reporter_type_converters.h",
-    "safe_browsing/safebrowsing_messages.h",
     "search/instant_types.cc",
     "search/instant_types.h",
     "search/ntp_logging_events.h",
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index ed6711e..29930ce 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -161,8 +161,6 @@
 const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[] =
     FPL("Protected Preferences");
 const base::FilePath::CharType kReadmeFilename[] = FPL("README");
-const base::FilePath::CharType kSafeBrowsingBaseFilename[] =
-    FPL("Safe Browsing");
 const base::FilePath::CharType kSecurePreferencesFilename[] =
     FPL("Secure Preferences");
 const base::FilePath::CharType kServiceStateFileName[] = FPL("Service State");
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 8c845b5..53a3b71 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -62,7 +62,6 @@
 extern const base::FilePath::CharType kPreviewsOptOutDBFilename[];
 extern const base::FilePath::CharType kProtectedPreferencesFilenameDeprecated[];
 extern const base::FilePath::CharType kReadmeFilename[];
-extern const base::FilePath::CharType kSafeBrowsingBaseFilename[];
 extern const base::FilePath::CharType kSecurePreferencesFilename[];
 extern const base::FilePath::CharType kServiceStateFileName[];
 extern const base::FilePath::CharType kSingletonCookieFilename[];
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 8dfd7855..14a1efcf 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -820,32 +820,6 @@
 // See http://crbug.com/120416 for how to remove this switch.
 const char kSavePageAsMHTML[]               = "save-page-as-mhtml";
 
-// If present, safebrowsing only performs update when
-// SafeBrowsingProtocolManager::ForceScheduleNextUpdate() is explicitly called.
-// This is used for testing only.
-const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update";
-
-// TODO(lzheng): Remove this flag once the feature works fine
-// (http://crbug.com/74848).
-//
-// Disables safebrowsing feature that checks download url and downloads
-// content's hash to make sure the content are not malicious.
-const char kSbDisableDownloadProtection[] =
-    "safebrowsing-disable-download-protection";
-
-// Disables safebrowsing feature that checks for blacklisted extensions.
-const char kSbDisableExtensionBlacklist[] =
-    "safebrowsing-disable-extension-blacklist";
-
-// List of comma-separated sha256 hashes of executable files which the
-// download-protection service should treat as "dangerous."  For a file to
-// show a warning, it also must be considered a dangerous filetype and not
-// be whitelisted otherwise (by signature or URL) and must be on a supported
-// OS. Hashes are in hex. This is used for manual testing when looking
-// for ways to by-pass download protection.
-const char kSbManualDownloadBlacklist[] =
-    "safebrowsing-manual-download-blacklist";
-
 // Causes the process to run as a service process.
 const char kServiceProcess[]                = "service";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 61c2139d..7d12de903 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -235,10 +235,6 @@
 extern const char kRemoteDebuggingTargets[];
 extern const char kRestoreLastSession[];
 extern const char kSavePageAsMHTML[];
-extern const char kSbDisableAutoUpdate[];
-extern const char kSbDisableDownloadProtection[];
-extern const char kSbDisableExtensionBlacklist[];
-extern const char kSbManualDownloadBlacklist[];
 extern const char kServiceProcess[];
 extern const char kShowAppList[];
 extern const char kSilentDebuggerExtensionAPI[];
diff --git a/chrome/common/chrome_utility_printing_messages.h b/chrome/common/chrome_utility_printing_messages.h
index 1f374a75..f1a8ad7 100644
--- a/chrome/common/chrome_utility_printing_messages.h
+++ b/chrome/common/chrome_utility_printing_messages.h
@@ -99,7 +99,7 @@
 // Tell the utility process to start rendering the given PDF into a metafile.
 // Utility process would be alive until
 // ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop message.
-IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Start,
+IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
                      IPC::PlatformFileForTransit /* input_file */,
                      printing::PdfRenderSettings /* settings */,
                      bool /* print_text_with_gdi */)
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h
index 91707a1..553c873 100644
--- a/chrome/common/common_message_generator.h
+++ b/chrome/common/common_message_generator.h
@@ -11,7 +11,6 @@
 #include "chrome/common/page_load_metrics/page_load_metrics_messages.h"
 #include "chrome/common/prerender_messages.h"
 #include "chrome/common/render_messages.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/common/tts_messages.h"
 #include "content/public/common/common_param_traits.h"
 #include "content/public/common/common_param_traits_macros.h"
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 800f7045..db8e714 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -82,6 +82,8 @@
 
 const char kSendAction[] = "sendaction";
 
+const char kNSEvent[] = "nsevent";
+
 }  // namespace mac
 #endif
 
@@ -156,6 +158,7 @@
     { mac::kNSException, kMediumSize },
     { mac::kNSExceptionTrace, kMediumSize },
     { mac::kSendAction, kMediumSize },
+    { mac::kNSEvent, kMediumSize },
     { mac::kZombie, kMediumSize },
     { mac::kZombieTrace, kMediumSize },
     // content/:
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h
index 6f660312..a09783d 100644
--- a/chrome/common/crash_keys.h
+++ b/chrome/common/crash_keys.h
@@ -130,6 +130,9 @@
 // target-action.
 extern const char kSendAction[];
 
+// In the CrApplication, records information about the current event.
+extern const char kNSEvent[];
+
 }  // namespace mac
 #endif
 
diff --git a/chrome/common/extensions/api/certificate_provider.idl b/chrome/common/extensions/api/certificate_provider.idl
index 4062d04..91096d3 100644
--- a/chrome/common/extensions/api/certificate_provider.idl
+++ b/chrome/common/extensions/api/certificate_provider.idl
@@ -13,6 +13,21 @@
     SHA512
   };
 
+  // The type of code being requested by the extension with requestPin function.
+  enum PinRequestType {
+    PIN,
+    PUK
+  };
+
+  // The types of errors that can be presented to the user through the
+  // requestPin function.
+  enum PinRequestErrorType {
+    INVALID_PIN,
+    INVALID_PUK,
+    MAX_ATTEMPTS_EXCEEDED,
+    UNKNOWN_ERROR
+  };
+
   [noinline_doc] dictionary CertificateInfo {
     // Must be the DER encoding of a X.509 certificate. Currently, only
     // certificates of RSA keys are supported.
@@ -25,6 +40,10 @@
   };
 
   [noinline_doc] dictionary SignRequest {
+    // The unique ID to be used by the extension should it need to call a method
+    // that requires it, e.g. requestPin.
+    long signRequestId;
+
     // The digest that must be signed.
     ArrayBuffer digest;
 
@@ -36,6 +55,45 @@
     ArrayBuffer certificate;
   };
 
+  dictionary RequestPinDetails {
+    // The ID given by Chrome in SignRequest.
+    long signRequestId;
+
+    // The type of code requested. Default is PIN.
+    PinRequestType? requestType;
+
+    // The error template displayed to the user. This should be set if the
+    // previous request failed, to notify the user of the failure reason.
+    PinRequestErrorType? errorType;
+
+    // The number of attempts left. This is provided so that any UI can present
+    // this information to the user. Chrome is not expected to enforce this,
+    // instead stopPinRequest should be called by the extension with
+    // errorType = MAX_ATTEMPTS_EXCEEDED when the number of pin requests is
+    // exceeded.
+    long? attemptsLeft;
+  };
+
+  dictionary StopPinRequestDetails {
+    // The ID given by Chrome in SignRequest.
+    long signRequestId;
+
+    // The error template. If present it is displayed to user. Intended to
+    // contain the reason for stopping the flow if it was caused by an error,
+    // e.g. MAX_ATTEMPTS_EXCEEDED.
+    PinRequestErrorType? errorType;
+  };
+
+  dictionary PinResponseDetails {
+    // The code provided by the user. Empty if user closed the dialog or some
+    // other error occurred.
+    DOMString? userInput;
+  };
+
+  callback RequestPinCallback = void (optional PinResponseDetails details);
+
+  callback StopPinRequestCallback = void ();
+
   // The callback provided by the extension that Chrome uses to report back
   // rejected certificates. See <code>CertificatesCallback</code>.
   callback ResultCallback = void (ArrayBuffer[] rejectedCertificates);
@@ -76,4 +134,25 @@
     static void onSignDigestRequested(SignRequest request,
                                       SignCallback reportCallback);
   };
+
+  interface Functions {
+    // Requests the PIN from the user. Only one ongoing request at a time is
+    // allowed. The requests issued while another flow is ongoing are rejected.
+    // It's the extension's responsibility to try again later if another flow is
+    // in progress.
+    // |details|: Contains the details about the requested dialog.
+    // |callback|: Is called when the dialog is resolved with the user input, or
+    // when the dialog request finishes unsuccessfully (e.g. the dialog was
+    // canceled by the user or was not allowed to be shown).
+    static void requestPin(RequestPinDetails details,
+                           RequestPinCallback callback);
+
+    // Stops the pin request started by the $(ref:requestPin) function.
+    // |details|: Contains the details about the reason for stopping the
+    // request flow.
+    // |callback|: To be used by Chrome to send to the extension the status from
+    // their request to close PIN dialog for user.
+    static void stopPinRequest(StopPinRequestDetails details,
+                               StopPinRequestCallback callback);
+  };
 };
diff --git a/chrome/renderer/BUILD.gn b/chrome/renderer/BUILD.gn
index bf7505a..fe44507 100644
--- a/chrome/renderer/BUILD.gn
+++ b/chrome/renderer/BUILD.gn
@@ -189,6 +189,7 @@
       "safe_browsing/threat_dom_details.cc",
       "safe_browsing/threat_dom_details.h",
     ]
+    deps += [ "//components/safe_browsing/common:common" ]
     if (safe_browsing_mode == 1) {
       sources += [
         "safe_browsing/feature_extractor_clock.cc",
diff --git a/chrome/renderer/safe_browsing/DEPS b/chrome/renderer/safe_browsing/DEPS
index a37ca375..ef75e4ec 100644
--- a/chrome/renderer/safe_browsing/DEPS
+++ b/chrome/renderer/safe_browsing/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/safe_browsing/common",
   "+third_party/smhasher",
 ]
 
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
index 3cd2291..704ff2e 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate.cc
@@ -13,10 +13,10 @@
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/renderer/safe_browsing/feature_extractor_clock.h"
 #include "chrome/renderer/safe_browsing/phishing_classifier.h"
 #include "chrome/renderer/safe_browsing/scorer.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/renderer/document_state.h"
 #include "content/public/renderer/navigation_state.h"
 #include "content/public/renderer/render_frame.h"
diff --git a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
index 67ced46..5e5b799 100644
--- a/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
+++ b/chrome/renderer/safe_browsing/phishing_classifier_delegate_browsertest.cc
@@ -8,12 +8,12 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/safe_browsing/csd.pb.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/renderer/safe_browsing/features.h"
 #include "chrome/renderer/safe_browsing/phishing_classifier.h"
 #include "chrome/renderer/safe_browsing/scorer.h"
 #include "chrome/test/base/chrome_render_view_test.h"
 #include "chrome/test/base/chrome_unit_test_suite.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/renderer/safe_browsing/threat_dom_details.cc b/chrome/renderer/safe_browsing/threat_dom_details.cc
index c68b24f5..b2a8ed6 100644
--- a/chrome/renderer/safe_browsing/threat_dom_details.cc
+++ b/chrome/renderer/safe_browsing/threat_dom_details.cc
@@ -5,8 +5,7 @@
 #include "chrome/renderer/safe_browsing/threat_dom_details.h"
 
 #include "base/compiler_specific.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/renderer/render_frame.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
diff --git a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
index bdd68d09..157cefc 100644
--- a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
+++ b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
@@ -7,8 +7,8 @@
 #include <memory>
 
 #include "base/strings/stringprintf.h"
-#include "chrome/common/safe_browsing/safebrowsing_messages.h"
 #include "chrome/test/base/chrome_render_view_test.h"
+#include "components/safe_browsing/common/safebrowsing_messages.h"
 #include "content/public/renderer/render_view.h"
 #include "net/base/escape.h"
 #include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index f2da679..24431254 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -97,7 +97,7 @@
              const printing::PdfRenderSettings& conversion_settings) {
     if (!temp_dir_.CreateUniqueTempDir())
       return false;
-    return host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Start(
+    return host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
         IPC::TakePlatformFileForTransit(std::move(pdf_file)),
         conversion_settings, false /* print_text_with_gdi */));
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 59cfbe6f..e767d1a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2316,6 +2316,7 @@
         "../browser/extensions/api/hotword_private/hotword_private_apitest.cc",
         "../browser/extensions/api/vpn_provider/vpn_provider_apitest.cc",
         "../browser/ui/ash/launcher/arc_app_launcher_browsertest.cc",
+        "../browser/ui/views/arc_app_dialog_view_browsertest.cc",
         "../browser/ui/webui/options/chromeos/accounts_options_browsertest.cc",
         "../browser/ui/webui/options/chromeos/guest_mode_options_browsertest.cc",
         "../browser/ui/webui/options/chromeos/guest_mode_options_ui_browsertest.cc",
diff --git a/chrome/test/base/test_launcher_utils.cc b/chrome/test/base/test_launcher_utils.cc
index 81f9ca4c..8892674 100644
--- a/chrome/test/base/test_launcher_utils.cc
+++ b/chrome/test/base/test_launcher_utils.cc
@@ -16,6 +16,7 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/os_crypt/os_crypt_switches.h"
+#include "components/safe_browsing/common/safebrowsing_switches.h"
 #include "content/public/common/content_switches.h"
 
 #if defined(USE_AURA)
@@ -45,7 +46,7 @@
     command_line->AppendSwitchASCII(switches::kLoggingLevel, "0");  // info
 
   // Disable safebrowsing autoupdate.
-  command_line->AppendSwitch(switches::kSbDisableAutoUpdate);
+  command_line->AppendSwitch(safe_browsing::switches::kSbDisableAutoUpdate);
 
   // Don't install default apps.
   command_line->AppendSwitch(switches::kDisableDefaultApps);
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.html b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.html
new file mode 100644
index 0000000..c107807
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright 2016 The Chromium Authors. All rights reserved.  Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="basic.js"></script>
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.js b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.js
new file mode 100644
index 0000000..8d0d494
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic.js
@@ -0,0 +1,62 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The script requests pin and checks the input. If correct PIN (1234) is
+// provided, the script requests to close the dialog and stops there. If wrong
+// PIN is provided, the request is repeated until the limit of 3 bad tries is
+// reached. If the dialog is closed, the request is repeated without considering
+// it a wrong attempt. This allows the testing of quota limit of closed dialogs
+// (3 closed dialogs per 10 minutes).
+function userInputCallback(codeValue) {
+  if (chrome.runtime.lastError) {
+    // Should end up here only when quota is exceeded.
+    lastError = chrome.runtime.lastError.message;
+    return;
+  }
+
+  if (attempts >= 3) {
+    chrome.test.sendMessage('No attempt left');
+    return;
+  }
+
+  if (!codeValue || !codeValue.userInput) {
+    chrome.certificateProvider.requestPin(
+        {signRequestId: 123}, userInputCallback);
+    chrome.test.sendMessage('User closed the dialog', function(message) {
+      if (message == 'GetLastError') {
+        chrome.test.sendMessage(lastError);
+      }
+    });
+    return;
+  }
+
+  var success = codeValue.userInput == '1234';  // Validate the code.
+  if (success) {
+    chrome.certificateProvider.stopPinRequest(
+        {signRequestId: 123}, closeCallback);
+    chrome.test.sendMessage(lastError == '' ? 'Success' : lastError);
+  } else {
+    attempts++;
+    var code = attempts < 3 ? {signRequestId: 123, errorType: 'INVALID_PIN'} : {
+      signRequestId: 123,
+      requestType: 'PUK',
+      errorType: 'MAX_ATTEMPTS_EXCEEDED',
+      attemptsLeft: 0
+    };
+    chrome.certificateProvider.requestPin(code, userInputCallback);
+    chrome.test.sendMessage(lastError == '' ? 'Invalid PIN' : lastError);
+  }
+}
+
+function closeCallback() {
+  if (chrome.runtime.lastError != null) {
+    console.error('Error: ' + chrome.runtime.lastError.message);
+    lastError = chrome.runtime.lastError.message;
+    return;
+  }
+}
+
+var attempts = 0;
+var lastError = '';
+chrome.certificateProvider.requestPin({signRequestId: 123}, userInputCallback);
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.html b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.html
new file mode 100644
index 0000000..b6108716
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.html
@@ -0,0 +1,6 @@
+<!--
+ * Copyright 2016 The Chromium Authors. All rights reserved.  Use of this
+ * source code is governed by a BSD-style license that can be found in the
+ * LICENSE file.
+-->
+<script src="basic_lock.js"></script>
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.js b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.js
new file mode 100644
index 0000000..738d236f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/basic_lock.js
@@ -0,0 +1,14 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The script requests pin once and never send any other request again. Used to
+// test when the user closes the dialog while request is processing.
+function userInputCallback(codeValue) {
+  if (chrome.runtime.lastError) {
+    console.error('Error: ' + chrome.runtime.lastError.message);
+    return;
+  }
+}
+
+chrome.certificateProvider.requestPin({signRequestId: 123}, userInputCallback);
diff --git a/chrome/test/data/extensions/api_test/certificate_provider/request_pin/manifest.json b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/manifest.json
new file mode 100644
index 0000000..bbf6d2f4
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/certificate_provider/request_pin/manifest.json
@@ -0,0 +1,8 @@
+{
+  "name": "RequestPin tests",
+  "version": "0.1",
+  "manifest_version": 2,
+  "permissions": [
+    "certificateProvider"
+  ]
+}
diff --git a/chrome/utility/printing_handler.cc b/chrome/utility/printing_handler.cc
index 2dc63294..7dbae1a1 100644
--- a/chrome/utility/printing_handler.cc
+++ b/chrome/utility/printing_handler.cc
@@ -64,8 +64,8 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(PrintingHandler, message)
 #if defined(OS_WIN)
-    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Start,
-                        OnRenderPDFPagesToMetafileStart)
+    IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles,
+                        OnRenderPDFPagesToMetafile)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage,
                         OnRenderPDFPagesToMetafileGetPage)
     IPC_MESSAGE_HANDLER(ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop,
@@ -85,7 +85,7 @@
 }
 
 #if defined(OS_WIN)
-void PrintingHandler::OnRenderPDFPagesToMetafileStart(
+void PrintingHandler::OnRenderPDFPagesToMetafile(
     IPC::PlatformFileForTransit pdf_transit,
     const PdfRenderSettings& settings,
     bool print_text_with_gdi) {
@@ -109,8 +109,6 @@
 }
 
 void PrintingHandler::OnRenderPDFPagesToMetafileStop() {
-  chrome_pdf::ReleasePDFHandle(pdf_handle_);
-  pdf_handle_ = nullptr;
   ReleaseProcessIfNeeded();
 }
 
@@ -136,8 +134,6 @@
 
 #if defined(OS_WIN)
 int PrintingHandler::LoadPDF(base::File pdf_file) {
-  DCHECK(!pdf_handle_);
-
   int64_t length64 = pdf_file.GetLength();
   if (length64 <= 0 || length64 > std::numeric_limits<int>::max())
     return 0;
@@ -149,7 +145,7 @@
 
   int total_page_count = 0;
   if (!chrome_pdf::GetPDFDocInfo(&pdf_data_.front(), pdf_data_.size(),
-                                 &total_page_count, nullptr, &pdf_handle_)) {
+                                 &total_page_count, nullptr)) {
     return 0;
   }
   return total_page_count;
@@ -177,7 +173,7 @@
   // to StartPage.
   metafile.StartPage(gfx::Size(), gfx::Rect(), 1);
   if (!chrome_pdf::RenderPDFPageToDC(
-          pdf_handle_, page_number, metafile.context(),
+          &pdf_data_.front(), pdf_data_.size(), page_number, metafile.context(),
           pdf_rendering_settings_.dpi, pdf_rendering_settings_.area.x(),
           pdf_rendering_settings_.area.y(),
           pdf_rendering_settings_.area.width(),
@@ -208,9 +204,8 @@
     return false;
 
   int total_page_count = 0;
-  void* pdf_handle = nullptr;
   if (!chrome_pdf::GetPDFDocInfo(data.data(), data_size, &total_page_count,
-                                 nullptr, &pdf_handle)) {
+                                 nullptr)) {
     return false;
   }
 
@@ -219,14 +214,11 @@
   encoder.EncodeDocumentHeader(&pwg_header);
   int bytes_written = bitmap_file.WriteAtCurrentPos(pwg_header.data(),
                                                     pwg_header.size());
-  if (bytes_written != static_cast<int>(pwg_header.size())) {
-    chrome_pdf::ReleasePDFHandle(pdf_handle);
+  if (bytes_written != static_cast<int>(pwg_header.size()))
     return false;
-  }
 
   cloud_print::BitmapImage image(settings.area.size(),
                                  cloud_print::BitmapImage::BGRA);
-  bool ret = true;
   for (int i = 0; i < total_page_count; ++i) {
     int page_number = i;
 
@@ -235,8 +227,9 @@
     }
 
     if (!chrome_pdf::RenderPDFPageToBitmap(
-            pdf_handle, page_number, image.pixel_data(), image.size().width(),
-            image.size().height(), settings.dpi, settings.autorotate)) {
+            data.data(), data_size, page_number, image.pixel_data(),
+            image.size().width(), image.size().height(), settings.dpi,
+            settings.autorotate)) {
       return false;
     }
 
@@ -268,19 +261,14 @@
     }
 
     std::string pwg_page;
-    if (!encoder.EncodePage(image, header_info, &pwg_page)) {
-      ret = false;
-      break;
-    }
+    if (!encoder.EncodePage(image, header_info, &pwg_page))
+      return false;
     bytes_written = bitmap_file.WriteAtCurrentPos(pwg_page.data(),
                                                   pwg_page.size());
-    if (bytes_written != static_cast<int>(pwg_page.size())) {
-      ret = false;
-      break;
-    }
+    if (bytes_written != static_cast<int>(pwg_page.size()))
+      return false;
   }
-  chrome_pdf::ReleasePDFHandle(pdf_handle);
-  return ret;
+  return true;
 }
 
 void PrintingHandler::OnGetPrinterCapsAndDefaults(
diff --git a/chrome/utility/printing_handler.h b/chrome/utility/printing_handler.h
index 02696d4..99b6eeb 100644
--- a/chrome/utility/printing_handler.h
+++ b/chrome/utility/printing_handler.h
@@ -34,7 +34,7 @@
  private:
   // IPC message handlers.
 #if defined(OS_WIN)
-  void OnRenderPDFPagesToMetafileStart(IPC::PlatformFileForTransit pdf_transit,
+  void OnRenderPDFPagesToMetafile(IPC::PlatformFileForTransit pdf_transit,
                                   const PdfRenderSettings& settings,
                                   bool print_text_with_gdi);
   void OnRenderPDFPagesToMetafileGetPage(
@@ -68,7 +68,6 @@
 #if defined(OS_WIN)
   std::vector<char> pdf_data_;
   PdfRenderSettings pdf_rendering_settings_;
-  void* pdf_handle_ = nullptr;
 #endif
 
   DISALLOW_COPY_AND_ASSIGN(PrintingHandler);
diff --git a/chromecast/browser/cast_media_blocker.cc b/chromecast/browser/cast_media_blocker.cc
index dd92cad..daeca5b 100644
--- a/chromecast/browser/cast_media_blocker.cc
+++ b/chromecast/browser/cast_media_blocker.cc
@@ -11,10 +11,8 @@
 namespace chromecast {
 namespace shell {
 
-CastMediaBlocker::CastMediaBlocker(content::MediaSession* media_session,
-                                   content::WebContents* web_contents)
+CastMediaBlocker::CastMediaBlocker(content::MediaSession* media_session)
     : content::MediaSessionObserver(media_session),
-      content::WebContentsObserver(web_contents),
       blocked_(false),
       paused_by_user_(true),
       suspended_(true),
diff --git a/chromecast/browser/cast_media_blocker.h b/chromecast/browser/cast_media_blocker.h
index 1c3d562..58b3f99 100644
--- a/chromecast/browser/cast_media_blocker.h
+++ b/chromecast/browser/cast_media_blocker.h
@@ -14,14 +14,9 @@
 
 // This class implements a blocking mode for web applications and is used in
 // Chromecast internal code. Media is unblocked by default.
-//
-// TODO(derekjchow): Remove the inheritance from WebContentsObserver.
-// See http://crbug.com/660331
-class CastMediaBlocker : public content::MediaSessionObserver,
-                         content::WebContentsObserver {
+class CastMediaBlocker : public content::MediaSessionObserver {
  public:
-  CastMediaBlocker(content::MediaSession* media_session,
-                   content::WebContents* web_contents);
+  explicit CastMediaBlocker(content::MediaSession* media_session);
   ~CastMediaBlocker() override;
 
   // Sets if the web contents is allowed to play media or not. If media is
diff --git a/chromecast/browser/cast_media_blocker_browsertest.cc b/chromecast/browser/cast_media_blocker_browsertest.cc
index 94a9ddab..5d394de96 100644
--- a/chromecast/browser/cast_media_blocker_browsertest.cc
+++ b/chromecast/browser/cast_media_blocker_browsertest.cc
@@ -44,7 +44,7 @@
     WaitForLoadStop(web_contents_);
 
     blocker_ = base::MakeUnique<CastMediaBlocker>(
-        content::MediaSession::Get(web_contents_), web_contents_);
+        content::MediaSession::Get(web_contents_));
   }
 
   void BlockAndTestPlayerState(const std::string& media_type, bool blocked) {
diff --git a/chromecast/browser/cast_media_blocker_unittest.cc b/chromecast/browser/cast_media_blocker_unittest.cc
index 8bd152e..25d8a322 100644
--- a/chromecast/browser/cast_media_blocker_unittest.cc
+++ b/chromecast/browser/cast_media_blocker_unittest.cc
@@ -54,8 +54,7 @@
     content::RenderViewHostTestHarness::SetUp();
     media_session_ = base::MakeUnique<MockMediaSession>(
         content::MediaSession::Get(web_contents()));
-    media_blocker_ = base::MakeUnique<CastMediaBlocker>(media_session_.get(),
-                                                        web_contents());
+    media_blocker_ = base::MakeUnique<CastMediaBlocker>(media_session_.get());
 
     content::WebContentsTester::For(web_contents())
         ->NavigateAndCommit(GURL("https://www.youtube.com"));
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index b625bd9..718403a 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -148,8 +148,7 @@
   v8::Local<v8::Context> context =
       render_frame->GetWebFrame()->mainWorldScriptContext();
 
-  // CastGinRunner manages its own lifetime.
-  CastGinRunner* runner = new CastGinRunner(render_frame);
+  CastGinRunner* runner = CastGinRunner::Get(render_frame);
   gin::Runner::Scope scoper(runner);
 
   // Initialize AMD API for Mojo.
diff --git a/chromecast/renderer/cast_gin_runner.cc b/chromecast/renderer/cast_gin_runner.cc
index 7d9db16f..ca93bf51 100644
--- a/chromecast/renderer/cast_gin_runner.cc
+++ b/chromecast/renderer/cast_gin_runner.cc
@@ -7,36 +7,45 @@
 #include "content/public/renderer/render_frame.h"
 #include "gin/per_context_data.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebLocalFrame.h"
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 
 namespace chromecast {
 namespace shell {
 
-CastGinRunner::CastGinRunner(content::RenderFrame* render_frame)
-    : content::RenderFrameObserver(render_frame),
-      frame_(render_frame->GetWebFrame()),
-      context_holder_(
-          gin::PerContextData::From(frame_->mainWorldScriptContext())
-              ->context_holder()) {
+namespace {
+const void* kCastContextData;
+const void* kCastGinRunnerKey = static_cast<const void*>(&kCastContextData);
+}
+
+// static
+CastGinRunner* CastGinRunner::Get(content::RenderFrame* render_frame) {
+  DCHECK(render_frame);
+  blink::WebFrame* frame = render_frame->GetWebFrame();
+  v8::HandleScope handle_scope(blink::mainThreadIsolate());
+  gin::PerContextData* context_data =
+      gin::PerContextData::From(frame->mainWorldScriptContext());
+  CastGinRunner* runner =
+      static_cast<CastGinRunner*>(context_data->GetUserData(kCastGinRunnerKey));
+  return runner ? runner : new CastGinRunner(frame, context_data);
+}
+
+CastGinRunner::CastGinRunner(blink::WebFrame* frame,
+                             gin::PerContextData* context_data)
+    : frame_(frame), context_holder_(context_data->context_holder()) {
   DCHECK(frame_);
   DCHECK(context_holder_);
-  gin::PerContextData* context_data =
-      gin::PerContextData::From(frame_->mainWorldScriptContext());
 
-  v8::Isolate::Scope isolate_scope(context_holder_->isolate());
-  v8::HandleScope handle_scope(context_holder_->isolate());
-
-  context_data->SetUserData(kCastContextData, this);
+  // context_data takes ownership of this class.
+  context_data->SetUserData(kCastGinRunnerKey, this);
 
   // Note: this installs the runner globally. If we need to support more than
   // one runner at a time we'll have to revisit this.
   context_data->set_runner(this);
 }
 
-CastGinRunner::~CastGinRunner() {
-  RemoveUserData(render_frame()->GetWebFrame()->mainWorldScriptContext());
-}
+CastGinRunner::~CastGinRunner() {}
 
 void CastGinRunner::Run(const std::string& source,
                         const std::string& resource_name) {
@@ -56,31 +65,5 @@
   return context_holder_;
 }
 
-void CastGinRunner::WillReleaseScriptContext(v8::Local<v8::Context> context,
-                                             int world_id) {
-  RemoveUserDataFromMainWorldContext();
-}
-
-void CastGinRunner::DidClearWindowObject() {
-  RemoveUserDataFromMainWorldContext();
-}
-
-void CastGinRunner::OnDestruct() {
-  RemoveUserDataFromMainWorldContext();
-}
-
-void CastGinRunner::RemoveUserDataFromMainWorldContext() {
-  v8::HandleScope handle_scope(context_holder_->isolate());
-  RemoveUserData(render_frame()->GetWebFrame()->mainWorldScriptContext());
-}
-
-void CastGinRunner::RemoveUserData(v8::Local<v8::Context> context) {
-  gin::PerContextData* context_data = gin::PerContextData::From(context);
-  if (!context_data)
-    return;
-
-  context_data->RemoveUserData(kCastContextData);
-}
-
 }  // namespace shell
 }  // namespace chromecast
diff --git a/chromecast/renderer/cast_gin_runner.h b/chromecast/renderer/cast_gin_runner.h
index 2c1115aa..ac01ab2 100644
--- a/chromecast/renderer/cast_gin_runner.h
+++ b/chromecast/renderer/cast_gin_runner.h
@@ -7,27 +7,30 @@
 
 #include "base/macros.h"
 #include "base/supports_user_data.h"
-#include "content/public/renderer/render_frame_observer.h"
 #include "gin/runner.h"
 
-namespace {
-const char kCastContextData[] = "CastContextData";
-}
-
 namespace blink {
 class WebFrame;
 }
 
+namespace content {
+class RenderFrame;
+}
+
+namespace gin {
+class PerContextData;
+}
+
 namespace chromecast {
 namespace shell {
 
 // Implementation of gin::Runner that forwards Runner functions to WebFrame.
-class CastGinRunner : public gin::Runner,
-                      public base::SupportsUserData::Data,
-                      public content::RenderFrameObserver {
+// This class is lazily created per RenderFrame with the Get function and it's
+// lifetime is managed by the gin::PerContextData associated with the frame.
+class CastGinRunner : public gin::Runner, public base::SupportsUserData::Data {
  public:
-  // Does not take ownership of ContextHolder.
-  CastGinRunner(content::RenderFrame* render_frame);
+  // Gets or creates the CastGinRunner for this RenderFrame
+  static CastGinRunner* Get(content::RenderFrame* render_frame);
   ~CastGinRunner() override;
 
   // gin:Runner implementation:
@@ -39,15 +42,8 @@
                             v8::Local<v8::Value> argv[]) override;
   gin::ContextHolder* GetContextHolder() override;
 
-  // content::RenderFrameObserver implementation:
-  void WillReleaseScriptContext(v8::Local<v8::Context> context,
-                                int world_id) override;
-  void DidClearWindowObject() override;
-  void OnDestruct() override;
-
  private:
-  void RemoveUserDataFromMainWorldContext();
-  void RemoveUserData(v8::Local<v8::Context> context);
+  CastGinRunner(blink::WebFrame* frame, gin::PerContextData* context_data);
 
   // Frame to execute script in.
   blink::WebFrame* const frame_;
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index a15f26d..3ba8227 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -422,6 +422,7 @@
   shared_libraries = [ ":cronet" ]
 
   deps = [
+    ":cronet_combine_proguard_flags",
     ":cronet_sample_apk_java",
     ":cronet_sample_apk_resources",
     "//base:base_java",
@@ -429,15 +430,13 @@
   ]
 
   run_findbugs_override = true
-  if (!is_java_debug) {
-    proguard_enabled = true
-    proguard_configs = [
-      "proguard.cfg",
-      "sample/javatests/proguard.cfg",
-      "//base/android/proguard/chromium_apk.flags",
-      "//base/android/proguard/chromium_code.flags",
-    ]
-  }
+  proguard_enabled = true
+  proguard_configs = [
+    "$target_gen_dir/cronet_impl_native_proguard.cfg",
+    "cronet_impl_common_proguard.cfg",
+    "sample/javatests/proguard.cfg",
+    "//base/android/proguard/chromium_apk.flags",
+  ]
 }
 
 # cronet_sample_test_apk_resources is identical to
@@ -470,7 +469,7 @@
   additional_apks = [ "//net/android:net_test_support_apk" ]
 
   run_findbugs_override = true
-  proguard_enabled = !is_java_debug
+  proguard_enabled = true
 }
 
 generate_jni("cronet_tests_jni_headers") {
@@ -743,6 +742,7 @@
   ]
 
   deps = [
+    ":cronet_combine_proguard_flags",
     ":cronet_perf_test_apk_java",
     ":cronet_test_apk_java",
     "//base:base_java",
@@ -751,10 +751,10 @@
   run_findbugs_override = true
   proguard_enabled = true
   proguard_configs = [
-    "proguard.cfg",
+    "$target_gen_dir/cronet_impl_native_proguard.cfg",
+    "cronet_impl_common_proguard.cfg",
     "test/javaperftests/proguard.cfg",
     "//base/android/proguard/chromium_apk.flags",
-    "//base/android/proguard/chromium_code.flags",
   ]
 }
 
@@ -1021,8 +1021,11 @@
     "$root_out_dir/lib.java/components/cronet/android/cronet_api.jar",
     "$root_out_dir/lib.java/components/cronet/android/cronet_impl_common_java.jar",
     "$root_out_dir/lib.java/components/cronet/android/cronet_impl_platform_java.jar",
+    "$target_gen_dir/cronet_impl_native_proguard.cfg",
     "//AUTHORS",
     "//chrome/VERSION",
+    "cronet_impl_common_proguard.cfg",
+    "cronet_impl_platform_proguard.cfg",
   ]
   outputs = [
     "$_package_dir/{{source_file_part}}",
@@ -1030,6 +1033,7 @@
 
   deps = [
     ":cronet_api_java",
+    ":cronet_combine_proguard_flags",
     ":cronet_impl_common_java",
     ":cronet_impl_platform_java",
   ]
@@ -1038,14 +1042,15 @@
 action("cronet_combine_proguard_flags") {
   script = "//components/cronet/tools/generate_proguard_file.py"
   outputs = [
-    "$_package_dir/proguard.cfg",
+    "$target_gen_dir/cronet_impl_native_proguard.cfg",
   ]
-
   args = [
     "--output-file",
-    rebase_path("$_package_dir/proguard.cfg", root_build_dir),
+    rebase_path("$target_gen_dir/cronet_impl_native_proguard.cfg",
+                root_build_dir),
+    rebase_path("//components/cronet/android/cronet_impl_native_proguard.cfg",
+                root_build_dir),
     rebase_path("//base/android/proguard/chromium_code.flags", root_build_dir),
-    rebase_path("//components/cronet/android/proguard.cfg", root_build_dir),
   ]
 }
 
@@ -1102,7 +1107,6 @@
   # not including any deps in cronet_package target otherwise.
   if (!(target_cpu == "arm" && arm_version == 7) || !arm_use_neon) {
     deps = [
-      ":cronet_combine_proguard_flags",
       ":cronet_package_copy",
       ":cronet_package_copy_native_lib",
       ":cronet_package_copy_native_lib_unstripped",
diff --git a/components/cronet/android/cronet_impl_common_proguard.cfg b/components/cronet/android/cronet_impl_common_proguard.cfg
new file mode 100644
index 0000000..531394a
--- /dev/null
+++ b/components/cronet/android/cronet_impl_common_proguard.cfg
@@ -0,0 +1,6 @@
+# Proguard config for apps that depend on cronet_impl_common_java.jar.
+
+# This constructor is called using the reflection from Cronet API (cronet_api.jar).
+-keep class org.chromium.net.impl.CronetEngineBuilderImpl {
+    public <init>(android.content.Context);
+}
\ No newline at end of file
diff --git a/components/cronet/android/proguard.cfg b/components/cronet/android/cronet_impl_native_proguard.cfg
similarity index 77%
rename from components/cronet/android/proguard.cfg
rename to components/cronet/android/cronet_impl_native_proguard.cfg
index 1d6c8e17..9ee247f 100644
--- a/components/cronet/android/proguard.cfg
+++ b/components/cronet/android/cronet_impl_native_proguard.cfg
@@ -1,13 +1,8 @@
+# Proguard config for apps that depend on cronet_impl_native_java.jar.
+
 -keep class org.chromium.net.impl.CronetUrlRequest$HeadersList
 -keep class org.chromium.net.impl.ChromiumUrlRequest$ResponseHeadersMap
 
-# This constructor is called by the reflection from Cronet API. It cannot be
-# annotated with @org.chromium.base.annotations.AccessedByNative in order to
-# avoid the dependency on Chromium-Base Java classes.
--keep class org.chromium.net.impl.CronetEngineBuilderImpl {
-    public <init>(android.content.Context);
-}
-
 # Suppress unnecessary warnings.
 -dontnote org.chromium.net.ProxyChangeListener$ProxyReceiver
 -dontnote org.chromium.net.AndroidKeyStore
diff --git a/components/cronet/android/cronet_impl_platform_proguard.cfg b/components/cronet/android/cronet_impl_platform_proguard.cfg
new file mode 100644
index 0000000..3e9d42c
--- /dev/null
+++ b/components/cronet/android/cronet_impl_platform_proguard.cfg
@@ -0,0 +1,7 @@
+# Proguard config for apps that depend on cronet_impl_platform_java.jar.
+
+# This constructor is called using the reflection from the Cronet common
+# implementation (cronet_impl_platform_java.jar).
+-keep class org.chromium.net.impl.JavaCronetEngine {
+    public <init>(java.lang.String);
+}
\ No newline at end of file
diff --git a/components/metrics/data_use_tracker.cc b/components/metrics/data_use_tracker.cc
index d97462a..b9b9bda0 100644
--- a/components/metrics/data_use_tracker.cc
+++ b/components/metrics/data_use_tracker.cc
@@ -22,24 +22,10 @@
 const int kDefaultUMAWeeklyQuotaBytes = 204800;
 const double kDefaultUMARatio = 0.05;
 
-// This function is for forwarding metrics usage pref changes to the appropriate
-// callback on the appropriate thread.
-// TODO(gayane): Reduce the frequency of posting tasks from IO to UI thread.
-void UpdateMetricsUsagePrefs(
-    const UpdateUsagePrefCallbackType& update_on_ui_callback,
-    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
-    const std::string& service_name,
-    int message_size,
-    bool is_cellular) {
-  ui_task_runner->PostTask(
-      FROM_HERE, base::Bind(update_on_ui_callback, service_name, message_size,
-                            is_cellular));
-}
-
 }  // namespace
 
 DataUseTracker::DataUseTracker(PrefService* local_state)
-    : local_state_(local_state), weak_ptr_factory_(this) {}
+    : local_state_(local_state) {}
 
 DataUseTracker::~DataUseTracker() {}
 
@@ -59,15 +45,17 @@
   registry->RegisterDictionaryPref(metrics::prefs::kUmaCellDataUse);
 }
 
-UpdateUsagePrefCallbackType DataUseTracker::GetDataUseForwardingCallback(
-    scoped_refptr<base::SequencedTaskRunner> ui_task_runner) {
-  DCHECK(ui_task_runner->RunsTasksOnCurrentThread());
+void DataUseTracker::UpdateMetricsUsagePrefs(const std::string& service_name,
+                                             int message_size,
+                                             bool is_cellular) {
+  DCHECK(thread_checker_.CalledOnValidThread());
 
-  return base::Bind(
-      &UpdateMetricsUsagePrefs,
-      base::Bind(&DataUseTracker::UpdateMetricsUsagePrefsOnUIThread,
-                 weak_ptr_factory_.GetWeakPtr()),
-      ui_task_runner);
+  if (!is_cellular)
+    return;
+
+  UpdateUsagePref(prefs::kUserCellDataUse, message_size);
+  if (service_name == "UMA")
+    UpdateUsagePref(prefs::kUmaCellDataUse, message_size);
 }
 
 bool DataUseTracker::ShouldUploadLogOnCellular(int log_bytes) {
@@ -98,20 +86,6 @@
          uma_ratio;
 }
 
-void DataUseTracker::UpdateMetricsUsagePrefsOnUIThread(
-    const std::string& service_name,
-    int message_size,
-    bool is_celllular) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  if (!is_celllular)
-    return;
-
-  UpdateUsagePref(prefs::kUserCellDataUse, message_size);
-  if (service_name == "UMA")
-    UpdateUsagePref(prefs::kUmaCellDataUse, message_size);
-}
-
 void DataUseTracker::UpdateUsagePref(const std::string& pref_name,
                                      int message_size) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/metrics/data_use_tracker.h b/components/metrics/data_use_tracker.h
index b6441ec..e5eb2ba 100644
--- a/components/metrics/data_use_tracker.h
+++ b/components/metrics/data_use_tracker.h
@@ -10,9 +10,6 @@
 #include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
 #include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -38,10 +35,10 @@
   // Registers data use prefs using provided |registry|.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
-  // Returns a callback to data use pref updating function. Should be called on
-  // UI thread.
-  UpdateUsagePrefCallbackType GetDataUseForwardingCallback(
-      scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
+  // Updates data usage tracking prefs with the specified values.
+  void UpdateMetricsUsagePrefs(const std::string& service_name,
+                               int message_size,
+                               bool is_cellular);
 
   // Returns whether a log with provided |log_bytes| can be uploaded according
   // to data use ratio and UMA quota provided by variations.
@@ -53,12 +50,6 @@
   FRIEND_TEST_ALL_PREFIXES(DataUseTrackerTest, CheckComputeTotalDataUse);
   FRIEND_TEST_ALL_PREFIXES(DataUseTrackerTest, CheckCanUploadUMALog);
 
-  // Updates data usage prefs on UI thread according to what Prefservice
-  // expects.
-  void UpdateMetricsUsagePrefsOnUIThread(const std::string& service_name,
-                                         int message_size,
-                                         bool is_cellular);
-
   // Updates provided |pref_name| for a current date with the given message
   // size.
   void UpdateUsagePref(const std::string& pref_name, int message_size);
@@ -90,8 +81,6 @@
 
   base::ThreadChecker thread_checker_;
 
-  base::WeakPtrFactory<DataUseTracker> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(DataUseTracker);
 };
 
diff --git a/components/metrics/data_use_tracker_unittest.cc b/components/metrics/data_use_tracker_unittest.cc
index ed32a4a..0cb9668 100644
--- a/components/metrics/data_use_tracker_unittest.cc
+++ b/components/metrics/data_use_tracker_unittest.cc
@@ -109,7 +109,7 @@
   int user_pref_value = 0;
   int uma_pref_value = 0;
 
-  data_use_tracker.UpdateMetricsUsagePrefsOnUIThread("", 2 * 100, true);
+  data_use_tracker.UpdateMetricsUsagePrefs("", 2 * 100, true);
   local_state.GetDictionary(prefs::kUserCellDataUse)
       ->GetInteger(kTodayStr, &user_pref_value);
   EXPECT_EQ(2 * 100, user_pref_value);
@@ -117,7 +117,7 @@
       ->GetInteger(kTodayStr, &uma_pref_value);
   EXPECT_EQ(0, uma_pref_value);
 
-  data_use_tracker.UpdateMetricsUsagePrefsOnUIThread("UMA", 100, true);
+  data_use_tracker.UpdateMetricsUsagePrefs("UMA", 100, true);
   local_state.GetDictionary(prefs::kUserCellDataUse)
       ->GetInteger(kTodayStr, &user_pref_value);
   EXPECT_EQ(3 * 100, user_pref_value);
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index 8e8a1a6..cc0e457e 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -538,14 +538,15 @@
   log_manager_.StoreLog(log, MetricsLog::ONGOING_LOG);
 }
 
-UpdateUsagePrefCallbackType MetricsService::GetDataUseForwardingCallback() {
+void MetricsService::UpdateMetricsUsagePrefs(const std::string& service_name,
+                                             int message_size,
+                                             bool is_cellular) {
   DCHECK(IsSingleThreaded());
-
   if (data_use_tracker_) {
-    return data_use_tracker_->GetDataUseForwardingCallback(
-        base::ThreadTaskRunnerHandle::Get());
+    data_use_tracker_->UpdateMetricsUsagePrefs(service_name,
+                                               message_size,
+                                               is_cellular);
   }
-  return UpdateUsagePrefCallbackType();
 }
 
 void MetricsService::MergeHistogramDeltas() {
diff --git a/components/metrics/metrics_service.h b/components/metrics/metrics_service.h
index 47095f70..562f465 100644
--- a/components/metrics/metrics_service.h
+++ b/components/metrics/metrics_service.h
@@ -201,9 +201,10 @@
   // Pushes a log that has been generated by an external component.
   void PushExternalLog(const std::string& log);
 
-  // Returns a callback to data use pref updating function which can be called
-  // from any thread, but this function should be called on UI thread.
-  UpdateUsagePrefCallbackType GetDataUseForwardingCallback();
+  // Updates data usage tracking prefs with the specified values.
+  void UpdateMetricsUsagePrefs(const std::string& service_name,
+                               int message_size,
+                               bool is_cellular);
 
   // Merge any data from metrics providers into the global StatisticsRecorder.
   void MergeHistogramDeltas();
diff --git a/components/reading_list/ios/reading_list_model.h b/components/reading_list/ios/reading_list_model.h
index cae0226..c3eb2f4 100644
--- a/components/reading_list/ios/reading_list_model.h
+++ b/components/reading_list/ios/reading_list_model.h
@@ -116,17 +116,6 @@
     DISALLOW_COPY_AND_ASSIGN(ScopedReadingListBatchUpdate);
   };
 
-  // TODO(crbug.com/664924): Remove temporary methods for transition.
-
-  // Allows iterating through read entries in the model. Must be called on a
-  // singlerunloop to ensure no entry is returned twice and all entries are
-  // returned
-  virtual const ReadingListEntry& GetReadEntryAtIndex(size_t index) const = 0;
-  virtual const ReadingListEntry& GetUnreadEntryAtIndex(size_t index) const = 0;
-  virtual void MarkReadByURL(const GURL& url) = 0;
-  virtual void MarkUnreadByURL(const GURL& url) = 0;
-  virtual size_t read_size() const = 0;
-
  protected:
   ReadingListModel();
   virtual ~ReadingListModel();
diff --git a/components/reading_list/ios/reading_list_model_impl.cc b/components/reading_list/ios/reading_list_model_impl.cc
index 4727b777..fb010a2 100644
--- a/components/reading_list/ios/reading_list_model_impl.cc
+++ b/components/reading_list/ios/reading_list_model_impl.cc
@@ -13,13 +13,6 @@
 #include "components/reading_list/ios/reading_list_pref_names.h"
 #include "url/gurl.h"
 
-ReadingListModelImpl::Cache::Cache()
-    : read_entries(std::vector<GURL>()),
-      unread_entries(std::vector<GURL>()),
-      dirty(false) {}
-
-ReadingListModelImpl::Cache::~Cache() {}
-
 ReadingListModelImpl::ReadingListModelImpl()
     : ReadingListModelImpl(nullptr, nullptr) {}
 
@@ -28,7 +21,6 @@
     PrefService* pref_service)
     : unread_entry_count_(0),
       read_entry_count_(0),
-      cache_(base::MakeUnique<struct Cache>()),
       pref_service_(pref_service),
       has_unseen_(false),
       loaded_(false),
@@ -40,7 +32,6 @@
   } else {
     loaded_ = true;
     entries_ = base::MakeUnique<ReadingListEntries>();
-    cache_->dirty = true;
   }
   has_unseen_ = GetPersistentHasUnseen();
 }
@@ -51,7 +42,6 @@
     std::unique_ptr<ReadingListEntries> entries) {
   DCHECK(CalledOnValidThread());
   entries_ = std::move(entries);
-  cache_->dirty = true;
   for (auto& iterator : *entries_) {
     if (iterator.second.IsRead()) {
       read_entry_count_++;
@@ -93,14 +83,6 @@
   return unread_entry_count_;
 }
 
-size_t ReadingListModelImpl::read_size() const {
-  DCHECK(CalledOnValidThread());
-  DCHECK(read_entry_count_ + unread_entry_count_ == entries_->size());
-  if (!loaded())
-    return 0;
-  return read_entry_count_;
-}
-
 bool ReadingListModelImpl::HasUnseenEntries() const {
   DCHECK(CalledOnValidThread());
   if (!loaded())
@@ -131,58 +113,6 @@
   return GetMutableEntryFromURL(gurl);
 }
 
-const ReadingListEntry& ReadingListModelImpl::GetReadEntryAtIndex(
-    size_t index) const {
-  DCHECK(CalledOnValidThread());
-  DCHECK(loaded());
-  DCHECK(index < read_entry_count_);
-  if (cache_->dirty) {
-    RebuildIndex();
-  }
-  return *GetEntryByURL(cache_->read_entries[index]);
-}
-
-const ReadingListEntry& ReadingListModelImpl::GetUnreadEntryAtIndex(
-    size_t index) const {
-  DCHECK(CalledOnValidThread());
-  DCHECK(loaded());
-  DCHECK(index < unread_entry_count_);
-  if (cache_->dirty) {
-    RebuildIndex();
-  }
-  return *GetEntryByURL(cache_->unread_entries[index]);
-}
-
-void ReadingListModelImpl::RebuildIndex() const {
-  DCHECK(CalledOnValidThread());
-  DCHECK(loaded());
-  if (!cache_->dirty) {
-    return;
-  }
-  cache_->dirty = false;
-  cache_->read_entries.clear();
-  cache_->unread_entries.clear();
-  for (auto& iterator : *entries_) {
-    if (iterator.second.IsRead()) {
-      cache_->read_entries.push_back(iterator.first);
-    } else {
-      cache_->unread_entries.push_back(iterator.first);
-    }
-  }
-  DCHECK(read_entry_count_ == cache_->read_entries.size());
-  DCHECK(unread_entry_count_ == cache_->unread_entries.size());
-  std::sort(cache_->read_entries.begin(), cache_->read_entries.end(),
-            [this](const GURL& left_url, const GURL& right_url) {
-              return this->entries_->at(left_url).UpdateTime() >
-                     this->entries_->at(right_url).UpdateTime();
-            });
-  std::sort(cache_->unread_entries.begin(), cache_->unread_entries.end(),
-            [this](const GURL& left_url, const GURL& right_url) {
-              return this->entries_->at(left_url).UpdateTime() >
-                     this->entries_->at(right_url).UpdateTime();
-            });
-}
-
 ReadingListEntry* ReadingListModelImpl::GetMutableEntryFromURL(
     const GURL& url) const {
   DCHECK(CalledOnValidThread());
@@ -210,7 +140,6 @@
   }
   GURL url = entry->URL();
   entries_->insert(std::make_pair(url, std::move(*entry)));
-  cache_->dirty = true;
   for (auto& observer : observers_) {
     observer.ReadingListDidAddEntry(this, url);
     observer.ReadingListDidApplyChanges(this);
@@ -239,7 +168,6 @@
   entry->MergeLocalStateFrom(*existing_entry);
 
   entries_->find(url)->second = std::move(*entry);
-  cache_->dirty = true;
 
   existing_entry = GetMutableEntryFromURL(url);
   if (existing_entry->IsRead()) {
@@ -280,7 +208,6 @@
     unread_entry_count_--;
   }
   entries_->erase(url);
-  cache_->dirty = true;
   for (auto& observer : observers_)
     observer.ReadingListDidApplyChanges(this);
 }
@@ -305,7 +232,6 @@
   if (storage_layer_) {
     storage_layer_->SaveEntry(*GetEntryByURL(url));
   }
-  cache_->dirty = true;
 
   for (auto& observer : observers_) {
     observer.ReadingListDidAddEntry(this, url);
@@ -315,14 +241,6 @@
   return entries_->at(url);
 }
 
-void ReadingListModelImpl::MarkReadByURL(const GURL& url) {
-  return SetReadStatus(url, true);
-}
-
-void ReadingListModelImpl::MarkUnreadByURL(const GURL& url) {
-  return SetReadStatus(url, false);
-}
-
 void ReadingListModelImpl::SetReadStatus(const GURL& url, bool read) {
   DCHECK(CalledOnValidThread());
   DCHECK(loaded());
@@ -346,7 +264,6 @@
   }
   entry.SetRead(read);
   entry.MarkEntryUpdated();
-  cache_->dirty = true;
   if (storage_layer_) {
     storage_layer_->SaveEntry(entry);
   }
diff --git a/components/reading_list/ios/reading_list_model_impl.h b/components/reading_list/ios/reading_list_model_impl.h
index 1ff5056..c49d713 100644
--- a/components/reading_list/ios/reading_list_model_impl.h
+++ b/components/reading_list/ios/reading_list_model_impl.h
@@ -46,7 +46,6 @@
 
   size_t size() const override;
   size_t unread_size() const override;
-  size_t read_size() const override;
 
   bool HasUnseenEntries() const override;
   void ResetUnseenEntries() override;
@@ -54,10 +53,6 @@
   const std::vector<GURL> Keys() const override;
 
   const ReadingListEntry* GetEntryByURL(const GURL& gurl) const override;
-  const ReadingListEntry& GetUnreadEntryAtIndex(size_t index) const override;
-  const ReadingListEntry& GetReadEntryAtIndex(size_t index) const override;
-  void MarkReadByURL(const GURL& url) override;
-  void MarkUnreadByURL(const GURL& url) override;
 
   void RemoveEntryByURL(const GURL& url) override;
 
@@ -121,17 +116,6 @@
   size_t unread_entry_count_;
   size_t read_entry_count_;
 
-  // TODO(crbug.com/664924): Remove temporary cache and move it to
-  // ReadingListViewController.
-  struct Cache {
-    Cache();
-    ~Cache();
-    std::vector<GURL> read_entries;
-    std::vector<GURL> unread_entries;
-    bool dirty;
-  };
-  std::unique_ptr<struct Cache> cache_;
-
   std::unique_ptr<ReadingListModelStorage> storage_layer_;
   PrefService* pref_service_;
   bool has_unseen_;
diff --git a/components/reading_list/ios/reading_list_model_observer.h b/components/reading_list/ios/reading_list_model_observer.h
index 44b0132..123ea0b 100644
--- a/components/reading_list/ios/reading_list_model_observer.h
+++ b/components/reading_list/ios/reading_list_model_observer.h
@@ -64,19 +64,6 @@
   // are applied and then this method is called.
   virtual void ReadingListDidApplyChanges(ReadingListModel* model) {}
 
-  // TODO(crbug.com/664924): Remove temporary methods
-  virtual void ReadingListWillRemoveUnreadEntry(const ReadingListModel* model,
-                                                size_t index) {}
-
-  virtual void ReadingListWillRemoveReadEntry(const ReadingListModel* model,
-                                              size_t index) {}
-
-  virtual void ReadingListWillAddUnreadEntry(const ReadingListModel* model,
-                                             const ReadingListEntry& entry) {}
-
-  virtual void ReadingListWillAddReadEntry(const ReadingListModel* model,
-                                           const ReadingListEntry& entry) {}
-
  protected:
   ReadingListModelObserver() {}
   virtual ~ReadingListModelObserver() {}
diff --git a/components/reading_list/ios/reading_list_model_unittest.mm b/components/reading_list/ios/reading_list_model_unittest.mm
index 970bcc4..dff2d10 100644
--- a/components/reading_list/ios/reading_list_model_unittest.mm
+++ b/components/reading_list/ios/reading_list_model_unittest.mm
@@ -558,38 +558,38 @@
 TEST_F(ReadingListModelTest, UpdateReadEntryTitle) {
   const GURL gurl("http://example.com");
   model_->AddEntry(gurl, "sample");
-  model_->MarkReadByURL(gurl);
-  const ReadingListEntry& entry = model_->GetReadEntryAtIndex(0);
+  model_->SetReadStatus(gurl, true);
+  const ReadingListEntry* entry = model_->GetEntryByURL(gurl);
   ClearCounts();
 
   model_->SetEntryTitle(gurl, "ping");
   AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
-  EXPECT_EQ("ping", entry.Title());
+  EXPECT_EQ("ping", entry->Title());
 }
 
 TEST_F(ReadingListModelTest, UpdateReadEntryState) {
   const GURL gurl("http://example.com");
   model_->AddEntry(gurl, "sample");
-  model_->MarkReadByURL(gurl);
-  const ReadingListEntry& entry = model_->GetReadEntryAtIndex(0);
+  model_->SetReadStatus(gurl, true);
+  const ReadingListEntry* entry = model_->GetEntryByURL(gurl);
   ClearCounts();
 
   model_->SetEntryDistilledState(gurl, ReadingListEntry::PROCESSING);
   AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
-  EXPECT_EQ(ReadingListEntry::PROCESSING, entry.DistilledState());
+  EXPECT_EQ(ReadingListEntry::PROCESSING, entry->DistilledState());
 }
 
 TEST_F(ReadingListModelTest, UpdateReadDistilledPath) {
   const GURL gurl("http://example.com");
   model_->AddEntry(gurl, "sample");
-  model_->MarkReadByURL(gurl);
-  const ReadingListEntry& entry = model_->GetReadEntryAtIndex(0);
+  model_->SetReadStatus(gurl, true);
+  const ReadingListEntry* entry = model_->GetEntryByURL(gurl);
   ClearCounts();
 
   model_->SetEntryDistilledPath(gurl, base::FilePath("distilled/page.html"));
   AssertObserverCount(0, 0, 0, 0, 0, 0, 0, 1, 1);
-  EXPECT_EQ(ReadingListEntry::PROCESSED, entry.DistilledState());
-  EXPECT_EQ(base::FilePath("distilled/page.html"), entry.DistilledPath());
+  EXPECT_EQ(ReadingListEntry::PROCESSED, entry->DistilledState());
+  EXPECT_EQ(base::FilePath("distilled/page.html"), entry->DistilledPath());
 }
 
 // Tests that ReadingListModel calls CallbackModelBeingDeleted when destroyed.
diff --git a/components/safe_browsing/OWNERS b/components/safe_browsing/OWNERS
new file mode 100644
index 0000000..b7fd72e
--- /dev/null
+++ b/components/safe_browsing/OWNERS
@@ -0,0 +1,6 @@
+mattm@chromium.org
+nparker@chromium.org
+shess@chromium.org
+
+# For componentization
+timvolodine@chromium.org
diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn
new file mode 100644
index 0000000..47587637
--- /dev/null
+++ b/components/safe_browsing/common/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("common") {
+  sources = [
+    "safebrowsing_constants.cc",
+    "safebrowsing_constants.h",
+    "safebrowsing_message_generator.cc",
+    "safebrowsing_message_generator.h",
+    "safebrowsing_messages.h",
+    "safebrowsing_switches.cc",
+    "safebrowsing_switches.h",
+  ]
+
+  deps = [
+    "//base",
+    "//ipc",
+    "//url/ipc:url_ipc",
+  ]
+}
diff --git a/components/safe_browsing/common/DEPS b/components/safe_browsing/common/DEPS
new file mode 100644
index 0000000..acf92ab
--- /dev/null
+++ b/components/safe_browsing/common/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+ipc",
+  "+url"
+]
diff --git a/components/safe_browsing/common/OWNERS b/components/safe_browsing/common/OWNERS
new file mode 100644
index 0000000..6734395
--- /dev/null
+++ b/components/safe_browsing/common/OWNERS
@@ -0,0 +1,4 @@
+jialiul@chromium.org
+
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=file://ipc/SECURITY_OWNERS
diff --git a/components/safe_browsing/common/safebrowsing_constants.cc b/components/safe_browsing/common/safebrowsing_constants.cc
new file mode 100644
index 0000000..543f725e
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_constants.cc
@@ -0,0 +1,12 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/common/safebrowsing_constants.h"
+
+namespace safe_browsing {
+
+const base::FilePath::CharType kSafeBrowsingBaseFilename[] =
+    FILE_PATH_LITERAL("Safe Browsing");
+
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/common/safebrowsing_constants.h b/components/safe_browsing/common/safebrowsing_constants.h
new file mode 100644
index 0000000..17173cc
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_constants.h
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_CONSTANTS_H_
+#define COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_CONSTANTS_H_
+
+#include "base/files/file_path.h"
+
+namespace safe_browsing {
+
+extern const base::FilePath::CharType kSafeBrowsingBaseFilename[];
+
+}
+
+#endif  // COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_CONSTANTS_H_
diff --git a/components/safe_browsing/common/safebrowsing_message_generator.cc b/components/safe_browsing/common/safebrowsing_message_generator.cc
new file mode 100644
index 0000000..8629de28
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_message_generator.cc
@@ -0,0 +1,39 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+
+// Generate param traits size methods.
+#include "ipc/param_traits_size_macros.h"
+namespace IPC {
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+}  // namespace IPC
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+}  // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+}  // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "components/safe_browsing/common/safebrowsing_message_generator.h"
+}  // namespace IPC
diff --git a/components/safe_browsing/common/safebrowsing_message_generator.h b/components/safe_browsing/common/safebrowsing_message_generator.h
new file mode 100644
index 0000000..8141e6d9c
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_message_generator.h
@@ -0,0 +1,7 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multiply-included file, hence no include guard.
+
+#include "components/safe_browsing/common/safebrowsing_messages.h"
diff --git a/chrome/common/safe_browsing/safebrowsing_messages.h b/components/safe_browsing/common/safebrowsing_messages.h
similarity index 98%
rename from chrome/common/safe_browsing/safebrowsing_messages.h
rename to components/safe_browsing/common/safebrowsing_messages.h
index 7391798..1432398 100644
--- a/chrome/common/safe_browsing/safebrowsing_messages.h
+++ b/components/safe_browsing/common/safebrowsing_messages.h
@@ -9,6 +9,7 @@
 
 #include "ipc/ipc_message_macros.h"
 #include "url/gurl.h"
+#include "url/ipc/url_param_traits.h"
 
 #define IPC_MESSAGE_START SafeBrowsingMsgStart
 
diff --git a/components/safe_browsing/common/safebrowsing_switches.cc b/components/safe_browsing/common/safebrowsing_switches.cc
new file mode 100644
index 0000000..04fb912f
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_switches.cc
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/common/safebrowsing_switches.h"
+
+namespace safe_browsing {
+namespace switches {
+
+// If present, safebrowsing only performs update when
+// SafeBrowsingProtocolManager::ForceScheduleNextUpdate() is explicitly called.
+// This is used for testing only.
+const char kSbDisableAutoUpdate[] = "safebrowsing-disable-auto-update";
+
+// TODO(lzheng): Remove this flag once the feature works fine
+// (http://crbug.com/74848).
+//
+// Disables safebrowsing feature that checks download url and downloads
+// content's hash to make sure the content are not malicious.
+const char kSbDisableDownloadProtection[] =
+    "safebrowsing-disable-download-protection";
+
+// Disables safebrowsing feature that checks for blacklisted extensions.
+const char kSbDisableExtensionBlacklist[] =
+    "safebrowsing-disable-extension-blacklist";
+
+// List of comma-separated sha256 hashes of executable files which the
+// download-protection service should treat as "dangerous."  For a file to
+// show a warning, it also must be considered a dangerous filetype and not
+// be whitelisted otherwise (by signature or URL) and must be on a supported
+// OS. Hashes are in hex. This is used for manual testing when looking
+// for ways to by-pass download protection.
+const char kSbManualDownloadBlacklist[] =
+    "safebrowsing-manual-download-blacklist";
+
+}  // namespace switches
+}  // namespace safe_browsing
diff --git a/components/safe_browsing/common/safebrowsing_switches.h b/components/safe_browsing/common/safebrowsing_switches.h
new file mode 100644
index 0000000..126795b
--- /dev/null
+++ b/components/safe_browsing/common/safebrowsing_switches.h
@@ -0,0 +1,19 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_SWITCHES_H_
+#define COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_SWITCHES_H_
+
+namespace safe_browsing {
+namespace switches {
+
+extern const char kSbDisableAutoUpdate[];
+extern const char kSbDisableDownloadProtection[];
+extern const char kSbDisableExtensionBlacklist[];
+extern const char kSbManualDownloadBlacklist[];
+
+}  // namespace switches
+}  // namespace safe_browsing
+
+#endif  // COMPONENTS_SAFE_BROWSING_COMMON_SAFEBROWSING_SWITCHES_H_
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index ac09f63..d134dfc8 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -856,6 +856,34 @@
     'args': ['--deqp-egl-display-type=angle-gl']
   },
 
+  'angle_deqp_gles31_gl_tests': {
+    'tester_configs': [
+      {
+        'fyi_only': True,
+        'run_on_optional': False,
+        # Run on the Win/Linux Release NVIDIA bots.
+        'build_configs': ['Release'],
+        'swarming_dimension_sets': [
+          {
+            'gpu': '10de:104a',
+            'os': 'Windows-2008ServerR2-SP1'
+          },
+          {
+            'gpu': '10de:104a',
+            'os': 'Linux'
+          }
+        ],
+      }
+    ],
+    'swarming': {
+      # TODO(geofflang): Increase the number of shards as more tests start to
+      # pass and runtime increases.
+      'shards': 4,
+    },
+    'test': 'angle_deqp_gles31_tests',
+    'args': ['--deqp-egl-display-type=angle-gl']
+  },
+
   # Until we have more capacity, run angle_end2end_tests only on the
   # FYI waterfall, the ANGLE trybots (which mirror the FYI waterfall),
   # and the optional trybots (mainly used during ANGLE rolls).
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 35a18801..58de2127 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1210,6 +1210,8 @@
   SYSTEM_DISPLAY_TOUCHCALIBRATIONSTART,
   SYSTEM_DISPLAY_TOUCHCALIBRATIONSET,
   SYSTEM_DISPLAY_TOUCHCALIBRATIONRESET,
+  CERTIFICATEPROVIDER_REQUESTPIN,
+  CERTIFICATEPROVIDER_STOPPINREQUEST,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/common/api/_behavior_features.json b/extensions/common/api/_behavior_features.json
index 67171f7a..b05f1fc9e 100644
--- a/extensions/common/api/_behavior_features.json
+++ b/extensions/common/api/_behavior_features.json
@@ -75,12 +75,19 @@
     "channel": "stable",
     "component_extensions_auto_granted": false,
     "platforms": ["chromeos"],
-    "location": "external_component",
     "whitelist": [
       "E24F1786D842E91E74C27929B0B3715A4689A473",  // Gnubby component extension
       "6F9E349A0561C78A0D3F41496FE521C5151C7F71",  // Gnubby app
       "8EBDF73405D0B84CEABB8C7513C9B9FA9F1DC2CE",  // Genius app (help)
-      "3F50C3A83839D9C76334BCE81CDEC06174F266AF"   // Virtual Keyboard
+      "06BE211D5F014BAB34BC22D9DDA09C63A81D828E",  // Chrome OS XKB
+      "3F50C3A83839D9C76334BCE81CDEC06174F266AF",  // Virtual Keyboard
+      "2F47B526FA71F44816618C41EC55E5EE9543FDCC",  // Braille Keyboard
+      "86672C8D7A04E24EFB244BF96FE518C4C4809F73",  // Speech synthesis
+      "1CF709D51B2B96CF79D00447300BD3BFBE401D21",  // Mobile activation
+      "D519188F86D9ACCEE0412007B227D9936EB9676B",  // Gaia auth extension
+      "40FF1103292F40C34066E023B8BE8CAE18306EAE",  // Chromeos help
+      "3C654B3B6682CA194E75AD044CEDE927675DDEE8",  // Easy unlock
+      "2FCBCE08B34CCA1728A85F1EFBD9A34DD2558B2E"   // ChromeVox
     ]
   }
   ]
diff --git a/gpu/angle_deqp_tests_main.cc b/gpu/angle_deqp_tests_main.cc
index 9814d70..daad62a 100644
--- a/gpu/angle_deqp_tests_main.cc
+++ b/gpu/angle_deqp_tests_main.cc
@@ -19,7 +19,14 @@
 
 }  // namespace
 
+// Defined in angle_deqp_gtest.cpp. Declared here so we don't need to make a
+// header that we import in Chromium.
+namespace angle {
+void InitTestHarness(int* argc, char** argv);
+}
+
 int main(int argc, char** argv) {
+  angle::InitTestHarness(&argc, argv);
   base::CommandLine::Init(argc, argv);
   base::TestSuite test_suite(argc, argv);
   int rt = base::LaunchUnitTestsSerially(
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index b78c429..9f20f71d 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -76,6 +76,8 @@
   {'name': 'cull_face'},
   {'name': 'depth_test', 'state_flag': 'framebuffer_state_.clear_state_dirty'},
   {'name': 'dither', 'default': True},
+  {'name': 'framebuffer_srgb_ext', 'default': True,
+   'extension_flag': 'ext_srgb_write_control'},
   {'name': 'polygon_offset_fill'},
   {'name': 'sample_alpha_to_coverage'},
   {'name': 'sample_coverage'},
diff --git a/gpu/command_buffer/service/context_state.cc b/gpu/command_buffer/service/context_state.cc
index 94192a6..5aa24fb 100644
--- a/gpu/command_buffer/service/context_state.cc
+++ b/gpu/command_buffer/service/context_state.cc
@@ -221,7 +221,6 @@
       pack_reverse_row_order(false),
       ignore_cached_state(false),
       fbo_binding_for_scissor_workaround_dirty(false),
-      framebuffer_srgb_(false),
       feature_info_(feature_info),
       error_state_(ErrorState::Create(error_state_client, logger)) {
   Initialize();
@@ -505,15 +504,8 @@
   RestoreIndexedUniformBufferBindings(prev_state);
   RestoreGlobalState(prev_state);
 
-  if (!prev_state) {
-    if (feature_info_->feature_flags().desktop_srgb_support) {
-      framebuffer_srgb_ = false;
-      glDisable(GL_FRAMEBUFFER_SRGB);
-    }
-  } else if (framebuffer_srgb_ != prev_state->framebuffer_srgb_) {
-    // FRAMEBUFFER_SRGB will be restored lazily at render time.
-    framebuffer_srgb_ = prev_state->framebuffer_srgb_;
-  }
+  // FRAMEBUFFER_SRGB will be restored lazily at render time.
+  framebuffer_srgb_valid_ = false;
 }
 
 ErrorState* ContextState::GetErrorState() {
@@ -706,10 +698,11 @@
 }
 
 void ContextState::EnableDisableFramebufferSRGB(bool enable) {
-  if (framebuffer_srgb_ == enable)
+  if (framebuffer_srgb_valid_ && framebuffer_srgb_ == enable)
     return;
   EnableDisable(GL_FRAMEBUFFER_SRGB, enable);
   framebuffer_srgb_ = enable;
+  framebuffer_srgb_valid_ = true;
 }
 
 void ContextState::InitStateManual(const ContextState*) const {
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 72e4c6c2..6566974 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -354,7 +354,11 @@
 
   void InitStateManual(const ContextState* prev_state) const;
 
-  bool framebuffer_srgb_;
+  // EnableDisableFramebufferSRGB is called at very high frequency. Cache the
+  // true value of FRAMEBUFFER_SRGB, if we know it, to elide some of these
+  // calls.
+  bool framebuffer_srgb_valid_ = false;
+  bool framebuffer_srgb_ = false;
 
   // Generic vertex attrib base types: FLOAT, INT, or UINT.
   // Each base type is encoded into 2 bits, the lowest 2 bits for location 0,
diff --git a/gpu/command_buffer/service/context_state_autogen.h b/gpu/command_buffer/service/context_state_autogen.h
index c0da2cd..38fae6e 100644
--- a/gpu/command_buffer/service/context_state_autogen.h
+++ b/gpu/command_buffer/service/context_state_autogen.h
@@ -22,6 +22,8 @@
   bool cached_depth_test;
   bool dither;
   bool cached_dither;
+  bool framebuffer_srgb_ext;
+  bool cached_framebuffer_srgb_ext;
   bool polygon_offset_fill;
   bool cached_polygon_offset_fill;
   bool sample_alpha_to_coverage;
@@ -143,6 +145,12 @@
         return;
       enable_flags.cached_dither = enable;
       break;
+    case GL_FRAMEBUFFER_SRGB_EXT:
+      if (enable_flags.cached_framebuffer_srgb_ext == enable &&
+          !ignore_cached_state)
+        return;
+      enable_flags.cached_framebuffer_srgb_ext = enable;
+      break;
     case GL_POLYGON_OFFSET_FILL:
       if (enable_flags.cached_polygon_offset_fill == enable &&
           !ignore_cached_state)
diff --git a/gpu/command_buffer/service/context_state_impl_autogen.h b/gpu/command_buffer/service/context_state_impl_autogen.h
index 6bc4a82..3569bbf 100644
--- a/gpu/command_buffer/service/context_state_impl_autogen.h
+++ b/gpu/command_buffer/service/context_state_impl_autogen.h
@@ -21,6 +21,8 @@
       cached_depth_test(false),
       dither(true),
       cached_dither(true),
+      framebuffer_srgb_ext(true),
+      cached_framebuffer_srgb_ext(true),
       polygon_offset_fill(false),
       cached_polygon_offset_fill(false),
       sample_alpha_to_coverage(false),
@@ -167,6 +169,13 @@
     if (prev_state->enable_flags.cached_dither != enable_flags.cached_dither) {
       EnableDisable(GL_DITHER, enable_flags.cached_dither);
     }
+    if (feature_info_->feature_flags().ext_srgb_write_control) {
+      if (prev_state->enable_flags.cached_framebuffer_srgb_ext !=
+          enable_flags.cached_framebuffer_srgb_ext) {
+        EnableDisable(GL_FRAMEBUFFER_SRGB_EXT,
+                      enable_flags.cached_framebuffer_srgb_ext);
+      }
+    }
     if (prev_state->enable_flags.cached_polygon_offset_fill !=
         enable_flags.cached_polygon_offset_fill) {
       EnableDisable(GL_POLYGON_OFFSET_FILL,
@@ -219,6 +228,10 @@
     EnableDisable(GL_CULL_FACE, enable_flags.cached_cull_face);
     EnableDisable(GL_DEPTH_TEST, enable_flags.cached_depth_test);
     EnableDisable(GL_DITHER, enable_flags.cached_dither);
+    if (feature_info_->feature_flags().ext_srgb_write_control) {
+      EnableDisable(GL_FRAMEBUFFER_SRGB_EXT,
+                    enable_flags.cached_framebuffer_srgb_ext);
+    }
     EnableDisable(GL_POLYGON_OFFSET_FILL,
                   enable_flags.cached_polygon_offset_fill);
     EnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE,
@@ -433,6 +446,8 @@
       return enable_flags.depth_test;
     case GL_DITHER:
       return enable_flags.dither;
+    case GL_FRAMEBUFFER_SRGB_EXT:
+      return enable_flags.framebuffer_srgb_ext;
     case GL_POLYGON_OFFSET_FILL:
       return enable_flags.polygon_offset_fill;
     case GL_SAMPLE_ALPHA_TO_COVERAGE:
@@ -835,6 +850,12 @@
         params[0] = static_cast<GLint>(enable_flags.dither);
       }
       return true;
+    case GL_FRAMEBUFFER_SRGB_EXT:
+      *num_written = 1;
+      if (params) {
+        params[0] = static_cast<GLint>(enable_flags.framebuffer_srgb_ext);
+      }
+      return true;
     case GL_POLYGON_OFFSET_FILL:
       *num_written = 1;
       if (params) {
@@ -1269,6 +1290,12 @@
         params[0] = static_cast<GLfloat>(enable_flags.dither);
       }
       return true;
+    case GL_FRAMEBUFFER_SRGB_EXT:
+      *num_written = 1;
+      if (params) {
+        params[0] = static_cast<GLfloat>(enable_flags.framebuffer_srgb_ext);
+      }
+      return true;
     case GL_POLYGON_OFFSET_FILL:
       *num_written = 1;
       if (params) {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 77000c5..cd87ab2 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -572,11 +572,13 @@
     validators_.index_type.AddValue(GL_UNSIGNED_INT);
   }
 
+  bool has_srgb_framebuffer_support = false;
   if (gl_version_info_->IsAtLeastGL(3, 2) ||
       (gl_version_info_->IsAtLeastGL(2, 0) &&
        (extensions.Contains("GL_EXT_framebuffer_sRGB") ||
         extensions.Contains("GL_ARB_framebuffer_sRGB")))) {
     feature_flags_.desktop_srgb_support = true;
+    has_srgb_framebuffer_support = true;
   }
   // With EXT_sRGB, unsized SRGB_EXT and SRGB_ALPHA_EXT are accepted by the
   // <format> and <internalformat> parameter of TexImage2D. GLES3 adds support
@@ -599,6 +601,22 @@
         GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT);
     validators_.texture_unsized_internal_format.AddValue(GL_SRGB_EXT);
     validators_.texture_unsized_internal_format.AddValue(GL_SRGB_ALPHA_EXT);
+    has_srgb_framebuffer_support = true;
+  }
+  if (gl_version_info_->is_es3)
+    has_srgb_framebuffer_support = true;
+
+  if (has_srgb_framebuffer_support && !IsWebGLContext()) {
+    // GL_FRAMEBUFFER_SRGB_EXT is exposed by the GLES extension
+    // GL_EXT_sRGB_write_control (which is not part of the core, even in GLES3),
+    // and the desktop extension GL_ARB_framebuffer_sRGB (part of the core in
+    // 3.0).
+    if (feature_flags_.desktop_srgb_support ||
+        extensions.Contains("GL_EXT_sRGB_write_control")) {
+      feature_flags_.ext_srgb_write_control = true;
+      AddExtensionString("GL_EXT_sRGB_write_control");
+      validators_.capability.AddValue(GL_FRAMEBUFFER_SRGB_EXT);
+    }
   }
 
   // On desktop, GL_EXT_texture_sRGB is required regardless of GL version,
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index d72dfc1..8128c72 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -98,6 +98,7 @@
     bool khr_debug = false;
     bool chromium_bind_generates_resource = false;
     bool angle_webgl_compatibility = false;
+    bool ext_srgb_write_control = false;
   };
 
   FeatureInfo();
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 49b8d19..902a9531 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -246,8 +246,11 @@
       NOTREACHED();
       break;
   }
+  // Note that because GL_EXT_sRGB is a substring of GL_EXT_sRGB_write_control,
+  // which is not part of the ES3 core, we have to be careful to search for
+  // "GL_EXT_sRGB ", and append a space to the end of the extension string.
   if (expect_ext_srgb) {
-    EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_sRGB"));
+    EXPECT_THAT(info_->extensions() + " ", HasSubstr("GL_EXT_sRGB "));
     EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
     EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT));
     EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
@@ -259,7 +262,7 @@
     EXPECT_TRUE(info_->validators()->framebuffer_parameter.IsValid(
         GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
   } else {
-    EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB")));
+    EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB ")));
     EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
     EXPECT_FALSE(info_->validators()->texture_format.IsValid(
         GL_SRGB_ALPHA_EXT));
@@ -593,7 +596,7 @@
   SetupInitExpectations("GL_EXT_sRGB GL_OES_rgb8_rgba8");
 
   if (GetContextType() == CONTEXT_TYPE_OPENGLES3) {
-    EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB")));
+    EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB ")));
     EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
     EXPECT_FALSE(
         info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT));
@@ -606,7 +609,7 @@
     EXPECT_FALSE(info_->validators()->framebuffer_parameter.IsValid(
         GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
   } else {
-    EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_sRGB"));
+    EXPECT_THAT(info_->extensions() + " ", HasSubstr("GL_EXT_sRGB "));
     EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
     EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT));
     EXPECT_TRUE(
@@ -922,7 +925,7 @@
 
 TEST_P(FeatureInfoTest, Initialize_sRGBGLES3) {
   SetupInitExpectationsWithGLVersion("", "", "OpenGL ES 3.0");
-  EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB")));
+  EXPECT_THAT(info_->extensions() + " ", Not(HasSubstr("GL_EXT_sRGB ")));
   EXPECT_FALSE(info_->validators()->texture_format.IsValid(
       GL_SRGB_EXT));
   EXPECT_FALSE(info_->validators()->texture_format.IsValid(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 46dc896..f5c727b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -707,6 +707,7 @@
   // Workarounds
   void OnFboChanged() const;
   void OnUseFramebuffer() const;
+  void UpdateFramebufferSRGB(Framebuffer* framebuffer);
 
   error::ContextLostReason GetContextLostReasonFromResetStatus(
       GLenum reset_status) const;
@@ -3458,6 +3459,7 @@
   DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
   DoBindFramebuffer(GL_FRAMEBUFFER, 0);
   DoBindRenderbuffer(GL_RENDERBUFFER, 0);
+  UpdateFramebufferSRGB(nullptr);
 
   bool call_gl_clear = !surfaceless_ && !offscreen;
 #if defined(OS_ANDROID)
@@ -4295,21 +4297,37 @@
   Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
   bool valid = CheckFramebufferValid(
       framebuffer, target, GL_INVALID_FRAMEBUFFER_OPERATION, func_name);
-  if (valid && !features().chromium_framebuffer_multisample)
+  if (!valid)
+    return false;
+
+  if (!features().chromium_framebuffer_multisample)
     OnUseFramebuffer();
-  if (valid && feature_info_->feature_flags().desktop_srgb_support) {
-    // If framebuffer contains sRGB images, then enable FRAMEBUFFER_SRGB.
-    // Otherwise, disable FRAMEBUFFER_SRGB. Assume default fbo does not have
-    // sRGB image.
-    // In theory, we can just leave FRAMEBUFFER_SRGB on. However, many drivers
-    // behave incorrectly when all images are linear encoding, they still apply
-    // the sRGB conversion, but when at least one image is sRGB, then they
-    // behave correctly.
-    bool enable_framebuffer_srgb =
-        framebuffer && framebuffer->HasSRGBAttachments();
-    state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb);
+
+  UpdateFramebufferSRGB(framebuffer);
+  return true;
+}
+
+void GLES2DecoderImpl::UpdateFramebufferSRGB(Framebuffer* framebuffer) {
+  // Manually set the value of FRAMEBUFFER_SRGB based on the state that was set
+  // by the client.
+  bool needs_enable_disable_framebuffer_srgb = false;
+  bool enable_framebuffer_srgb = true;
+  if (feature_info_->feature_flags().ext_srgb_write_control) {
+    needs_enable_disable_framebuffer_srgb = true;
+    enable_framebuffer_srgb &= state_.GetEnabled(GL_FRAMEBUFFER_SRGB);
   }
-  return valid;
+  // On desktop, enable FRAMEBUFFER_SRGB only if the framebuffer contains sRGB
+  // attachments. In theory, we can just leave FRAMEBUFFER_SRGB enabled,
+  // however,
+  // many drivers behave incorrectly when no attachments are sRGB. When at
+  // least one attachment is sRGB, then they behave correctly.
+  if (feature_info_->feature_flags().desktop_srgb_support) {
+    needs_enable_disable_framebuffer_srgb = true;
+    // Assume that the default fbo does not have an sRGB image.
+    enable_framebuffer_srgb &= framebuffer && framebuffer->HasSRGBAttachments();
+  }
+  if (needs_enable_disable_framebuffer_srgb)
+    state_.EnableDisableFramebufferSRGB(enable_framebuffer_srgb);
 }
 
 bool GLES2DecoderImpl::CheckBoundReadFramebufferValid(
@@ -7424,6 +7442,11 @@
       // DrawElements* for old desktop GL.
       return;
     }
+    if (cap == GL_FRAMEBUFFER_SRGB) {
+      // Enable and Disable GL_FRAMEBUFFER_SRGB is done manually in
+      // CheckBoundDrawFramebufferValid.
+      return;
+    }
     glDisable(cap);
   }
 }
@@ -7436,6 +7459,11 @@
       // DrawElements* for old desktop GL.
       return;
     }
+    if (cap == GL_FRAMEBUFFER_SRGB) {
+      // Enable and Disable GL_FRAMEBUFFER_SRGB is done manually in
+      // CheckBoundDrawFramebufferValid.
+      return;
+    }
     glEnable(cap);
   }
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 0895cdd..1f961d1 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5140,6 +5140,14 @@
         return true;
       }
       return false;
+    case GL_FRAMEBUFFER_SRGB_EXT:
+      state_.enable_flags.framebuffer_srgb_ext = enabled;
+      if (state_.enable_flags.cached_framebuffer_srgb_ext != enabled ||
+          state_.ignore_cached_state) {
+        state_.enable_flags.cached_framebuffer_srgb_ext = enabled;
+        return true;
+      }
+      return false;
     case GL_POLYGON_OFFSET_FILL:
       state_.enable_flags.polygon_offset_fill = enabled;
       if (state_.enable_flags.cached_polygon_offset_fill != enabled ||
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
index af2e41c..d155c35 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
@@ -17,6 +17,9 @@
   ExpectEnableDisable(GL_CULL_FACE, false);
   ExpectEnableDisable(GL_DEPTH_TEST, false);
   ExpectEnableDisable(GL_DITHER, true);
+  if (group_->feature_info()->feature_flags().ext_srgb_write_control) {
+    ExpectEnableDisable(GL_FRAMEBUFFER_SRGB_EXT, true);
+  }
   ExpectEnableDisable(GL_POLYGON_OFFSET_FILL, false);
   ExpectEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE, false);
   ExpectEnableDisable(GL_SAMPLE_COVERAGE, false);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index bbc96b4..9352747 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -435,6 +435,13 @@
       .Times(1)
       .RetiresOnSaturation();
 
+  if (group_->feature_info()->feature_flags().ext_srgb_write_control ||
+      group_->feature_info()->feature_flags().desktop_srgb_support) {
+    EXPECT_CALL(*gl_, Disable(GL_FRAMEBUFFER_SRGB))
+        .Times(1)
+        .RetiresOnSaturation();
+  }
+
   // TODO(boliu): Remove OS_ANDROID once crbug.com/259023 is fixed and the
   // workaround has been reverted.
 #if !defined(OS_ANDROID)
diff --git a/gpu/command_buffer/tests/gl_test_utils.cc b/gpu/command_buffer/tests/gl_test_utils.cc
index bf860a6..f10a919 100644
--- a/gpu/command_buffer/tests/gl_test_utils.cc
+++ b/gpu/command_buffer/tests/gl_test_utils.cc
@@ -71,9 +71,13 @@
 }
 
 bool GLTestHelper::HasExtension(const char* extension) {
-  std::string extensions(
-      reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
-  return extensions.find(extension) != std::string::npos;
+  // Pad with an extra space to ensure that |extension| is not a substring of
+  // another extension.
+  std::string extensions =
+      std::string(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))) +
+      " ";
+  std::string extension_padded = std::string(extension) + " ";
+  return extensions.find(extension_padded) != std::string::npos;
 }
 
 bool GLTestHelper::CheckGLError(const char* msg, int line) {
diff --git a/mash/BUILD.gn b/mash/BUILD.gn
index b4337e0..c1eb630 100644
--- a/mash/BUILD.gn
+++ b/mash/BUILD.gn
@@ -17,6 +17,7 @@
     "//mash/login",
     "//mash/screenlock",
     "//mash/session",
+    "//mash/simple_wm",
     "//mash/task_viewer",
   ]
 
diff --git a/mash/common/BUILD.gn b/mash/common/BUILD.gn
new file mode 100644
index 0000000..3f285f0
--- /dev/null
+++ b/mash/common/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("common") {
+  sources = [
+    "config.cc",
+    "config.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
diff --git a/mash/common/config.cc b/mash/common/config.cc
new file mode 100644
index 0000000..f4e14f7
--- /dev/null
+++ b/mash/common/config.cc
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mash/common/config.h"
+
+#include "base/command_line.h"
+
+namespace mash {
+namespace common {
+
+const char kWindowManagerSwitch[] = "window-manager";
+
+std::string GetWindowManagerServiceName() {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kWindowManagerSwitch)) {
+    std::string service_name =
+        base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+            kWindowManagerSwitch);
+    return service_name;
+  }
+  // TODO(beng): move this constant to a mojom file in //ash.
+  return "ash";
+}
+
+}  // namespace common
+}  // namespace mash
diff --git a/mash/common/config.h b/mash/common/config.h
new file mode 100644
index 0000000..3f7e6e2
--- /dev/null
+++ b/mash/common/config.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MASH_COMMON_CONFIG_H_
+#define MASH_COMMON_CONFIG_H_
+
+#include <string>
+
+namespace mash {
+namespace common {
+
+// This file contains configuration functions that can be used by any mash
+// service.
+
+// Returns the name of the window manager service to run. By default this will
+// return "ash". A different value can be specified on the command line by
+// passing --window-manager=<foo>.
+std::string GetWindowManagerServiceName();
+
+}  // namespace common
+}  // namespace mash
+
+#endif  // MASH_COMMON_CONFIG_H_
diff --git a/mash/login/BUILD.gn b/mash/login/BUILD.gn
index 10efd20..3fc13dd 100644
--- a/mash/login/BUILD.gn
+++ b/mash/login/BUILD.gn
@@ -19,6 +19,7 @@
     "//ash/public/cpp",
     "//ash/public/interfaces",
     "//base",
+    "//mash/common",
     "//mash/init/public/interfaces",
     "//mash/login/public/interfaces",
     "//mojo/public/cpp/bindings",
diff --git a/mash/login/login.cc b/mash/login/login.cc
index e428075a..d28929d 100644
--- a/mash/login/login.cc
+++ b/mash/login/login.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "mash/common/config.h"
 #include "mash/init/public/interfaces/constants.mojom.h"
 #include "mash/init/public/interfaces/init.mojom.h"
 #include "mash/login/public/interfaces/login.mojom.h"
@@ -117,7 +118,8 @@
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
   void StartWindowManager(const service_manager::Identity& identity) {
-    mash_wm_connection_ = connector_->Connect("ash");
+    mash_wm_connection_ =
+        connector_->Connect(common::GetWindowManagerServiceName());
     mash_wm_connection_->SetConnectionLostClosure(
         base::Bind(&UI::StartWindowManager, base::Unretained(this), identity));
     window_manager_connection_ =
diff --git a/mash/session/BUILD.gn b/mash/session/BUILD.gn
index 535adad4..0083be0a 100644
--- a/mash/session/BUILD.gn
+++ b/mash/session/BUILD.gn
@@ -17,6 +17,7 @@
   deps = [
     "//base",
     "//content/public/common:service_names",
+    "//mash/common",
     "//mash/login/public/interfaces",
     "//mash/quick_launch/public/interfaces:constants",
     "//mash/screenlock/public/interfaces:constants",
diff --git a/mash/session/session.cc b/mash/session/session.cc
index f72a9a35..a28ac33 100644
--- a/mash/session/session.cc
+++ b/mash/session/session.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "content/public/common/service_names.mojom.h"
+#include "mash/common/config.h"
 #include "mash/login/public/interfaces/constants.mojom.h"
 #include "mash/login/public/interfaces/login.mojom.h"
 #include "mash/quick_launch/public/interfaces/constants.mojom.h"
@@ -99,7 +100,7 @@
 
 void Session::StartWindowManager() {
   StartRestartableService(
-      "ash",
+      common::GetWindowManagerServiceName(),
       base::Bind(&Session::StartWindowManager,
                  base::Unretained(this)));
 }
diff --git a/mash/simple_wm/BUILD.gn b/mash/simple_wm/BUILD.gn
new file mode 100644
index 0000000..2145fde
--- /dev/null
+++ b/mash/simple_wm/BUILD.gn
@@ -0,0 +1,62 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+import("//tools/grit/repack.gni")
+
+service("simple_wm") {
+  testonly = true
+
+  sources = [
+    "main.cc",
+  ]
+
+  deps = [
+    ":lib",
+    "//base",
+    "//services/service_manager/public/cpp",
+    "//ui/views/mus:for_mojo_application",
+  ]
+
+  resources = [ "$root_out_dir/views_mus_resources.pak" ]
+}
+
+source_set("lib") {
+  testonly = true
+  sources = [
+    "simple_wm.cc",
+    "simple_wm.h",
+  ]
+
+  deps = [
+    "//base",
+    "//services/service_manager/public/cpp",
+    "//services/ui/public/cpp",
+    "//services/ui/public/interfaces",
+    "//ui/aura",
+    "//ui/aura:test_support",
+    "//ui/display",
+    "//ui/display:test_support",
+    "//ui/gfx/geometry/mojo",
+    "//ui/views",
+    "//ui/views/mus:mus",
+    "//ui/wm",
+  ]
+
+  public_deps = [
+    "//skia",  # Due to use of Sk types in service header.
+  ]
+
+  data_deps = [
+    ":manifest",
+    "//services/ui",
+  ]
+}
+
+service_manifest("manifest") {
+  name = "simple_wm"
+  source = "manifest.json"
+}
diff --git a/mash/simple_wm/main.cc b/mash/simple_wm/main.cc
new file mode 100644
index 0000000..42311306
--- /dev/null
+++ b/mash/simple_wm/main.cc
@@ -0,0 +1,12 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mash/simple_wm/simple_wm.h"
+#include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/service_runner.h"
+
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+  service_manager::ServiceRunner runner(new simple_wm::SimpleWM);
+  return runner.Run(service_request_handle);
+}
diff --git a/mash/simple_wm/manifest.json b/mash/simple_wm/manifest.json
new file mode 100644
index 0000000..32164e3
--- /dev/null
+++ b/mash/simple_wm/manifest.json
@@ -0,0 +1,12 @@
+{
+  "name": "simple_wm",
+  "display_name": "Simple Window Manager",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "requires": {
+        "*": [ "app" ],
+        "ui": [ "ui:window_manager" ]
+      }
+    }
+  }
+}
diff --git a/mash/simple_wm/simple_wm.cc b/mash/simple_wm/simple_wm.cc
new file mode 100644
index 0000000..49917e2
--- /dev/null
+++ b/mash/simple_wm/simple_wm.cc
@@ -0,0 +1,245 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mash/simple_wm/simple_wm.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/display/screen_base.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/mojo/geometry.mojom.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/mus/aura_init.h"
+#include "ui/views/mus/mus_client.h"
+#include "ui/views/widget/native_widget_aura.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+#include "ui/wm/core/default_activation_client.h"
+
+namespace simple_wm {
+
+namespace {
+
+const int kNonClientTopHeight = 24;
+const int kNonClientSize = 5;
+
+}  // namespace
+
+class SimpleWM::FrameView : public views::WidgetDelegateView,
+                            public aura::WindowObserver {
+ public:
+  explicit FrameView(aura::Window* client_window)
+      : client_window_(client_window) {
+    client_window_->AddObserver(this);
+  }
+  ~FrameView() override {}
+
+ private:
+  // views::WidgetDelegateView:
+  base::string16 GetWindowTitle() const override {
+    base::string16* title =
+        client_window_->GetProperty(aura::client::kTitleKey);
+    if (!title)
+      return base::UTF8ToUTF16("(Window)");
+    return *title;
+  }
+  void Layout() override {
+    // Client offsets are applied automatically by the window service.
+    gfx::Rect parent_bounds = GetWidget()->GetNativeWindow()->bounds();
+    parent_bounds.set_origin(gfx::Point());
+    client_window_->SetBounds(parent_bounds);
+  }
+
+  // aura::WindowObserver:
+  void OnWindowPropertyChanged(aura::Window* window, const void* key,
+                               intptr_t old) override {
+    if (key == aura::client::kTitleKey)
+      GetWidget()->UpdateWindowTitle();
+  }
+
+  aura::Window* client_window_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameView);
+};
+
+SimpleWM::SimpleWM() {}
+
+SimpleWM::~SimpleWM() {
+  // WindowTreeHost uses state from WindowTreeClient, so destroy it first.
+  window_tree_host_.reset();
+
+  // WindowTreeClient destruction may callback to us.
+  window_tree_client_.reset();
+
+  gpu_service_.reset();
+
+  display::Screen::SetScreenInstance(nullptr);
+}
+
+void SimpleWM::OnStart() {
+  CHECK(!started_);
+  started_ = true;
+  screen_ = base::MakeUnique<display::ScreenBase>();
+  display::Screen::SetScreenInstance(screen_.get());
+  aura_init_ = base::MakeUnique<views::AuraInit>(
+      context()->connector(), context()->identity(), "views_mus_resources.pak",
+      std::string(), nullptr, views::AuraInit::Mode::AURA_MUS_WINDOW_MANAGER);
+  gpu_service_ = ui::GpuService::Create(context()->connector(), nullptr);
+  compositor_context_factory_ =
+      base::MakeUnique<aura::MusContextFactory>(gpu_service_.get());
+  aura::Env::GetInstance()->set_context_factory(
+      compositor_context_factory_.get());
+  window_tree_client_ = base::MakeUnique<aura::WindowTreeClient>(
+      context()->connector(), this, this);
+  aura::Env::GetInstance()->SetWindowTreeClient(window_tree_client_.get());
+  window_tree_client_->ConnectAsWindowManager();
+}
+
+bool SimpleWM::OnConnect(
+    const service_manager::ServiceInfo& remote_info,
+    service_manager::InterfaceRegistry* registry) {
+  return true;
+}
+
+void SimpleWM::OnEmbed(
+    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
+  // WindowTreeClients configured as the window manager should never get
+  // OnEmbed().
+  NOTREACHED();
+}
+
+void SimpleWM::OnLostConnection(aura::WindowTreeClient* client) {
+  window_tree_host_.reset();
+  window_tree_client_.reset();
+}
+
+void SimpleWM::OnEmbedRootDestroyed(aura::Window* root) {
+  // WindowTreeClients configured as the window manager should never get
+  // OnEmbedRootDestroyed().
+  NOTREACHED();
+}
+
+void SimpleWM::OnPointerEventObserved(const ui::PointerEvent& event,
+                                      aura::Window* target) {
+  // Don't care.
+}
+
+aura::client::CaptureClient* SimpleWM::GetCaptureClient() {
+  return wm_state_.capture_controller();
+}
+
+aura::PropertyConverter* SimpleWM::GetPropertyConverter() {
+  return &property_converter_;
+}
+
+void SimpleWM::SetWindowManagerClient(
+    aura::WindowManagerClient* client) {
+  window_manager_client_ = client;
+}
+
+bool SimpleWM::OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) {
+  FrameView* frame_view = GetFrameViewForClientWindow(window);
+  frame_view->GetWidget()->SetBounds(*bounds);
+  return true;
+}
+
+bool SimpleWM::OnWmSetProperty(
+    aura::Window* window,
+    const std::string& name,
+    std::unique_ptr<std::vector<uint8_t>>* new_data) {
+  return true;
+}
+
+aura::Window* SimpleWM::OnWmCreateTopLevelWindow(
+    ui::mojom::WindowType window_type,
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  aura::Window* client_window = new aura::Window(nullptr);
+  SetWindowType(client_window, window_type);
+  client_window->Init(ui::LAYER_NOT_DRAWN);
+
+  views::Widget* frame_widget = new views::Widget;
+  views::NativeWidgetAura* frame_native_widget =
+      new views::NativeWidgetAura(frame_widget, true);
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  FrameView* frame_view = new FrameView(client_window);
+  params.delegate = frame_view;
+  params.native_widget = frame_native_widget;
+  params.parent = root_;
+  params.bounds = gfx::Rect(10, 10, 500, 500);
+  frame_widget->Init(params);
+  frame_widget->Show();
+
+  frame_widget->GetNativeWindow()->AddChild(client_window);
+
+  client_window_to_frame_view_[client_window] = frame_view;
+  // TODO(beng): probably need to observe client_window from now on so we can
+  // clean up this map.
+
+  return client_window;
+}
+
+void SimpleWM::OnWmClientJankinessChanged(
+    const std::set<aura::Window*>& client_windows,
+    bool janky) {
+  // Don't care.
+}
+
+void SimpleWM::OnWmWillCreateDisplay(const display::Display& display) {
+  screen_->display_list().AddDisplay(display,
+                                     display::DisplayList::Type::PRIMARY);
+}
+
+void SimpleWM::OnWmNewDisplay(
+    std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
+    const display::Display& display) {
+  // Only handles a single root.
+  DCHECK(!root_);
+  window_tree_host_ = std::move(window_tree_host);
+  window_tree_host_->InitCompositor();
+  root_ = window_tree_host_->window();
+  DCHECK(window_manager_client_);
+  window_manager_client_->AddActivationParent(root_);
+  ui::mojom::FrameDecorationValuesPtr frame_decoration_values =
+      ui::mojom::FrameDecorationValues::New();
+  frame_decoration_values->normal_client_area_insets.Set(
+      kNonClientTopHeight, kNonClientSize, kNonClientSize, kNonClientSize);
+  frame_decoration_values->max_title_bar_button_width = 0;
+  window_manager_client_->SetFrameDecorationValues(
+      std::move(frame_decoration_values));
+  new wm::DefaultActivationClient(root_);
+  aura::client::SetFocusClient(root_, &focus_client_);
+}
+
+void SimpleWM::OnWmDisplayRemoved(
+    aura::WindowTreeHostMus* window_tree_host) {
+  DCHECK_EQ(window_tree_host, window_tree_host_.get());
+  root_ = nullptr;
+  window_tree_host_.reset();
+}
+
+void SimpleWM::OnWmDisplayModified(const display::Display& display) {}
+
+void SimpleWM::OnWmPerformMoveLoop(
+    aura::Window* window,
+    ui::mojom::MoveLoopSource source,
+    const gfx::Point& cursor_location,
+    const base::Callback<void(bool)>& on_done) {
+  // Don't care.
+}
+
+void SimpleWM::OnWmCancelMoveLoop(aura::Window* window) {}
+
+void SimpleWM::OnWmSetClientArea(
+    aura::Window* window,
+    const gfx::Insets& insets,
+    const std::vector<gfx::Rect>& additional_client_areas) {}
+
+SimpleWM::FrameView* SimpleWM::GetFrameViewForClientWindow(
+    aura::Window* client_window) {
+  auto it = client_window_to_frame_view_.find(client_window);
+  return it != client_window_to_frame_view_.end() ? it->second : nullptr;
+}
+
+}  // namespace simple_wm
+
diff --git a/mash/simple_wm/simple_wm.h b/mash/simple_wm/simple_wm.h
new file mode 100644
index 0000000..ac7042ca
--- /dev/null
+++ b/mash/simple_wm/simple_wm.h
@@ -0,0 +1,116 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MASH_SIMPLE_WM_SIMPLE_WM_H_
+#define MASH_SIMPLE_WM_SIMPLE_WM_H_
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/ui/public/cpp/gpu/gpu_service.h"
+#include "ui/aura/env.h"
+#include "ui/aura/mus/mus_context_factory.h"
+#include "ui/aura/mus/property_converter.h"
+#include "ui/aura/mus/property_utils.h"
+#include "ui/aura/mus/window_manager_delegate.h"
+#include "ui/aura/mus/window_tree_client.h"
+#include "ui/aura/mus/window_tree_client_delegate.h"
+#include "ui/aura/mus/window_tree_host_mus.h"
+#include "ui/aura/test/test_focus_client.h"
+#include "ui/aura/window.h"
+#include "ui/display/display.h"
+#include "ui/wm/core/capture_controller.h"
+#include "ui/wm/core/wm_state.h"
+
+namespace display {
+class ScreenBase;
+}
+
+namespace views {
+class AuraInit;
+}
+
+namespace simple_wm {
+
+class SimpleWM : public service_manager::Service,
+                 public aura::WindowTreeClientDelegate,
+                 public aura::WindowManagerDelegate {
+ public:
+  SimpleWM();
+  ~SimpleWM() override;
+
+ private:
+  class FrameView;
+
+  // service_manager::Service:
+  void OnStart() override;
+  bool OnConnect(const service_manager::ServiceInfo& remote_info,
+                 service_manager::InterfaceRegistry* registry) override;
+
+  // aura::WindowTreeClientDelegate:
+  void OnEmbed(
+      std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) override;
+  void OnLostConnection(aura::WindowTreeClient* client) override;
+  void OnEmbedRootDestroyed(aura::Window* root) override;
+  void OnPointerEventObserved(const ui::PointerEvent& event,
+                              aura::Window* target) override;
+  aura::client::CaptureClient* GetCaptureClient() override;
+  aura::PropertyConverter* GetPropertyConverter() override;
+
+  // aura::WindowManagerDelegate:
+  void SetWindowManagerClient(aura::WindowManagerClient* client) override;
+  bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override;
+  bool OnWmSetProperty(
+      aura::Window* window,
+      const std::string& name,
+      std::unique_ptr<std::vector<uint8_t>>* new_data) override;
+  aura::Window* OnWmCreateTopLevelWindow(
+      ui::mojom::WindowType window_type,
+      std::map<std::string, std::vector<uint8_t>>* properties) override;
+  void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
+                                  bool janky) override;
+  void OnWmWillCreateDisplay(const display::Display& display) override;
+  void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
+                      const display::Display& display) override;
+  void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override;
+  void OnWmDisplayModified(const display::Display& display) override;
+  void OnWmPerformMoveLoop(aura::Window* window,
+                           ui::mojom::MoveLoopSource source,
+                           const gfx::Point& cursor_location,
+                           const base::Callback<void(bool)>& on_done) override;
+  void OnWmCancelMoveLoop(aura::Window* window) override;
+  void OnWmSetClientArea(
+      aura::Window* window,
+      const gfx::Insets& insets,
+      const std::vector<gfx::Rect>& additional_client_areas) override;
+
+  FrameView* GetFrameViewForClientWindow(aura::Window* client_window);
+
+  std::unique_ptr<views::AuraInit> aura_init_;
+  ::wm::WMState wm_state_;
+  std::unique_ptr<display::ScreenBase> screen_;
+  aura::PropertyConverter property_converter_;
+  aura::test::TestFocusClient focus_client_;
+  std::unique_ptr<aura::WindowTreeHostMus> window_tree_host_;
+  aura::Window* root_ = nullptr;
+  aura::WindowManagerClient* window_manager_client_ = nullptr;
+  std::unique_ptr<aura::WindowTreeClient> window_tree_client_;
+  std::unique_ptr<ui::GpuService> gpu_service_;
+  std::unique_ptr<aura::MusContextFactory> compositor_context_factory_;
+  std::map<aura::Window*, FrameView*> client_window_to_frame_view_;
+
+  bool started_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleWM);
+};
+
+}  // namespace simple_wm
+
+#endif  // MASH_SIMPLE_WM_SIMPLE_WM_H_
diff --git a/pdf/pdf.cc b/pdf/pdf.cc
index e60c4bd..e6cf5480 100644
--- a/pdf/pdf.cc
+++ b/pdf/pdf.cc
@@ -82,7 +82,8 @@
 }
 
 #if defined(OS_WIN)
-bool RenderPDFPageToDC(void* pdf_handle,
+bool RenderPDFPageToDC(const void* pdf_buffer,
+                       int buffer_size,
                        int page_number,
                        HDC dc,
                        int dpi,
@@ -106,8 +107,8 @@
       pp::Rect(bounds_origin_x, bounds_origin_y, bounds_width, bounds_height),
       fit_to_bounds, stretch_to_bounds, keep_aspect_ratio, center_in_bounds,
       autorotate);
-  bool ret =
-      engine_exports->RenderPDFPageToDC(pdf_handle, page_number, settings, dc);
+  bool ret = engine_exports->RenderPDFPageToDC(pdf_buffer, buffer_size,
+                                               page_number, settings, dc);
   if (!g_sdk_initialized_via_pepper)
     ShutdownSDK();
 
@@ -127,49 +128,40 @@
 bool GetPDFDocInfo(const void* pdf_buffer,
                    int buffer_size,
                    int* page_count,
-                   double* max_page_width,
-                   void** pdf_handle) {
+                   double* max_page_width) {
   if (!g_sdk_initialized_via_pepper) {
     if (!InitializeSDK())
       return false;
   }
   PDFEngineExports* engine_exports = PDFEngineExports::Get();
   bool ret = engine_exports->GetPDFDocInfo(pdf_buffer, buffer_size, page_count,
-                                           max_page_width, pdf_handle);
+                                           max_page_width);
   if (!g_sdk_initialized_via_pepper)
     ShutdownSDK();
 
   return ret;
 }
 
-void ReleasePDFHandle(void* pdf_handle) {
-  if (!g_sdk_initialized_via_pepper) {
-    if (!InitializeSDK())
-      return;
-  }
-  PDFEngineExports* engine_exports = PDFEngineExports::Get();
-  engine_exports->ReleasePDFHandle(pdf_handle);
-  if (!g_sdk_initialized_via_pepper)
-    ShutdownSDK();
-}
-
-bool GetPDFPageSizeByIndex(void* pdf_handle,
+bool GetPDFPageSizeByIndex(const void* pdf_buffer,
+                           int pdf_buffer_size,
                            int page_number,
                            double* width,
                            double* height) {
   if (!g_sdk_initialized_via_pepper) {
-    if (!InitializeSDK())
+    if (!chrome_pdf::InitializeSDK())
       return false;
   }
-  PDFEngineExports* engine_exports = PDFEngineExports::Get();
-  bool ret = engine_exports->GetPDFPageSizeByIndex(pdf_handle, page_number,
-                                                   width, height);
+  chrome_pdf::PDFEngineExports* engine_exports =
+      chrome_pdf::PDFEngineExports::Get();
+  bool ret = engine_exports->GetPDFPageSizeByIndex(pdf_buffer, pdf_buffer_size,
+                                                   page_number, width, height);
   if (!g_sdk_initialized_via_pepper)
-    ShutdownSDK();
+    chrome_pdf::ShutdownSDK();
   return ret;
 }
 
-bool RenderPDFPageToBitmap(void* pdf_handle,
+bool RenderPDFPageToBitmap(const void* pdf_buffer,
+                           int pdf_buffer_size,
                            int page_number,
                            void* bitmap_buffer,
                            int bitmap_width,
@@ -184,8 +176,8 @@
   PDFEngineExports::RenderingSettings settings(
       dpi, dpi, pp::Rect(bitmap_width, bitmap_height), true, false, true, true,
       autorotate);
-  bool ret = engine_exports->RenderPDFPageToBitmap(pdf_handle, page_number,
-                                                   settings, bitmap_buffer);
+  bool ret = engine_exports->RenderPDFPageToBitmap(
+      pdf_buffer, pdf_buffer_size, page_number, settings, bitmap_buffer);
   if (!g_sdk_initialized_via_pepper)
     ShutdownSDK();
 
diff --git a/pdf/pdf.h b/pdf/pdf.h
index 2c01124..c785b551 100644
--- a/pdf/pdf.h
+++ b/pdf/pdf.h
@@ -36,7 +36,9 @@
 const void* PPP_GetInterface(const char* interface_name);
 
 #if defined(OS_WIN)
-// |pdf_handle| is the handle to the PDF document.
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |buffer_size| is the size of |pdf_buffer| in bytes.
 // |page_number| is the 0-based index of the page to be rendered.
 // |dc| is the device context to render into.
 // |dpi| and |dpi_y| is the resolution. If the value is -1, the dpi from the DC
@@ -61,7 +63,8 @@
 // |autorotate| specifies whether the final image should be rotated to match
 //     the output bound.
 // Returns false if the document or the page number are not valid.
-bool RenderPDFPageToDC(void* pdf_handle,
+bool RenderPDFPageToDC(const void* pdf_buffer,
+                       int buffer_size,
                        int page_number,
                        HDC dc,
                        int dpi,
@@ -81,35 +84,32 @@
 void SetPDFUseGDIPrinting(bool enable);
 #endif  // defined(OS_WIN)
 
-// All the out parameters are optional and can be NULL.
+// |page_count| and |max_page_width| are optional and can be NULL.
 // Returns false if the document is not valid.
-// Returns true on success. In which case, if |pdf_handle| is not NULL, then
-// the handle is guaranteed to be valid and not NULL. The caller takes
-// ownership of |pdf_handle| and must call ReleasePDFHandle() on it when done.
 bool GetPDFDocInfo(const void* pdf_buffer,
                    int buffer_size,
                    int* page_count,
-                   double* max_page_width,
-                   void** pdf_handle);
-
-// Releases the handle received from GetPDFDocInfo().
-// |pdf_handle| can be NULL.
-void ReleasePDFHandle(void* pdf_handle);
+                   double* max_page_width);
 
 // Gets the dimensions of a specific page in a document.
-// |pdf_handle| is the handle to the PDF document.
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
 // |page_number| is the page number that the function will get the dimensions
 //     of.
 // |width| is the output for the width of the page in points.
 // |height| is the output for the height of the page in points.
 // Returns false if the document or the page number are not valid.
-bool GetPDFPageSizeByIndex(void* pdf_handle,
+bool GetPDFPageSizeByIndex(const void* pdf_buffer,
+                           int pdf_buffer_size,
                            int page_number,
                            double* width,
                            double* height);
 
 // Renders PDF page into 4-byte per pixel BGRA color bitmap.
-// |pdf_handle| is the handle to the PDF document.
+// |pdf_buffer| is the buffer that contains the entire PDF document to be
+//     rendered.
+// |pdf_buffer_size| is the size of |pdf_buffer| in bytes.
 // |page_number| is the 0-based index of the page to be rendered.
 // |bitmap_buffer| is the output buffer for bitmap.
 // |bitmap_width| is the width of the output bitmap.
@@ -118,7 +118,8 @@
 // |autorotate| specifies whether the final image should be rotated to match
 //     the output bound.
 // Returns false if the document or the page number are not valid.
-bool RenderPDFPageToBitmap(void* pdf_handle,
+bool RenderPDFPageToBitmap(const void* pdf_buffer,
+                           int pdf_buffer_size,
                            int page_number,
                            void* bitmap_buffer,
                            int bitmap_width,
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index 4c7ce63..4bb62b3 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -333,8 +333,9 @@
   static PDFEngineExports* Get();
 
 #if defined(OS_WIN)
-  // See the definitions of the corresponding functions in pdf.h for details.
-  virtual bool RenderPDFPageToDC(void* pdf_handle,
+  // See the definition of RenderPDFPageToDC in pdf.cc for details.
+  virtual bool RenderPDFPageToDC(const void* pdf_buffer,
+                                 int buffer_size,
                                  int page_number,
                                  const RenderingSettings& settings,
                                  HDC dc) = 0;
@@ -345,7 +346,9 @@
   virtual void SetPDFUseGDIPrinting(bool enable) = 0;
 #endif  // defined(OS_WIN)
 
-  virtual bool RenderPDFPageToBitmap(void* pdf_handle,
+  // See the definition of RenderPDFPageToBitmap in pdf.cc for details.
+  virtual bool RenderPDFPageToBitmap(const void* pdf_buffer,
+                                     int pdf_buffer_size,
                                      int page_number,
                                      const RenderingSettings& settings,
                                      void* bitmap_buffer) = 0;
@@ -353,12 +356,11 @@
   virtual bool GetPDFDocInfo(const void* pdf_buffer,
                              int buffer_size,
                              int* page_count,
-                             double* max_page_width,
-                             void** pdf_handle) = 0;
+                             double* max_page_width) = 0;
 
-  virtual void ReleasePDFHandle(void* pdf_handle) = 0;
-
-  virtual bool GetPDFPageSizeByIndex(void* pdf_handle,
+  // See the definition of GetPDFPageSizeByIndex in pdf.cc for details.
+  virtual bool GetPDFPageSizeByIndex(const void* pdf_buffer,
+                                     int pdf_buffer_size,
                                      int page_number,
                                      double* width,
                                      double* height) = 0;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 0853d79..80f1fd6 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4007,17 +4007,19 @@
 }
 
 #if defined(OS_WIN)
-bool PDFiumEngineExports::RenderPDFPageToDC(void* pdf_handle,
+bool PDFiumEngineExports::RenderPDFPageToDC(const void* pdf_buffer,
+                                            int buffer_size,
                                             int page_number,
                                             const RenderingSettings& settings,
                                             HDC dc) {
-  FPDF_DOCUMENT doc = pdf_handle;
+  FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr);
   if (!doc)
     return false;
   FPDF_PAGE page = FPDF_LoadPage(doc, page_number);
-  if (!page)
+  if (!page) {
+    FPDF_CloseDocument(doc);
     return false;
-
+  }
   RenderingSettings new_settings = settings;
   // calculate the page size
   if (new_settings.dpi_x == -1)
@@ -4071,6 +4073,7 @@
   }
   RestoreDC(dc, save_state);
   FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
   return true;
 }
 
@@ -4086,16 +4089,20 @@
 #endif  // defined(OS_WIN)
 
 bool PDFiumEngineExports::RenderPDFPageToBitmap(
-    void* pdf_handle,
+    const void* pdf_buffer,
+    int pdf_buffer_size,
     int page_number,
     const RenderingSettings& settings,
     void* bitmap_buffer) {
-  FPDF_DOCUMENT doc = pdf_handle;
+  FPDF_DOCUMENT doc =
+      FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr);
   if (!doc)
     return false;
   FPDF_PAGE page = FPDF_LoadPage(doc, page_number);
-  if (!page)
+  if (!page) {
+    FPDF_CloseDocument(doc);
     return false;
+  }
 
   pp::Rect dest;
   int rotate = CalculatePosition(page, settings, &dest);
@@ -4114,49 +4121,48 @@
       FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
   FPDFBitmap_Destroy(bitmap);
   FPDF_ClosePage(page);
+  FPDF_CloseDocument(doc);
   return true;
 }
 
 bool PDFiumEngineExports::GetPDFDocInfo(const void* pdf_buffer,
                                         int buffer_size,
                                         int* page_count,
-                                        double* max_page_width,
-                                        void** pdf_handle) {
+                                        double* max_page_width) {
   FPDF_DOCUMENT doc = FPDF_LoadMemDocument(pdf_buffer, buffer_size, nullptr);
   if (!doc)
     return false;
-
   int page_count_local = FPDF_GetPageCount(doc);
-  if (page_count)
+  if (page_count) {
     *page_count = page_count_local;
-
+  }
   if (max_page_width) {
     *max_page_width = 0;
     for (int page_number = 0; page_number < page_count_local; page_number++) {
       double page_width = 0;
       double page_height = 0;
       FPDF_GetPageSizeByIndex(doc, page_number, &page_width, &page_height);
-      *max_page_width = std::max(*max_page_width, page_width);
+      if (page_width > *max_page_width) {
+        *max_page_width = page_width;
+      }
     }
   }
-
-  if (pdf_handle)
-    *pdf_handle = doc;  // Caller takes ownership.
-  else
-    FPDF_CloseDocument(pdf_handle);
+  FPDF_CloseDocument(doc);
   return true;
 }
 
-void PDFiumEngineExports::ReleasePDFHandle(void* pdf_handle) {
-  FPDF_CloseDocument(pdf_handle);
-}
-
-bool PDFiumEngineExports::GetPDFPageSizeByIndex(void* pdf_handle,
+bool PDFiumEngineExports::GetPDFPageSizeByIndex(const void* pdf_buffer,
+                                                int pdf_buffer_size,
                                                 int page_number,
                                                 double* width,
                                                 double* height) {
-  FPDF_DOCUMENT doc = pdf_handle;
-  return doc && FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0;
+  FPDF_DOCUMENT doc =
+      FPDF_LoadMemDocument(pdf_buffer, pdf_buffer_size, nullptr);
+  if (!doc)
+    return false;
+  bool success = FPDF_GetPageSizeByIndex(doc, page_number, width, height) != 0;
+  FPDF_CloseDocument(doc);
+  return success;
 }
 
 }  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 4795b16..0334a602 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -771,7 +771,8 @@
 
 // PDFEngineExports:
 #if defined(OS_WIN)
-  bool RenderPDFPageToDC(void* pdf_handle,
+  bool RenderPDFPageToDC(const void* pdf_buffer,
+                         int buffer_size,
                          int page_number,
                          const RenderingSettings& settings,
                          HDC dc) override;
@@ -780,17 +781,17 @@
 
   void SetPDFUseGDIPrinting(bool enable) override;
 #endif  // defined(OS_WIN)
-  bool RenderPDFPageToBitmap(void* pdf_handle,
+  bool RenderPDFPageToBitmap(const void* pdf_buffer,
+                             int pdf_buffer_size,
                              int page_number,
                              const RenderingSettings& settings,
                              void* bitmap_buffer) override;
   bool GetPDFDocInfo(const void* pdf_buffer,
                      int buffer_size,
                      int* page_count,
-                     double* max_page_width,
-                     void** pdf_handle) override;
-  void ReleasePDFHandle(void* pdf_handle) override;
-  bool GetPDFPageSizeByIndex(void* pdf_handle,
+                     double* max_page_width) override;
+  bool GetPDFPageSizeByIndex(const void* pdf_buffer,
+                             int pdf_buffer_size,
                              int page_number,
                              double* width,
                              double* height) override;
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 227f8c1..a31706b 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -4385,6 +4385,24 @@
         "args": [
           "--deqp-egl-display-type=angle-gl"
         ],
+        "name": "angle_deqp_gles31_gl_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Linux"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles31_tests",
+        "use_xvfb": false
+      },
+      {
+        "args": [
+          "--deqp-egl-display-type=angle-gl"
+        ],
         "name": "angle_deqp_gles3_gl_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -13450,6 +13468,24 @@
       },
       {
         "args": [
+          "--deqp-egl-display-type=angle-gl"
+        ],
+        "name": "angle_deqp_gles31_gl_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ],
+          "shards": 4
+        },
+        "test": "angle_deqp_gles31_tests",
+        "use_xvfb": false
+      },
+      {
+        "args": [
           "--deqp-egl-display-type=angle-d3d11"
         ],
         "name": "angle_deqp_gles3_d3d11_tests",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 0c109f5..b94763bd 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -35,12 +35,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -250,15 +244,6 @@
         "test": "keyboard_unittests"
       },
       {
-        "args": [
-          "--override-use-gl-with-osmesa-for-tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "mash_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -562,12 +547,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -1022,12 +1001,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
@@ -1243,15 +1216,6 @@
         "test": "keyboard_unittests"
       },
       {
-        "args": [
-          "--override-use-gl-with-osmesa-for-tests"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "mash_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1509,12 +1473,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "ash_unittests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "aura_unittests"
       },
       {
diff --git a/testing/buildbot/filters/site-per-process.browser_tests.filter b/testing/buildbot/filters/site-per-process.browser_tests.filter
index bcc584f..f0b0ba2 100644
--- a/testing/buildbot/filters/site-per-process.browser_tests.filter
+++ b/testing/buildbot/filters/site-per-process.browser_tests.filter
@@ -18,3 +18,6 @@
 
 # crbug.com/669299: Wrong view frame source with --site-per-process
 -ChromeNavigationBrowserTest.TestViewFrameSource
+
+# crbug.com/670362: Flaky failure (expected MouseDown not found)
+-DevToolsPixelOutputTests.TestLatencyInfoInstrumentation
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 4947dc9..c6d44074 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -103,6 +103,11 @@
     "type": "raw",
     "args": [],
   },
+  "angle_deqp_gles31_tests": {
+    "label": "//third_party/angle/src/tests:angle_deqp_gles31_tests",
+    "type": "raw",
+    "args": [],
+  },
   "angle_end2end_tests": {
     "label": "//third_party/angle/src/tests:angle_end2end_tests",
     "type": "raw",
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations
index c4b857c7..365b239 100644
--- a/third_party/WebKit/LayoutTests/LeakExpectations
+++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -37,6 +37,8 @@
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/touch-scroll-customization.html [ Leak ]
 crbug.com/410974 virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scrollstate-distribute-to-scroll-chain-descendant.html [ Leak ]
 
+crbug.com/670324 fast/speech/scripted/speechrecognition-restart-onend.html [ Leak ]
+
 # -----------------------------------------------------------------
 # Untriaged but known real leaks.
 # -----------------------------------------------------------------
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index babcb0e..3ff58b2 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1627,6 +1627,7 @@
 crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/upload-progress-events.html [ Failure Timeout ]
 crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/upload-onprogress-event.html [ Failure ]
 crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html [ Timeout ]
+crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob-sync.html [ Pass Timeout ]
 
 crbug.com/669357 virtual/mojo-loading/http/tests/inspector/network/network-fetch.html [ Failure ]
 crbug.com/669357 virtual/mojo-loading/http/tests/inspector-protocol/network-data-length.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha-expected.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha-expected.html
new file mode 100644
index 0000000..f043213
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha-expected.html
@@ -0,0 +1,40 @@
+<html>
+<body>
+<canvas id="canvas" width="600" height="100" ></canvas>
+<script>
+var canvas = document.createElement("canvas");
+canvas.width = canvas.height = 100;
+var context = canvas.getContext("2d");
+context.fillStyle = 'green';
+context.fillRect(0, 0, 100, 100);
+var canvas2 = document.createElement("canvas");
+var context2 = canvas2.getContext("2d");
+var drawCanvas = document.getElementById("canvas");
+var drawCtx = drawCanvas.getContext("2d");
+
+context2.globalAlpha = 0.0;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 0, 0, 100, 100);
+
+context2.globalAlpha = 0.2;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 100, 0, 100, 100);
+
+context2.globalAlpha = 0.4;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 200, 0, 100, 100);
+
+context2.globalAlpha = 0.6;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 300, 0, 100, 100);
+
+context2.globalAlpha = 0.8;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 400, 0, 100, 100);
+
+context2.globalAlpha = 1.0;
+context2.drawImage(canvas, 0, 0);
+drawCtx.drawImage(canvas2, 0, 0, 100, 100, 500, 0, 100, 100);
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha.html b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha.html
new file mode 100644
index 0000000..982e1d23
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/canvas/OffscreenCanvas-2d-globalAlpha.html
@@ -0,0 +1,40 @@
+<html>
+<body>
+<canvas id="canvas" width="600" height="100" ></canvas>
+<script>
+var canvas = document.getElementById("canvas");
+var context = canvas.getContext("2d");
+
+var offscreenCanvas1 = new OffscreenCanvas(100, 100);
+var ctx1 = offscreenCanvas1.getContext('2d');
+ctx1.fillStyle = 'green';
+ctx1.fillRect(0, 0, 100, 100);
+var offscreenCanvas2 = new OffscreenCanvas(100, 100);
+var ctx2 = offscreenCanvas2.getContext('2d');
+
+ctx2.globalAlpha = 0.0;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 0, 0, 100, 100);
+
+ctx2.globalAlpha = 0.2;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 100, 0, 100, 100);
+
+ctx2.globalAlpha = 0.4;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 200, 0, 100, 100);
+
+ctx2.globalAlpha = 0.6;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 300, 0, 100, 100);
+
+ctx2.globalAlpha = 0.8;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 400, 0, 100, 100);
+
+ctx2.globalAlpha = 1.0;
+ctx2.drawImage(offscreenCanvas1, 0, 0);
+context.drawImage(offscreenCanvas2, 0, 0, 100, 100, 500, 0, 100, 100);
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html
new file mode 100644
index 0000000..16ed9c0c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaStreamTrack-clone.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<canvas id="canvas"/>
+<script>
+
+createTrack = function() {
+  ac = new AudioContext();
+  var osc = ac.createOscillator();
+  var dest = ac.createMediaStreamDestination();
+  osc.connect(dest);
+  return dest.stream.getAudioTracks()[0];
+}
+
+test(t => {
+  track = createTrack();
+  var original_id = track.id;
+  track_clone = track.clone();
+  assert_not_equals(track.id, track_clone.id);
+}, "Cloned MediaStreamTracks have new IDs");
+
+test(t => {
+  track = createTrack();
+  assert_true(track.enabled);
+  track.enabled = false;
+  assert_false(track.enabled);
+
+  track_clone = track.clone();
+  assert_false(track_clone.enabled,
+               "Clones of disabled tracks should still be disabled.");
+  track_clone.enabled = true;
+  assert_not_equals(track.enabled, track_clone.enabled,
+                    "Tracks enabled status should not be linked.");
+}, "Clones of disabled MediaStreamTracks are still disabled.");
+
+// TODO(pbos): Add tests that make sure muted and stopped properties are
+// carried over. Part of crbug:669212.
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 419d0ea..087e8a8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -486,6 +486,7 @@
 interface OffscreenCanvasRenderingContext2D
     getter canvas
     getter fillStyle
+    getter globalAlpha
     getter globalCompositeOperation
     getter imageSmoothingEnabled
     getter imageSmoothingQuality
@@ -535,6 +536,7 @@
     method transform
     method translate
     setter fillStyle
+    setter globalAlpha
     setter globalCompositeOperation
     setter imageSmoothingEnabled
     setter imageSmoothingQuality
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/preload/dynamic_remove_preload_href-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/http/tests/preload/dynamic_remove_preload_href-expected.txt
deleted file mode 100644
index effbabc..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/preload/dynamic_remove_preload_href-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 14: <link rel=preload> has an invalid `href` value
-This is a testharness.js-based test.
-FAIL Makes sure that dynamically removed preloaded resource stop downloading assert_equals: expected 3 but got 4
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.png
index b4290cd..42920c6 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.txt
index c92da46..22d1a362 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/search/search-rtl-expected.txt
@@ -37,19 +37,19 @@
           text run at (0,0) width 37: "PASS"
 layer at (23,45) size 157x16
   LayoutBlockFlow {DIV} at (0,0) size 157x16
-    LayoutText {#text} at (14,0) size 143x16
-      text run at (14,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
-      text run at (37,0) width 21: "she"
-      text run at (58,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
-      text run at (104,0) width 14: "he"
+    LayoutText {#text} at (31,0) size 126x16
+      text run at (31,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
+      text run at (54,0) width 9: "B"
+      text run at (63,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
+      text run at (109,0) width 9: "A"
       text run at (118,0) width 39 RTL: "\x{5D4}\x{5D5}\x{5D0} \x{5D6}\x{5D4} "
 layer at (23,67) size 227x16
   LayoutBlockFlow {DIV} at (0,0) size 227x16
-    LayoutText {#text} at (84,0) size 143x16
-      text run at (84,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
-      text run at (107,0) width 21: "she"
-      text run at (128,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
-      text run at (174,0) width 14: "he"
+    LayoutText {#text} at (101,0) size 126x16
+      text run at (101,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
+      text run at (124,0) width 9: "B"
+      text run at (133,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
+      text run at (179,0) width 9: "A"
       text run at (188,0) width 39 RTL: "\x{5D4}\x{5D5}\x{5D0} \x{5D6}\x{5D4} "
 layer at (23,89) size 157x16
   LayoutBlockFlow {DIV} at (0,0) size 157x16
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.png b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.png
deleted file mode 100644
index 42920c6..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.txt
deleted file mode 100644
index 22d1a362..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/fast/forms/search/search-rtl-expected.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x600
-  LayoutBlockFlow {HTML} at (0,0) size 800x600
-    LayoutBlockFlow {BODY} at (8,8) size 784x576
-      LayoutBlockFlow {P} at (0,0) size 784x18
-        LayoutText {#text} at (0,0) size 54x17
-          text run at (0,0) width 54: "Test for "
-        LayoutInline {I} at (0,0) size 703x17
-          LayoutInline {A} at (0,0) size 304x17 [color=#0000EE]
-            LayoutText {#text} at (53,0) size 304x17
-              text run at (53,0) width 304: "http://bugs.webkit.org/show_bug.cgi?id=11916"
-          LayoutText {#text} at (356,0) size 400x17
-            text run at (356,0) width 5: " "
-            text run at (360,0) width 396: "REGRESSION (SearchField): RTL search fields are mixed up"
-        LayoutText {#text} at (755,0) size 5x17
-          text run at (755,0) width 5: "."
-      LayoutBlockFlow {P} at (0,34) size 784x66
-        LayoutTextControl {INPUT} at (0,0) size 175x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
-          LayoutFlexibleBox {DIV} at (3,3) size 169x16
-            LayoutBlockFlow {DIV} at (12,0) size 157x16
-        LayoutText {#text} at (175,2) size 4x17
-          text run at (175,2) width 4: " "
-        LayoutBR {BR} at (0,0) size 0x0
-        LayoutTextControl {INPUT} at (0,22) size 245x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
-          LayoutFlexibleBox {DIV} at (3,3) size 239x16
-            LayoutBlockFlow {DIV} at (12,0) size 227x16
-        LayoutText {#text} at (245,24) size 4x17
-          text run at (245,24) width 4: " "
-        LayoutBR {BR} at (0,0) size 0x0
-        LayoutTextControl {INPUT} at (0,44) size 175x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
-          LayoutFlexibleBox {DIV} at (3,3) size 169x16
-            LayoutBlockFlow {DIV} at (12,0) size 157x16
-        LayoutText {#text} at (0,0) size 0x0
-      LayoutBlockFlow {P} at (0,116) size 784x18
-        LayoutText {#text} at (0,0) size 37x17
-          text run at (0,0) width 37: "PASS"
-layer at (23,45) size 157x16
-  LayoutBlockFlow {DIV} at (0,0) size 157x16
-    LayoutText {#text} at (31,0) size 126x16
-      text run at (31,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
-      text run at (54,0) width 9: "B"
-      text run at (63,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
-      text run at (109,0) width 9: "A"
-      text run at (118,0) width 39 RTL: "\x{5D4}\x{5D5}\x{5D0} \x{5D6}\x{5D4} "
-layer at (23,67) size 227x16
-  LayoutBlockFlow {DIV} at (0,0) size 227x16
-    LayoutText {#text} at (101,0) size 126x16
-      text run at (101,0) width 23 RTL: " \x{5D5}\x{5D6}\x{5D4}\x{5D5}"
-      text run at (124,0) width 9: "B"
-      text run at (133,0) width 46 RTL: " \x{5D5}\x{5D4}\x{5D9}\x{5D0} \x{5D6}\x{5D4} "
-      text run at (179,0) width 9: "A"
-      text run at (188,0) width 39 RTL: "\x{5D4}\x{5D5}\x{5D0} \x{5D6}\x{5D4} "
-layer at (23,89) size 157x16
-  LayoutBlockFlow {DIV} at (0,0) size 157x16
-layer at (11,49) size 9x9 transparent
-  LayoutBlockFlow {DIV} at (0,3.50) size 9x9
-layer at (11,71) size 9x9 transparent
-  LayoutBlockFlow {DIV} at (0,3.50) size 9x9
-layer at (11,93) size 9x9 transparent
-  LayoutBlockFlow {DIV} at (0,3.50) size 9x9
-caret: position 0 of child 0 {DIV} of child 0 {DIV} of child 0 {DIV} of {#document-fragment} of child 9 {INPUT} of child 3 {P} of body
diff --git a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index 9812097..f7e4f6a 100644
--- a/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/service-worker-navigation-preload/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -493,6 +493,7 @@
 interface OffscreenCanvasRenderingContext2D
     getter canvas
     getter fillStyle
+    getter globalAlpha
     getter globalCompositeOperation
     getter imageSmoothingEnabled
     getter imageSmoothingQuality
@@ -542,6 +543,7 @@
     method transform
     method translate
     setter fillStyle
+    setter globalAlpha
     setter globalCompositeOperation
     setter imageSmoothingEnabled
     setter imageSmoothingQuality
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index a6730407..f7914d1 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -503,6 +503,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     getter canvas
 [Worker]     getter fillStyle
+[Worker]     getter globalAlpha
 [Worker]     getter globalCompositeOperation
 [Worker]     getter imageSmoothingEnabled
 [Worker]     getter imageSmoothingQuality
@@ -552,6 +553,7 @@
 [Worker]     method transform
 [Worker]     method translate
 [Worker]     setter fillStyle
+[Worker]     setter globalAlpha
 [Worker]     setter globalCompositeOperation
 [Worker]     setter imageSmoothingEnabled
 [Worker]     setter imageSmoothingQuality
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 4f1230b..085f5e3 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4367,6 +4367,7 @@
     getter canvas
     getter fillStyle
     getter filter
+    getter globalAlpha
     getter globalCompositeOperation
     getter imageSmoothingEnabled
     getter imageSmoothingQuality
@@ -4417,6 +4418,7 @@
     method translate
     setter fillStyle
     setter filter
+    setter globalAlpha
     setter globalCompositeOperation
     setter imageSmoothingEnabled
     setter imageSmoothingQuality
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index a5cc7547..54c6ae4 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -498,6 +498,7 @@
 [Worker]     attribute @@toStringTag
 [Worker]     getter canvas
 [Worker]     getter fillStyle
+[Worker]     getter globalAlpha
 [Worker]     getter globalCompositeOperation
 [Worker]     getter imageSmoothingEnabled
 [Worker]     getter imageSmoothingQuality
@@ -547,6 +548,7 @@
 [Worker]     method transform
 [Worker]     method translate
 [Worker]     setter fillStyle
+[Worker]     setter globalAlpha
 [Worker]     setter globalCompositeOperation
 [Worker]     setter imageSmoothingEnabled
 [Worker]     setter imageSmoothingQuality
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
index ede7f72..920d5b80 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp
@@ -257,7 +257,7 @@
                    : ScanOnly),
       m_preloader(preloader),
       m_resource(toCSSStyleSheetResource(resource)) {
-  m_resource->addClient(this);
+  m_resource->addClient(this, Resource::DontMarkAsReferenced);
 }
 
 CSSPreloaderResourceClient::~CSSPreloaderResourceClient() {}
diff --git a/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp b/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
index ff92e2b..428b8935 100644
--- a/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/CSSPreloadScannerTest.cpp
@@ -58,6 +58,7 @@
   const char* data = "@import url('http://127.0.0.1/preload.css');";
   resource->appendData(data, strlen(data));
 
+  EXPECT_EQ(Resource::PreloadNotReferenced, resource->getPreloadResult());
   EXPECT_EQ(1u, resourceClient->m_preloads.size());
   EXPECT_EQ("http://127.0.0.1/preload.css",
             resourceClient->m_preloads.front()->resourceURL());
diff --git a/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp b/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
index 4c8d7d9..6a8fdaa8 100644
--- a/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
+++ b/third_party/WebKit/Source/modules/mediacapturefromelement/CanvasCaptureMediaStreamTrack.cpp
@@ -40,8 +40,7 @@
 
 CanvasCaptureMediaStreamTrack* CanvasCaptureMediaStreamTrack::clone(
     ExecutionContext* context) {
-  MediaStreamComponent* clonedComponent =
-      MediaStreamComponent::create(component()->source());
+  MediaStreamComponent* clonedComponent = component()->clone();
   CanvasCaptureMediaStreamTrack* clonedTrack =
       new CanvasCaptureMediaStreamTrack(*this, clonedComponent);
   MediaStreamCenter::instance().didCreateMediaStreamTrack(clonedComponent);
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
index 0e4d5d1..f27b7db 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/MediaStreamTrack.cpp
@@ -139,8 +139,9 @@
 }
 
 MediaStreamTrack* MediaStreamTrack::clone(ExecutionContext* context) {
-  MediaStreamComponent* clonedComponent =
-      MediaStreamComponent::create(component()->source());
+  // TODO(pbos): Make sure m_readyState and m_stopped carries over on cloned
+  // tracks.
+  MediaStreamComponent* clonedComponent = component()->clone();
   MediaStreamTrack* clonedTrack =
       MediaStreamTrack::create(context, clonedComponent);
   MediaStreamCenter::instance().didCreateMediaStreamTrack(clonedComponent);
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp
index 0042689..64819e62 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.cpp
@@ -14,30 +14,11 @@
 #include "platform/network/ResourceRequest.h"
 #include "platform/weborigin/KURL.h"
 #include "public/platform/WebURLRequest.h"
-#include "public/platform/modules/notifications/WebNotificationConstants.h"
-#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/Threading.h"
 #include <memory>
 
-#define NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, type_name, value, max) \
-  case NotificationImageLoader::Type::type_name: {                            \
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(                                          \
-        CustomCountHistogram, metric##type_name##Histogram,                   \
-        new CustomCountHistogram("Notifications." #metric "." #type_name,     \
-                                 1 /* min */, max, 50 /* buckets */));        \
-    metric##type_name##Histogram.count(value);                                \
-    break;                                                                    \
-  }
-
-#define NOTIFICATION_HISTOGRAM_COUNTS(metric, type, value, max)            \
-  switch (type) {                                                          \
-    NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Image, value, max)      \
-    NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Icon, value, max)       \
-    NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, Badge, value, max)      \
-    NOTIFICATION_PER_TYPE_HISTOGRAM_COUNTS(metric, ActionIcon, value, max) \
-  }
-
 namespace {
 
 // 99.9% of all images were fetched successfully in 90 seconds.
@@ -47,53 +28,11 @@
 
 namespace blink {
 
-NotificationImageLoader::NotificationImageLoader(Type type)
-    : m_type(type), m_stopped(false), m_startTime(0.0) {}
+NotificationImageLoader::NotificationImageLoader()
+    : m_stopped(false), m_startTime(0.0) {}
 
 NotificationImageLoader::~NotificationImageLoader() {}
 
-// static
-SkBitmap NotificationImageLoader::scaleDownIfNeeded(const SkBitmap& image,
-                                                    Type type) {
-  int maxWidthPx = 0, maxHeightPx = 0;
-  switch (type) {
-    case Type::Image:
-      maxWidthPx = kWebNotificationMaxImageWidthPx;
-      maxHeightPx = kWebNotificationMaxImageHeightPx;
-      break;
-    case Type::Icon:
-      maxWidthPx = kWebNotificationMaxIconSizePx;
-      maxHeightPx = kWebNotificationMaxIconSizePx;
-      break;
-    case Type::Badge:
-      maxWidthPx = kWebNotificationMaxBadgeSizePx;
-      maxHeightPx = kWebNotificationMaxBadgeSizePx;
-      break;
-    case Type::ActionIcon:
-      maxWidthPx = kWebNotificationMaxActionIconSizePx;
-      maxHeightPx = kWebNotificationMaxActionIconSizePx;
-      break;
-  }
-  DCHECK_GT(maxWidthPx, 0);
-  DCHECK_GT(maxHeightPx, 0);
-  // TODO(peter): Explore doing the scaling on a background thread.
-  if (image.width() > maxWidthPx || image.height() > maxHeightPx) {
-    double scale = std::min(static_cast<double>(maxWidthPx) / image.width(),
-                            static_cast<double>(maxHeightPx) / image.height());
-    double startTime = monotonicallyIncreasingTimeMS();
-    // TODO(peter): Try using RESIZE_BETTER for large images.
-    SkBitmap scaledImage =
-        skia::ImageOperations::Resize(image, skia::ImageOperations::RESIZE_BEST,
-                                      std::lround(scale * image.width()),
-                                      std::lround(scale * image.height()));
-    NOTIFICATION_HISTOGRAM_COUNTS(LoadScaleDownTime, type,
-                                  monotonicallyIncreasingTimeMS() - startTime,
-                                  1000 * 10 /* 10 seconds max */);
-    return scaledImage;
-  }
-  return image;
-}
-
 void NotificationImageLoader::start(
     ExecutionContext* executionContext,
     const KURL& url,
@@ -150,13 +89,19 @@
   if (m_stopped)
     return;
 
-  NOTIFICATION_HISTOGRAM_COUNTS(LoadFinishTime, m_type,
-                                monotonicallyIncreasingTimeMS() - m_startTime,
-                                1000 * 60 * 60 /* 1 hour max */);
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(
+      CustomCountHistogram, finishedTimeHistogram,
+      new CustomCountHistogram("Notifications.Icon.LoadFinishTime", 1,
+                               1000 * 60 * 60 /* 1 hour max */,
+                               50 /* buckets */));
+  finishedTimeHistogram.count(monotonicallyIncreasingTimeMS() - m_startTime);
 
   if (m_data) {
-    NOTIFICATION_HISTOGRAM_COUNTS(LoadFileSize, m_type, m_data->size(),
-                                  10000000 /* ~10mb max */);
+    DEFINE_THREAD_SAFE_STATIC_LOCAL(
+        CustomCountHistogram, fileSizeHistogram,
+        new CustomCountHistogram("Notifications.Icon.FileSize", 1,
+                                 10000000 /* ~10mb max */, 50 /* buckets */));
+    fileSizeHistogram.count(m_data->size());
 
     std::unique_ptr<ImageDecoder> decoder = ImageDecoder::create(
         m_data, true /* dataComplete */, ImageDecoder::AlphaPremultiplied,
@@ -175,9 +120,12 @@
 }
 
 void NotificationImageLoader::didFail(const ResourceError& error) {
-  NOTIFICATION_HISTOGRAM_COUNTS(LoadFailTime, m_type,
-                                monotonicallyIncreasingTimeMS() - m_startTime,
-                                1000 * 60 * 60 /* 1 hour max */);
+  DEFINE_THREAD_SAFE_STATIC_LOCAL(
+      CustomCountHistogram, failedTimeHistogram,
+      new CustomCountHistogram("Notifications.Icon.LoadFailTime", 1,
+                               1000 * 60 * 60 /* 1 hour max */,
+                               50 /* buckets */));
+  failedTimeHistogram.count(monotonicallyIncreasingTimeMS() - m_startTime);
 
   runCallbackWithEmptyBitmap();
 }
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.h b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.h
index 46e6be4..ea0cc3d 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.h
+++ b/third_party/WebKit/Source/modules/notifications/NotificationImageLoader.h
@@ -10,11 +10,12 @@
 #include "modules/ModulesExport.h"
 #include "platform/SharedBuffer.h"
 #include "platform/heap/Handle.h"
-#include "third_party/skia/include/core/SkBitmap.h"
 #include "wtf/Functional.h"
 #include "wtf/RefPtr.h"
 #include <memory>
 
+class SkBitmap;
+
 namespace blink {
 
 class ExecutionContext;
@@ -27,20 +28,13 @@
     : public GarbageCollectedFinalized<NotificationImageLoader>,
       public ThreadableLoaderClient {
  public:
-  // Type names are used in UMAs, so do not rename.
-  enum class Type { Image, Icon, Badge, ActionIcon };
-
   // The bitmap may be empty if the request failed or the image data could not
   // be decoded.
   using ImageCallback = Function<void(const SkBitmap&)>;
 
-  explicit NotificationImageLoader(Type);
+  NotificationImageLoader();
   ~NotificationImageLoader() override;
 
-  // Scales down |image| according to its type and returns result. If it is
-  // already small enough, |image| is returned unchanged.
-  static SkBitmap scaleDownIfNeeded(const SkBitmap& image, Type);
-
   // Asynchronously downloads an image from the given url, decodes the loaded
   // data, and passes the bitmap to the callback. Times out if the load takes
   // too long and ImageCallback is invoked with an empty bitmap.
@@ -62,7 +56,6 @@
  private:
   void runCallbackWithEmptyBitmap();
 
-  Type m_type;
   bool m_stopped;
   double m_startTime;
   RefPtr<SharedBuffer> m_data;
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp b/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
index 4072119..bcb59f4 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationImageLoaderTest.cpp
@@ -7,7 +7,6 @@
 #include "core/dom/ExecutionContext.h"
 #include "core/fetch/MemoryCache.h"
 #include "core/testing/DummyPageHolder.h"
-#include "platform/testing/HistogramTester.h"
 #include "platform/testing/TestingPlatformSupport.h"
 #include "platform/testing/URLTestHelpers.h"
 #include "public/platform/Platform.h"
@@ -36,9 +35,7 @@
  public:
   NotificationImageLoaderTest()
       : m_page(DummyPageHolder::create()),
-        // Use an arbitrary type, since it only affects which UMA bucket we use.
-        m_loader(
-            new NotificationImageLoader(NotificationImageLoader::Type::Icon)) {}
+        m_loader(new NotificationImageLoader()) {}
 
   ~NotificationImageLoaderTest() override {
     m_loader->stop();
@@ -73,9 +70,6 @@
   ExecutionContext* context() const { return &m_page->document(); }
   LoadState loaded() const { return m_loaded; }
 
- protected:
-  HistogramTester m_histogramTester;
-
  private:
   std::unique_ptr<DummyPageHolder> m_page;
   Persistent<NotificationImageLoader> m_loader;
@@ -85,18 +79,8 @@
 TEST_F(NotificationImageLoaderTest, SuccessTest) {
   KURL url = registerMockedURL(kIcon500x500);
   loadImage(url);
-  m_histogramTester.expectTotalCount("Notifications.LoadFinishTime.Icon", 0);
-  m_histogramTester.expectTotalCount("Notifications.LoadFileSize.Icon", 0);
-  m_histogramTester.expectTotalCount("Notifications.LoadFailTime.Icon", 0);
   Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests();
   EXPECT_EQ(LoadState::kLoadSuccessful, loaded());
-  m_histogramTester.expectUniqueSample("Notifications.LoadFileSize.Icon", 7439,
-                                       1);
-  m_histogramTester.expectTotalCount("Notifications.LoadFailTime.Icon", 0);
-  // Should log a non-zero finish time.
-  m_histogramTester.expectTotalCount("Notifications.LoadFinishTime.Icon", 1);
-  m_histogramTester.expectBucketCount("Notifications.LoadFinishTime.Icon", 0,
-                                      0);
 }
 
 TEST_F(NotificationImageLoaderTest, TimeoutTest) {
@@ -110,20 +94,12 @@
   // result in a timeout.
   testingPlatform.runForPeriodSeconds(kImageFetchTimeoutInMs / 1000 - 1);
   EXPECT_EQ(LoadState::kNotLoaded, loaded());
-  m_histogramTester.expectTotalCount("Notifications.LoadFinishTime.Icon", 0);
-  m_histogramTester.expectTotalCount("Notifications.LoadFileSize.Icon", 0);
-  m_histogramTester.expectTotalCount("Notifications.LoadFailTime.Icon", 0);
 
   // Now advance time until a timeout should be expected.
   testingPlatform.runForPeriodSeconds(2);
 
   // If the loader times out, it calls the callback and returns an empty bitmap.
   EXPECT_EQ(LoadState::kLoadFailed, loaded());
-  m_histogramTester.expectTotalCount("Notifications.LoadFinishTime.Icon", 0);
-  m_histogramTester.expectTotalCount("Notifications.LoadFileSize.Icon", 0);
-  // Should log a non-zero failure time.
-  m_histogramTester.expectTotalCount("Notifications.LoadFailTime.Icon", 1);
-  m_histogramTester.expectBucketCount("Notifications.LoadFailTime.Icon", 0, 0);
 }
 
 }  // namspace
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.cpp b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.cpp
index fb717c2..7c4a01cd 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.cpp
+++ b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.cpp
@@ -6,14 +6,47 @@
 
 #include "platform/Histogram.h"
 #include "platform/weborigin/KURL.h"
+#include "public/platform/modules/notifications/WebNotificationConstants.h"
 #include "public/platform/modules/notifications/WebNotificationData.h"
 #include "public/platform/modules/notifications/WebNotificationResources.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkBitmap.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/Threading.h"
 #include <cmath>
 
 namespace blink {
 
+namespace {
+
+// Scales down |image| to fit within |maxWidthPx|x|maxHeightPx| if it is larger
+// and returns the result. Otherwise does nothing and returns |image| unchanged.
+// TODO(mvanouwerkerk): Explore doing the scaling on a background thread.
+SkBitmap scaleDownIfNeeded(const SkBitmap& image,
+                           int maxWidthPx,
+                           int maxHeightPx) {
+  if (image.width() > maxWidthPx || image.height() > maxHeightPx) {
+    double scale = std::min(static_cast<double>(maxWidthPx) / image.width(),
+                            static_cast<double>(maxHeightPx) / image.height());
+    DEFINE_THREAD_SAFE_STATIC_LOCAL(
+        CustomCountHistogram, scaleTimeHistogram,
+        new CustomCountHistogram("Notifications.Icon.ScaleDownTime", 1,
+                                 1000 * 10 /* 10 seconds max */,
+                                 50 /* buckets */));
+    double startTime = monotonicallyIncreasingTimeMS();
+    // TODO(peter): Try using RESIZE_BETTER for large images.
+    SkBitmap scaledImage =
+        skia::ImageOperations::Resize(image, skia::ImageOperations::RESIZE_BEST,
+                                      std::lround(scale * image.width()),
+                                      std::lround(scale * image.height()));
+    scaleTimeHistogram.count(monotonicallyIncreasingTimeMS() - startTime);
+    return scaledImage;
+  }
+  return image;
+}
+
+}  // namespace
+
 NotificationResourcesLoader::NotificationResourcesLoader(
     std::unique_ptr<CompletionCallback> completionCallback)
     : m_started(false),
@@ -36,23 +69,19 @@
 
   // TODO(johnme): ensure image is not loaded when it will not be used.
   // TODO(mvanouwerkerk): ensure no badge is loaded when it will not be used.
-  loadImage(executionContext, NotificationImageLoader::Type::Image,
-            notificationData.image,
+  loadImage(executionContext, notificationData.image,
             WTF::bind(&NotificationResourcesLoader::didLoadImage,
                       wrapWeakPersistent(this)));
-  loadImage(executionContext, NotificationImageLoader::Type::Icon,
-            notificationData.icon,
+  loadImage(executionContext, notificationData.icon,
             WTF::bind(&NotificationResourcesLoader::didLoadIcon,
                       wrapWeakPersistent(this)));
-  loadImage(executionContext, NotificationImageLoader::Type::Badge,
-            notificationData.badge,
+  loadImage(executionContext, notificationData.badge,
             WTF::bind(&NotificationResourcesLoader::didLoadBadge,
                       wrapWeakPersistent(this)));
 
   m_actionIcons.resize(numActions);
   for (size_t i = 0; i < numActions; i++)
-    loadImage(executionContext, NotificationImageLoader::Type::ActionIcon,
-              notificationData.actions[i].icon,
+    loadImage(executionContext, notificationData.actions[i].icon,
               WTF::bind(&NotificationResourcesLoader::didLoadActionIcon,
                         wrapWeakPersistent(this), i));
 }
@@ -79,7 +108,6 @@
 
 void NotificationResourcesLoader::loadImage(
     ExecutionContext* executionContext,
-    NotificationImageLoader::Type type,
     const KURL& url,
     std::unique_ptr<NotificationImageLoader::ImageCallback> imageCallback) {
   if (url.isNull() || url.isEmpty() || !url.isValid()) {
@@ -87,26 +115,26 @@
     return;
   }
 
-  NotificationImageLoader* imageLoader = new NotificationImageLoader(type);
+  NotificationImageLoader* imageLoader = new NotificationImageLoader();
   m_imageLoaders.append(imageLoader);
   imageLoader->start(executionContext, url, std::move(imageCallback));
 }
 
 void NotificationResourcesLoader::didLoadImage(const SkBitmap& image) {
-  m_image = NotificationImageLoader::scaleDownIfNeeded(
-      image, NotificationImageLoader::Type::Image);
+  m_image = scaleDownIfNeeded(image, kWebNotificationMaxImageWidthPx,
+                              kWebNotificationMaxImageHeightPx);
   didFinishRequest();
 }
 
 void NotificationResourcesLoader::didLoadIcon(const SkBitmap& image) {
-  m_icon = NotificationImageLoader::scaleDownIfNeeded(
-      image, NotificationImageLoader::Type::Icon);
+  m_icon = scaleDownIfNeeded(image, kWebNotificationMaxIconSizePx,
+                             kWebNotificationMaxIconSizePx);
   didFinishRequest();
 }
 
 void NotificationResourcesLoader::didLoadBadge(const SkBitmap& image) {
-  m_badge = NotificationImageLoader::scaleDownIfNeeded(
-      image, NotificationImageLoader::Type::Badge);
+  m_badge = scaleDownIfNeeded(image, kWebNotificationMaxBadgeSizePx,
+                              kWebNotificationMaxBadgeSizePx);
   didFinishRequest();
 }
 
@@ -114,8 +142,9 @@
                                                     const SkBitmap& image) {
   DCHECK_LT(actionIndex, m_actionIcons.size());
 
-  m_actionIcons[actionIndex] = NotificationImageLoader::scaleDownIfNeeded(
-      image, NotificationImageLoader::Type::ActionIcon);
+  m_actionIcons[actionIndex] =
+      scaleDownIfNeeded(image, kWebNotificationMaxActionIconSizePx,
+                        kWebNotificationMaxActionIconSizePx);
   didFinishRequest();
 }
 
diff --git a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.h b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.h
index 4ab17e9..8f11042 100644
--- a/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.h
+++ b/third_party/WebKit/Source/modules/notifications/NotificationResourcesLoader.h
@@ -56,7 +56,6 @@
 
  private:
   void loadImage(ExecutionContext*,
-                 NotificationImageLoader::Type,
                  const KURL&,
                  std::unique_ptr<NotificationImageLoader::ImageCallback>);
   void didLoadImage(const SkBitmap& image);
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
index e088931..02c13f4 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.idl
@@ -63,6 +63,7 @@
     void resetTransform();
 
     // compositing
+    attribute unrestricted double globalAlpha; // (default 1.0)
     attribute DOMString globalCompositeOperation; // (default source-over)
 
     // image smoothing
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
index 40f4631..0bc3ea179 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
@@ -227,7 +227,40 @@
   if (m_frameBufferCache.size() <= 1)
     return 0;
 
-  return clearCacheExceptTwoFrames(clearExceptFrame, kNotFound);
+  // We expect that after this call, we'll be asked to decode frames after this
+  // one. So we want to avoid clearing frames such that those requests would
+  // force re-decoding from the beginning of the image. There are two cases in
+  // which preserving |clearCacheExcept| frame is not enough to avoid that:
+  //
+  // 1. |clearExceptFrame| is not yet sufficiently decoded to decode subsequent
+  //    frames. We need the previous frame to sufficiently decode this frame.
+  // 2. The disposal method of |clearExceptFrame| is DisposeOverwritePrevious.
+  //    In that case, we need to keep the required previous frame in the cache
+  //    to prevent re-decoding that frame when |clearExceptFrame| is disposed.
+  //
+  // If either 1 or 2 is true, store the required previous frame in
+  // |clearExceptFrame2| so it won't be cleared.
+  size_t clearExceptFrame2 = kNotFound;
+  if (clearExceptFrame < m_frameBufferCache.size()) {
+    const ImageFrame& frame = m_frameBufferCache[clearExceptFrame];
+    if (!frameStatusSufficientForSuccessors(clearExceptFrame) ||
+        frame.getDisposalMethod() == ImageFrame::DisposeOverwritePrevious)
+      clearExceptFrame2 = frame.requiredPreviousFrameIndex();
+  }
+
+  // Now |clearExceptFrame2| indicates the frame that |clearExceptFrame|
+  // depends on, as described above. But if decoding is skipping forward past
+  // intermediate frames, this frame may be insufficiently decoded. So we need
+  // to keep traversing back through the required previous frames until we find
+  // the nearest ancestor that is sufficiently decoded. Preserving that will
+  // minimize the amount of future decoding needed.
+  while (clearExceptFrame2 < m_frameBufferCache.size() &&
+         !frameStatusSufficientForSuccessors(clearExceptFrame2)) {
+    clearExceptFrame2 =
+        m_frameBufferCache[clearExceptFrame2].requiredPreviousFrameIndex();
+  }
+
+  return clearCacheExceptTwoFrames(clearExceptFrame, clearExceptFrame2);
 }
 
 size_t ImageDecoder::clearCacheExceptTwoFrames(size_t clearExceptFrame1,
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
index 04a5ccb..9124bb8 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -267,10 +267,21 @@
 
   bool failed() const { return m_failed; }
 
-  // Clears decoded pixel data from all frames except the provided frame.
+  // Clears decoded pixel data from all frames except the provided frame. If
+  // subsequent frames depend on this frame's required previous frame, then that
+  // frame is also kept in cache to prevent re-decoding from the beginning.
   // Callers may pass WTF::kNotFound to clear all frames.
   // Note: If |m_frameBufferCache| contains only one frame, it won't be cleared.
   // Returns the number of bytes of frame data actually cleared.
+  //
+  // This is a virtual method because MockImageDecoder needs to override it in
+  // order to run the test ImageFrameGeneratorTest::clearMultiFrameDecode.
+  //
+  // @TODO  Let MockImageDecoder override ImageFrame::clearFrameBuffer instead,
+  //        so this method can be made non-virtual. It is used in the test
+  //        ImageFrameGeneratorTest::clearMultiFrameDecode. The test needs to
+  //        be modified since two frames may be kept in cache, instead of
+  //        always just one, with this clearCacheExceptFrame implementation.
   virtual size_t clearCacheExceptFrame(size_t);
 
   // If the image has a cursor hot-spot, stores it in the argument
@@ -379,6 +390,26 @@
   // future decodes to purge old frames as it goes.
   void updateAggressivePurging(size_t index);
 
+  // The method is only relevant for multi-frame images.
+  //
+  // This method indicates whether the provided frame has enough data to decode
+  // successive frames that depend on it. It is used by clearCacheExceptFrame
+  // to determine which frame to keep in cache when the indicated frame is not
+  // yet sufficiently decoded.
+  //
+  // The default condition is that the frame status needs to be FramePartial or
+  // FrameComplete, since the data of previous frames is copied in
+  // initFrameBuffer() before setting the status to FramePartial. For WebP,
+  // however, the status needs to be FrameComplete since the complete buffer is
+  // used to do alpha blending in WEBPImageDecoder::applyPostProcessing().
+  //
+  // Before calling this, verify that frame |index| exists by checking that
+  // |index| is smaller than |m_frameBufferCache|.size().
+  virtual bool frameStatusSufficientForSuccessors(size_t index) {
+    DCHECK(index < m_frameBufferCache.size());
+    return m_frameBufferCache[index].getStatus() != ImageFrame::FrameEmpty;
+  }
+
  private:
   enum class SniffResult { JPEG, PNG, GIF, WEBP, ICO, BMP, Invalid };
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
index b09870a..2693402 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -233,42 +233,6 @@
   return true;
 }
 
-size_t GIFImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) {
-  // We expect that after this call, we'll be asked to decode frames after
-  // this one.  So we want to avoid clearing frames such that those requests
-  // would force re-decoding from the beginning of the image.
-  //
-  // When |clearExceptFrame| is e.g. DisposeKeep, simply not clearing that
-  // frame is sufficient, as the next frame will be based on it, and in
-  // general future frames can't be based on anything previous.
-  //
-  // However, if this frame is DisposeOverwritePrevious, then subsequent
-  // frames will depend on this frame's required previous frame.  In this
-  // case, we need to preserve both this frame and that one.
-  size_t clearExceptFrame2 = kNotFound;
-  if (clearExceptFrame < m_frameBufferCache.size()) {
-    const ImageFrame& frame = m_frameBufferCache[clearExceptFrame];
-    if ((frame.getStatus() != ImageFrame::FrameEmpty) &&
-        (frame.getDisposalMethod() == ImageFrame::DisposeOverwritePrevious)) {
-      clearExceptFrame2 = clearExceptFrame;
-      clearExceptFrame = frame.requiredPreviousFrameIndex();
-    }
-  }
-
-  // Now |clearExceptFrame| indicates the frame that future frames will
-  // depend on.  But if decoding is skipping forward past intermediate frames,
-  // this frame may be FrameEmpty.  So we need to keep traversing back through
-  // the required previous frames until we find the nearest non-empty
-  // ancestor.  Preserving that will minimize the amount of future decoding
-  // needed.
-  while ((clearExceptFrame < m_frameBufferCache.size()) &&
-         (m_frameBufferCache[clearExceptFrame].getStatus() ==
-          ImageFrame::FrameEmpty))
-    clearExceptFrame =
-        m_frameBufferCache[clearExceptFrame].requiredPreviousFrameIndex();
-  return clearCacheExceptTwoFrames(clearExceptFrame, clearExceptFrame2);
-}
-
 void GIFImageDecoder::clearFrameBuffer(size_t frameIndex) {
   if (m_reader &&
       m_frameBufferCache[frameIndex].getStatus() == ImageFrame::FramePartial) {
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.h
index b4b5c35..0f68eb0 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoder.h
@@ -55,7 +55,6 @@
   int repetitionCount() const override;
   bool frameIsCompleteAtIndex(size_t) const override;
   float frameDurationAtIndex(size_t) const override;
-  size_t clearCacheExceptFrame(size_t) override;
   // CAUTION: setFailed() deletes |m_reader|.  Be careful to avoid
   // accessing deleted memory, especially when calling this from inside
   // GIFImageReader!
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
index a3fa61c..bbfec45 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.cpp
@@ -269,35 +269,6 @@
          ImageFrame::BlendAtopPreviousFrame;
 }
 
-size_t WEBPImageDecoder::clearCacheExceptFrame(size_t clearExceptFrame) {
-  // Don't clear if there are no frames, or only one.
-  if (m_frameBufferCache.size() <= 1)
-    return 0;
-
-  // If |clearExceptFrame| has status FrameComplete, we only preserve that
-  // frame.  Otherwise, we *also* preserve the most recent previous frame with
-  // status FrameComplete whose data will be required to decode
-  // |clearExceptFrame|, either in initFrameBuffer() or ApplyPostProcessing().
-  // This frame index is stored in |clearExceptFrame2|.  All other frames can
-  // be cleared.
-  size_t clearExceptFrame2 = kNotFound;
-  if (clearExceptFrame < m_frameBufferCache.size() &&
-      m_frameBufferCache[clearExceptFrame].getStatus() !=
-          ImageFrame::FrameComplete) {
-    clearExceptFrame2 =
-        m_frameBufferCache[clearExceptFrame].requiredPreviousFrameIndex();
-  }
-
-  while ((clearExceptFrame2 < m_frameBufferCache.size()) &&
-         (m_frameBufferCache[clearExceptFrame2].getStatus() !=
-          ImageFrame::FrameComplete)) {
-    clearExceptFrame2 =
-        m_frameBufferCache[clearExceptFrame2].requiredPreviousFrameIndex();
-  }
-
-  return clearCacheExceptTwoFrames(clearExceptFrame, clearExceptFrame2);
-}
-
 void WEBPImageDecoder::clearFrameBuffer(size_t frameIndex) {
   if (m_demux && m_demuxState >= WEBP_DEMUX_PARSED_HEADER &&
       m_frameBufferCache[frameIndex].getStatus() == ImageFrame::FramePartial) {
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
index d33de58..946d7cc 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoder.h
@@ -53,7 +53,6 @@
   int repetitionCount() const override;
   bool frameIsCompleteAtIndex(size_t) const override;
   float frameDurationAtIndex(size_t) const override;
-  size_t clearCacheExceptFrame(size_t) override;
 
  private:
   // ImageDecoder:
@@ -66,6 +65,17 @@
                          size_t dataSize,
                          size_t frameIndex);
 
+  // For WebP images, the frame status needs to be FrameComplete to decode
+  // subsequent frames that depend on frame |index|. The reason for this is that
+  // WebP uses the previous frame for alpha blending, in applyPostProcessing().
+  //
+  // Before calling this, verify that frame |index| exists by checking that
+  // |index| is smaller than |m_frameBufferCache|.size().
+  bool frameStatusSufficientForSuccessors(size_t index) override {
+    DCHECK(index < m_frameBufferCache.size());
+    return m_frameBufferCache[index].getStatus() == ImageFrame::FrameComplete;
+  }
+
   WebPIDecoder* m_decoder;
   WebPDecBuffer m_decoderBuffer;
   int m_formatFlags;
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
index 6793c6fc..22b8da2 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.cpp
@@ -50,11 +50,27 @@
 
 MediaStreamComponent::MediaStreamComponent(const String& id,
                                            MediaStreamSource* source)
-    : m_source(source), m_id(id), m_enabled(true), m_muted(false) {
+    : MediaStreamComponent(id, source, true, false) {}
+
+MediaStreamComponent::MediaStreamComponent(const String& id,
+                                           MediaStreamSource* source,
+                                           bool enabled,
+                                           bool muted)
+    : m_source(source), m_id(id), m_enabled(enabled), m_muted(muted) {
   DCHECK(m_id.length());
   ThreadState::current()->registerPreFinalizer(this);
 }
 
+MediaStreamComponent* MediaStreamComponent::clone() const {
+  MediaStreamComponent* clonedComponent = new MediaStreamComponent(
+      createCanonicalUUIDString(), source(), m_enabled, m_muted);
+  // TODO(pbos): Clone |m_trackData| as well.
+  // TODO(pbos): Move properties from MediaStreamTrack here so that they are
+  // also cloned. Part of crbug:669212 since stopped is currently not carried
+  // over, nor is ended().
+  return clonedComponent;
+}
+
 void MediaStreamComponent::dispose() {
   m_trackData.reset();
 }
diff --git a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
index 8aa26e9..635bc82 100644
--- a/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
+++ b/third_party/WebKit/Source/platform/mediastream/MediaStreamComponent.h
@@ -66,6 +66,8 @@
   static MediaStreamComponent* create(MediaStreamSource*);
   static MediaStreamComponent* create(const String& id, MediaStreamSource*);
 
+  MediaStreamComponent* clone() const;
+
   // |m_trackData| may hold pointers to GC objects indirectly, and it may touch
   // eagerly finalized objects in destruction.
   // So this class runs pre-finalizer to finalize |m_trackData| promptly.
@@ -93,6 +95,10 @@
 
  private:
   MediaStreamComponent(const String& id, MediaStreamSource*);
+  MediaStreamComponent(const String& id,
+                       MediaStreamSource*,
+                       bool enabled,
+                       bool muted);
 
   // AudioSourceProviderImpl wraps a WebAudioSourceProvider::provideInput()
   // calls into chromium to get a rendered audio stream.
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index 3c39350..305cfbe 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -62,6 +62,14 @@
     VariadicDynCastAllOfMatcher<clang::Expr, clang::UnresolvedMemberExpr>
         unresolvedMemberExpr;
 
+const clang::ast_matchers::internal::
+    VariadicDynCastAllOfMatcher<clang::Expr, clang::DependentScopeDeclRefExpr>
+        dependentScopeDeclRefExpr;
+
+const clang::ast_matchers::internal::
+    VariadicDynCastAllOfMatcher<clang::Expr, clang::CXXDependentScopeMemberExpr>
+        cxxDependentScopeMemberExpr;
+
 AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) {
   return Node.isOverloadedOperator();
 }
@@ -165,6 +173,34 @@
   return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder);
 }
 
+// Matches |T::m| and/or |x->T::m| and/or |x->m| CXXDependentScopeMemberExpr
+// if member |m| comes from a type that matches the InnerMatcher.
+AST_MATCHER_P(clang::CXXDependentScopeMemberExpr,
+              hasMemberFromType,
+              clang::ast_matchers::internal::Matcher<clang::QualType>,
+              InnerMatcher) {
+  // Given |T::m| and/or |x->T::m| and/or |x->m| ...
+  if (clang::NestedNameSpecifier* nestedNameSpecifier = Node.getQualifier()) {
+    // ... if |T| is present, then InnerMatcher has to match |T|.
+    clang::QualType qualType(nestedNameSpecifier->getAsType(), 0);
+    return InnerMatcher.matches(qualType, Finder, Builder);
+  } else {
+    // ... if there is no |T|, then InnerMatcher has to match the type of |x|.
+    clang::Expr* base_expr = Node.isImplicitAccess() ? nullptr : Node.getBase();
+    return base_expr &&
+           InnerMatcher.matches(base_expr->getType(), Finder, Builder);
+  }
+}
+
+// Matches |const Class<T>&| QualType if InnerMatcher matches |Class<T>|.
+AST_MATCHER_P(clang::QualType,
+              hasBaseType,
+              clang::ast_matchers::internal::Matcher<clang::Type>,
+              InnerMatcher) {
+  const clang::Type* type = Node.getTypePtrOrNull();
+  return type && InnerMatcher.matches(*type, Finder, Builder);
+}
+
 bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl,
                         const char* class_name) {
   if (decl.getParent()->getQualifiedNameAsString() == class_name)
@@ -531,6 +567,24 @@
 };
 
 template <>
+struct TargetNodeTraits<clang::DependentScopeDeclRefExpr> {
+  static clang::SourceLocation GetLoc(
+      const clang::DependentScopeDeclRefExpr& expr) {
+    return expr.getLocation();
+  }
+  static const char* GetName() { return "expr"; }
+};
+
+template <>
+struct TargetNodeTraits<clang::CXXDependentScopeMemberExpr> {
+  static clang::SourceLocation GetLoc(
+      const clang::CXXDependentScopeMemberExpr& expr) {
+    return expr.getMemberLoc();
+  }
+  static const char* GetName() { return "expr"; }
+};
+
+template <>
 struct TargetNodeTraits<clang::CXXCtorInitializer> {
   static clang::SourceLocation GetLoc(const clang::CXXCtorInitializer& init) {
     assert(init.isWritten());
@@ -677,10 +731,45 @@
 }
 
 clang::DeclarationName GetUnresolvedName(
+    const clang::DependentScopeDeclRefExpr& expr) {
+  return expr.getDeclName();
+}
+
+clang::DeclarationName GetUnresolvedName(
+    const clang::CXXDependentScopeMemberExpr& expr) {
+  return expr.getMember();
+}
+
+clang::DeclarationName GetUnresolvedName(
     const clang::UnresolvedUsingValueDecl& decl) {
   return decl.getDeclName();
 }
 
+// Returns whether |expr_node| is used as a callee in the AST (i.e. if
+// |expr_node| needs to resolve to a method or a function).
+bool IsCallee(const clang::Expr& expr, clang::ASTContext& context) {
+  auto matcher = stmt(hasParent(callExpr(callee(equalsNode(&expr)))));
+  return IsMatching(matcher, expr, context);
+}
+
+// Returns whether |decl| will be used as a callee in the AST (i.e. if the value
+// brought by the using declaration will resolve to a method or a function).
+bool IsCallee(const clang::UnresolvedUsingValueDecl& decl,
+              clang::ASTContext& /* context */) {
+  // Caller (i.e. GuessNameForUnresolvedDependentNode) should have already
+  // filtered out fields before calling |IsCallee|.
+  clang::IdentifierInfo* info = GetUnresolvedName(decl).getAsIdentifierInfo();
+  assert(info);
+  bool name_looks_like_a_field = info->getName().startswith(kBlinkFieldPrefix);
+  assert(!name_looks_like_a_field);
+
+  // Looking just at clang::UnresolvedUsingValueDecl, we cannot tell whether it
+  // refers to something callable or not.  Since fields should have been already
+  // filtered out before calling IsCallee (see the assert above), let's assume
+  // that |using Base::foo| refers to a method.
+  return true;
+}
+
 template <typename TargetNode>
 class UnresolvedRewriterBase : public RewriterBase<TargetNode> {
  public:
@@ -690,13 +779,33 @@
       : RewriterBase<TargetNode>(replacements) {}
 
   void run(const MatchFinder::MatchResult& result) override {
-    const TargetNode& expr = Base::GetTargetNode(result);
-    llvm::StringRef old_name = GetUnresolvedName(expr).getAsString();
-    std::string new_name;
-    if (GuessNameForUnresolvedDependentNode(expr, *result.Context, old_name,
-                                            new_name)) {
-      Base::AddReplacement(result, old_name, std::move(new_name));
+    const TargetNode& node = Base::GetTargetNode(result);
+
+    clang::DeclarationName decl_name = GetUnresolvedName(node);
+    switch (decl_name.getNameKind()) {
+      // Do not rewrite this:
+      //   return operator T*();
+      // into this:
+      //   return Operator type - parameter - 0 - 0 * T * ();
+      case clang::DeclarationName::NameKind::CXXConversionFunctionName:
+      case clang::DeclarationName::NameKind::CXXOperatorName:
+      case clang::DeclarationName::NameKind::CXXLiteralOperatorName:
+        return;
+      default:
+        break;
     }
+
+    // Make sure there is an old name + extract the old name.
+    clang::IdentifierInfo* info = GetUnresolvedName(node).getAsIdentifierInfo();
+    if (!info)
+      return;
+    llvm::StringRef old_name = info->getName();
+
+    // Try to guess a new name.
+    std::string new_name;
+    if (GuessNameForUnresolvedDependentNode(node, *result.Context, old_name,
+                                            new_name))
+      Base::AddReplacement(result, old_name, std::move(new_name));
   }
 
  private:
@@ -706,13 +815,16 @@
   // a specific decl until template instantiation - at the point of rename, one
   // cannot tell whether the node will eventually resolve to a field / method /
   // constant / etc.
+  //
+  // The method returns false if no renaming should be done.
+  // Otherwise the method returns true and sets |new_name|.
   bool GuessNameForUnresolvedDependentNode(const TargetNode& node,
                                            clang::ASTContext& context,
                                            llvm::StringRef old_name,
                                            std::string& new_name) {
     // |m_fieldName| -> |field_name_|.
     if (old_name.startswith(kBlinkFieldPrefix)) {
-      std::string field_name = old_name.str().substr(strlen(kBlinkFieldPrefix));
+      std::string field_name = old_name.substr(strlen(kBlinkFieldPrefix));
       if (field_name.find('_') == std::string::npos) {
         new_name = CamelCaseToUnderscoreCase(field_name) + "_";
         return true;
@@ -720,10 +832,10 @@
     }
 
     // |T::myMethod(...)| -> |T::MyMethod(...)|.
-    if ((old_name.find('_') == std::string::npos) &&
+    if ((old_name.find('_') == std::string::npos) && IsCallee(node, context) &&
         !IsBlacklistedFunctionOrMethodName(old_name)) {
       new_name = old_name;
-      new_name[0] = clang::toUppercase(new_name[0]);
+      new_name[0] = clang::toUppercase(old_name[0]);
       return true;
     }
 
@@ -742,6 +854,12 @@
 using UnresolvedUsingValueDeclRewriter =
     UnresolvedRewriterBase<clang::UnresolvedUsingValueDecl>;
 
+using DependentScopeDeclRefExprRewriter =
+    UnresolvedRewriterBase<clang::DependentScopeDeclRefExpr>;
+
+using CXXDependentScopeMemberExprRewriter =
+    UnresolvedRewriterBase<clang::CXXDependentScopeMemberExpr>;
+
 }  // namespace
 
 static llvm::cl::extrahelp common_help(CommonOptionsParser::HelpMessage);
@@ -1068,6 +1186,62 @@
   UsingDeclRewriter using_decl_rewriter(&replacements);
   match_finder.addMatcher(using_decl_matcher, &using_decl_rewriter);
 
+  // Matches any QualType that refers to a blink type:
+  // - const blink::Foo&
+  // - blink::Foo*
+  // - blink::Foo<T>
+  // - ...
+  // TODO(lukasza): The matchers below can be simplified after
+  // https://llvm.org/bugs/show_bug.cgi?id=30331 is fixed.
+  // Simplified matchers:
+  //    auto blink_qual_type_base_matcher =
+  //        qualType(hasDeclaration(in_blink_namespace));
+  //    auto blink_qual_type_matcher = qualType(anyOf(
+  //        blink_qual_type_base_matcher,
+  //        pointsTo(blink_qual_type_base_matcher),
+  //        references(blink_qual_type_base_matcher)));
+  auto blink_qual_type_bug_workaround_matcher1 = hasBaseType(
+      anyOf(enumType(hasDeclaration(in_blink_namespace)),
+            recordType(hasDeclaration(in_blink_namespace)),
+            templateSpecializationType(hasDeclaration(in_blink_namespace)),
+            templateTypeParmType(hasDeclaration(in_blink_namespace)),
+            typedefType(hasDeclaration(in_blink_namespace))));
+  auto blink_qual_type_base_matcher =
+      qualType(anyOf(blink_qual_type_bug_workaround_matcher1,
+                     hasBaseType(elaboratedType(
+                         namesType(blink_qual_type_bug_workaround_matcher1)))));
+  auto blink_qual_type_matcher =
+      qualType(anyOf(blink_qual_type_base_matcher, pointsTo(in_blink_namespace),
+                     references(in_blink_namespace)));
+
+  // Template-dependent decl lookup ========
+  // Given
+  //   template <typename T> void f() { T::foo(); }
+  // matches |T::foo|.
+  auto dependent_scope_decl_ref_expr_matcher =
+      expr(id("expr", dependentScopeDeclRefExpr(has(nestedNameSpecifier(
+                          specifiesType(blink_qual_type_matcher))))));
+  DependentScopeDeclRefExprRewriter dependent_scope_decl_ref_expr_rewriter(
+      &replacements);
+  match_finder.addMatcher(dependent_scope_decl_ref_expr_matcher,
+                          &dependent_scope_decl_ref_expr_rewriter);
+
+  // Template-dependent member lookup ========
+  // Given
+  //   template <typename T>
+  //   class Foo {
+  //     void f() { T::foo(); }
+  //     void g(T x) { x.bar(); }
+  //   };
+  // matches |T::foo| and |x.bar|.
+  auto cxx_dependent_scope_member_expr_matcher =
+      expr(id("expr", cxxDependentScopeMemberExpr(
+                          hasMemberFromType(blink_qual_type_matcher))));
+  CXXDependentScopeMemberExprRewriter cxx_dependent_scope_member_expr_rewriter(
+      &replacements);
+  match_finder.addMatcher(cxx_dependent_scope_member_expr_matcher,
+                          &cxx_dependent_scope_member_expr_rewriter);
+
   std::unique_ptr<clang::tooling::FrontendActionFactory> factory =
       clang::tooling::newFrontendActionFactory(&match_finder);
   int result = tool.run(factory.get());
diff --git a/tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc
index faef4ec..e0f87b1 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/fields-expected.cc
@@ -145,6 +145,14 @@
       !kIsGarbageCollected ? kRefCountedLifetime : kGarbageCollectedLifetime;
 };
 
+template <typename T>
+struct GenericHashTraitsBase {
+  // We don't want to capitalize fields in type traits
+  // (i.e. the |value| -> |kValue| rename is undesirable below).
+  // This problem is prevented by IsCallee heuristic.
+  static const int kWeakHandlingFlag = TypeTrait2<T>::value ? 123 : 456;
+};
+
 };  // namespace WTF
 
 void F() {
diff --git a/tools/clang/rewrite_to_chrome_style/tests/fields-original.cc b/tools/clang/rewrite_to_chrome_style/tests/fields-original.cc
index 726c521..d93d986 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/fields-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/fields-original.cc
@@ -142,6 +142,14 @@
       !isGarbageCollected ? RefCountedLifetime : GarbageCollectedLifetime;
 };
 
+template <typename T>
+struct GenericHashTraitsBase {
+  // We don't want to capitalize fields in type traits
+  // (i.e. the |value| -> |kValue| rename is undesirable below).
+  // This problem is prevented by IsCallee heuristic.
+  static const int kWeakHandlingFlag = TypeTrait2<T>::value ? 123 : 456;
+};
+
 };  // namespace WTF
 
 void F() {
diff --git a/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
index 69a33495..8d064a1 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
@@ -21,14 +21,11 @@
  public:
   template <typename U, typename V>
   Checked(const Checked<U, V>& rhs) {
-    // This (incorrectly) doesn't get rewritten, since it's not instantiated. In
-    // this case, the AST representation contains a bunch of
-    // CXXDependentScopeMemberExpr nodes.
-    if (rhs.hasOverflowed())
-      this->overflowed();
-    if (!IsInBounds<T>(rhs.m_value))
-      this->overflowed();
-    value_ = static_cast<T>(rhs.m_value);
+    if (rhs.HasOverflowed())
+      this->Overflowed();
+    if (!IsInBounds<T>(rhs.value_))
+      this->Overflowed();
+    value_ = static_cast<T>(rhs.value_);
   }
 
   bool HasOverflowed() const { return false; }
@@ -40,11 +37,28 @@
 
 template <typename To, typename From>
 To Bitwise_cast(From from) {
-  static_assert(sizeof(To) == sizeof(From));
+  static_assert(sizeof(To) == sizeof(From), "msg");
   return reinterpret_cast<To>(from);
 }
 
 }  // namespace WTF
 
+namespace mojo {
+
+template <typename U>
+struct ArrayTraits;
+
+template <typename U>
+struct ArrayTraits<WTF::Checked<U, int>> {
+  static bool HasOverflowed(WTF::Checked<U, int>& input) {
+    // |hasOverflowed| below should be rewritten to |HasOverflowed|
+    // (because this is a method of WTF::Checked;  it doesn't matter
+    // that we are not in WTF namespace *here*).
+    return input.HasOverflowed();
+  }
+};
+
+}  // namespace mojo
+
 using WTF::Bitwise_cast;
 using WTF::SafeCast;
diff --git a/tools/clang/rewrite_to_chrome_style/tests/function-templates-original.cc b/tools/clang/rewrite_to_chrome_style/tests/function-templates-original.cc
index 71267b0..80e244b 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/function-templates-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/function-templates-original.cc
@@ -21,9 +21,6 @@
  public:
   template<typename U, typename V>
   Checked(const Checked<U, V>& rhs){
-    // This (incorrectly) doesn't get rewritten, since it's not instantiated. In
-    // this case, the AST representation contains a bunch of
-    // CXXDependentScopeMemberExpr nodes.
     if (rhs.hasOverflowed())
       this->overflowed();
     if (!isInBounds<T>(rhs.m_value))
@@ -40,11 +37,28 @@
 
 template<typename To, typename From>
 To bitwise_cast(From from) {
-  static_assert(sizeof(To) == sizeof(From));
+  static_assert(sizeof(To) == sizeof(From), "msg");
   return reinterpret_cast<To>(from);
 }
 
 }  // namespace WTF
 
+namespace mojo {
+
+template <typename U>
+struct ArrayTraits;
+
+template <typename U>
+struct ArrayTraits<WTF::Checked<U, int>> {
+  static bool HasOverflowed(WTF::Checked<U, int>& input) {
+    // |hasOverflowed| below should be rewritten to |HasOverflowed|
+    // (because this is a method of WTF::Checked;  it doesn't matter
+    // that we are not in WTF namespace *here*).
+    return input.hasOverflowed();
+  }
+};
+
+}  // namespace mojo
+
 using WTF::bitwise_cast;
 using WTF::safeCast;
diff --git a/tools/clang/rewrite_to_chrome_style/tests/template-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/template-expected.cc
index a7f42051..18e4512 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/template-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/template-expected.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <type_traits>
+
 namespace not_blink {
 
 void function(int x) {}
@@ -9,6 +11,7 @@
 class Class {
  public:
   void method() {}
+  virtual void virtualMethod() {}
   template <typename T>
   void methodTemplate(T) {}
   template <typename T>
@@ -18,6 +21,17 @@
 template <typename T>
 void functionTemplate(T x) {}
 
+template <typename T = Class>
+void functionTemplate2() {
+  T::staticMethodTemplate(123);
+}
+
+template <typename T = Class>
+class TemplatedClass {
+ public:
+  void anotherMethod() { T::staticMethodTemplate(123); }
+};
+
 }  // not_blink
 
 namespace blink {
@@ -180,4 +194,90 @@
 
 }  // namespace test_unnamed_arg
 
+namespace cxx_dependent_scope_member_expr_testing {
+
+class PartitionAllocator {
+ public:
+  static void Method() {}
+};
+
+template <typename Allocator = PartitionAllocator>
+class Vector {
+ public:
+  // https://crbug.com/582315: |Allocator::method| is a
+  // CXXDependentScopeMemberExpr.
+  void AnotherMethod() {
+    if (std::is_class<Allocator>::value)  // Shouldn't rename |value|
+      Allocator::Method();                // Should rename |method| -> |Method|.
+  }
+};
+
+template <typename Allocator = PartitionAllocator>
+void Test() {
+  // https://crbug.com/582315: |Allocator::method| is a
+  // DependentScopeDeclRefExpr.
+  if (std::is_class<Allocator>::value)  // Shouldn't rename |value|.
+    Allocator::Method();                // Should rename |method|.
+}
+
+class InterceptingCanvasBase : public ::not_blink::Class {
+ public:
+  virtual void VirtualMethodInBlink(){};
+};
+
+template <typename DerivedCanvas>
+class InterceptingCanvas : public InterceptingCanvasBase {
+ public:
+  void virtualMethod() override {
+    this->Class::virtualMethod();  // https://crbug.com/582315#c19
+    this->InterceptingCanvasBase::VirtualMethodInBlink();
+  }
+};
+
+template <typename T>
+class ThreadSpecific {
+ public:
+  T* operator->();
+  operator T*();
+};
+
+template <typename T>
+inline ThreadSpecific<T>::operator T*() {
+  return nullptr;
+}
+
+template <typename T>
+inline T* ThreadSpecific<T>::operator->() {
+  return operator T*();
+}
+
+class Class {
+ public:
+  virtual void VirtualMethodInBlink() {}
+};
+
+}  // namespace cxx_dependent_scope_member_expr_testing
+
 }  // namespace blink
+
+namespace not_blink {
+
+namespace cxx_dependent_scope_member_expr_testing {
+
+class Base : public ::blink::cxx_dependent_scope_member_expr_testing::Class {
+ public:
+  virtual void virtualMethod() {}
+};
+
+template <typename T>
+class Derived : public Base {
+ public:
+  void virtualMethod() override {
+    this->Class::VirtualMethodInBlink();
+    this->Base::virtualMethod();
+  }
+};
+
+}  // namespace cxx_dependent_scope_member_expr_testing
+
+}  // namespace not_blink
diff --git a/tools/clang/rewrite_to_chrome_style/tests/template-original.cc b/tools/clang/rewrite_to_chrome_style/tests/template-original.cc
index cf22188..e8b9345 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/template-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/template-original.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <type_traits>
+
 namespace not_blink {
 
 void function(int x) {}
@@ -9,6 +11,7 @@
 class Class {
  public:
   void method() {}
+  virtual void virtualMethod() {}
   template <typename T>
   void methodTemplate(T) {}
   template <typename T>
@@ -18,6 +21,17 @@
 template <typename T>
 void functionTemplate(T x) {}
 
+template <typename T = Class>
+void functionTemplate2() {
+  T::staticMethodTemplate(123);
+}
+
+template <typename T = Class>
+class TemplatedClass {
+ public:
+  void anotherMethod() { T::staticMethodTemplate(123); }
+};
+
 }  // not_blink
 
 namespace blink {
@@ -180,4 +194,90 @@
 
 }  // namespace test_unnamed_arg
 
+namespace cxx_dependent_scope_member_expr_testing {
+
+class PartitionAllocator {
+ public:
+  static void method() {}
+};
+
+template <typename Allocator = PartitionAllocator>
+class Vector {
+ public:
+  // https://crbug.com/582315: |Allocator::method| is a
+  // CXXDependentScopeMemberExpr.
+  void anotherMethod() {
+    if (std::is_class<Allocator>::value)  // Shouldn't rename |value|
+      Allocator::method();                // Should rename |method| -> |Method|.
+  }
+};
+
+template <typename Allocator = PartitionAllocator>
+void test() {
+  // https://crbug.com/582315: |Allocator::method| is a
+  // DependentScopeDeclRefExpr.
+  if (std::is_class<Allocator>::value)  // Shouldn't rename |value|.
+    Allocator::method();                // Should rename |method|.
+}
+
+class InterceptingCanvasBase : public ::not_blink::Class {
+ public:
+  virtual void virtualMethodInBlink(){};
+};
+
+template <typename DerivedCanvas>
+class InterceptingCanvas : public InterceptingCanvasBase {
+ public:
+  void virtualMethod() override {
+    this->Class::virtualMethod();  // https://crbug.com/582315#c19
+    this->InterceptingCanvasBase::virtualMethodInBlink();
+  }
+};
+
+template <typename T>
+class ThreadSpecific {
+ public:
+  T* operator->();
+  operator T*();
+};
+
+template <typename T>
+inline ThreadSpecific<T>::operator T*() {
+  return nullptr;
+}
+
+template <typename T>
+inline T* ThreadSpecific<T>::operator->() {
+  return operator T*();
+}
+
+class Class {
+ public:
+  virtual void virtualMethodInBlink() {}
+};
+
+}  // namespace cxx_dependent_scope_member_expr_testing
+
 }  // namespace blink
+
+namespace not_blink {
+
+namespace cxx_dependent_scope_member_expr_testing {
+
+class Base : public ::blink::cxx_dependent_scope_member_expr_testing::Class {
+ public:
+  virtual void virtualMethod() {}
+};
+
+template <typename T>
+class Derived : public Base {
+ public:
+  void virtualMethod() override {
+    this->Class::virtualMethodInBlink();
+    this->Base::virtualMethod();
+  }
+};
+
+}  // namespace cxx_dependent_scope_member_expr_testing
+
+}  // namespace not_blink
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 079207c..41da607 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -39352,17 +39352,11 @@
 </histogram>
 
 <histogram name="Notifications.Icon.FileSize" units="bytes">
-  <obsolete>
-    Deprecated Nov 2016 in favor of Notifications.LoadFileSize.*
-  </obsolete>
   <owner>peter@chromium.org</owner>
   <summary>The number of bytes loaded for a Web Notification icon.</summary>
 </histogram>
 
 <histogram name="Notifications.Icon.LoadFailTime" units="ms">
-  <obsolete>
-    Deprecated Nov 2016 in favor of Notifications.LoadFailTime.*
-  </obsolete>
   <owner>peter@chromium.org</owner>
   <summary>
     The number of milliseconds it took to fail loading an icon for a Web
@@ -39371,9 +39365,6 @@
 </histogram>
 
 <histogram name="Notifications.Icon.LoadFinishTime" units="ms">
-  <obsolete>
-    Deprecated Nov 2016 in favor of Notifications.LoadFinishTime.*
-  </obsolete>
   <owner>peter@chromium.org</owner>
   <summary>
     The number of milliseconds it took to finish successfully loading an icon
@@ -39382,9 +39373,6 @@
 </histogram>
 
 <histogram name="Notifications.Icon.ScaleDownTime" units="ms">
-  <obsolete>
-    Deprecated Nov 2016 in favor of Notifications.LoadScaleDownTime.*
-  </obsolete>
   <owner>peter@chromium.org</owner>
   <summary>
     The number of milliseconds it took to scale down an icon for a Web
@@ -39392,45 +39380,6 @@
   </summary>
 </histogram>
 
-<histogram name="Notifications.LoadFailTime" units="ms">
-<!-- Name completed by histogram_suffixes name="NotificationImageTypes" -->
-
-  <owner>johnme@chromium.org</owner>
-  <summary>
-    The number of milliseconds it took to fail loading an icon/image for a Web
-    Notification.
-  </summary>
-</histogram>
-
-<histogram name="Notifications.LoadFileSize" units="bytes">
-<!-- Name completed by histogram_suffixes name="NotificationImageTypes" -->
-
-  <owner>johnme@chromium.org</owner>
-  <summary>
-    The number of bytes loaded for a Web Notification icon/image.
-  </summary>
-</histogram>
-
-<histogram name="Notifications.LoadFinishTime" units="ms">
-<!-- Name completed by histogram_suffixes name="NotificationImageTypes" -->
-
-  <owner>johnme@chromium.org</owner>
-  <summary>
-    The number of milliseconds it took to finish successfully loading an
-    icon/image for a Web Notification.
-  </summary>
-</histogram>
-
-<histogram name="Notifications.LoadScaleDownTime" units="ms">
-<!-- Name completed by histogram_suffixes name="NotificationImageTypes" -->
-
-  <owner>johnme@chromium.org</owner>
-  <summary>
-    The number of milliseconds it took to scale down an icon/image for a Web
-    Notification.
-  </summary>
-</histogram>
-
 <histogram name="Notifications.PerNotificationActions"
     enum="NotificationActionType">
   <owner>dewittj@chromium.org</owner>
@@ -84511,6 +84460,8 @@
   <int value="1149" label="SYSTEM_DISPLAY_TOUCHCALIBRATIONSTART"/>
   <int value="1150" label="SYSTEM_DISPLAY_TOUCHCALIBRATIONSET"/>
   <int value="1151" label="SYSTEM_DISPLAY_TOUCHCALIBRATIONRESET"/>
+  <int value="1152" label="CERTIFICATEPROVIDER_REQUESTPIN"/>
+  <int value="1153" label="CERTIFICATEPROVIDER_STOPPINREQUEST"/>
 </enum>
 
 <enum name="ExtensionIconState" type="int">
@@ -110806,17 +110757,6 @@
   <affected-histogram name="Notifications.Display"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="NotificationImageTypes" separator=".">
-  <suffix name="ActionIcon"/>
-  <suffix name="Badge"/>
-  <suffix name="Icon"/>
-  <suffix name="Image"/>
-  <affected-histogram name="Notifications.LoadFailTime"/>
-  <affected-histogram name="Notifications.LoadFileSize"/>
-  <affected-histogram name="Notifications.LoadFinishTime"/>
-  <affected-histogram name="Notifications.LoadScaleDownTime"/>
-</histogram_suffixes>
-
 <histogram_suffixes name="NQE.Accuracy.Metric.Accuracy.DiffPositiveOrNegative"
     separator=".">
   <suffix name="Negative"
diff --git a/ui/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index 38d7ae84..ec928419f 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -55,9 +55,10 @@
                    Mode mode)
     : resource_file_(resource_file),
       resource_file_200_(resource_file_200),
-      env_(aura::Env::CreateInstance(mode == Mode::AURA_MUS
-                                         ? aura::Env::Mode::MUS
-                                         : aura::Env::Mode::LOCAL)),
+      env_(aura::Env::CreateInstance(
+          (mode == Mode::AURA_MUS || mode == Mode::AURA_MUS_WINDOW_MANAGER)
+              ? aura::Env::Mode::MUS
+              : aura::Env::Mode::LOCAL)),
       views_delegate_(new MusViewsDelegate) {
   if (mode == Mode::AURA_MUS) {
     mus_client_ =
diff --git a/ui/views/mus/aura_init.h b/ui/views/mus/aura_init.h
index c028a7e..3558d73 100644
--- a/ui/views/mus/aura_init.h
+++ b/ui/views/mus/aura_init.h
@@ -43,8 +43,12 @@
     // Indicates AuraInit should target using aura with mus.
     AURA_MUS,
 
+    // Indicates AuraInit should target using aura with mus, for a Window
+    // Manager client.
+    AURA_MUS_WINDOW_MANAGER,
+
     // Indicates AuraInit should target using ui::Window.
-    UI,
+    UI
   };
 
   // |resource_file| is the file to load strings and 1x icons from.