diff --git a/AUTHORS b/AUTHORS
index 91d38d9..196012ab 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -502,6 +502,7 @@
 Vipul Bhasin <vipul.bhasin@gmail.com>
 Visa Putkinen <v.putkinen@partner.samsung.com>
 Vivek Galatage <vivek.vg@samsung.com>
+Wesley Lancel <wesleylancel@gmail.com>
 Will Hirsch <chromium@willhirsch.co.uk>
 William Xie <william.xie@intel.com>
 Xiang Long <xiang.long@intel.com>
diff --git a/DEPS b/DEPS
index decc1898..50c91ac 100644
--- a/DEPS
+++ b/DEPS
@@ -34,7 +34,7 @@
   'llvm_url': 'http://src.chromium.org/llvm-project',
   'llvm_git': 'https://llvm.googlesource.com',
   'webkit_trunk': 'http://src.chromium.org/blink/trunk',
-  'webkit_revision': 'ed228f8d2b2ef02da74b9fde69990da74643683c', # from svn revision 191074
+  'webkit_revision': '3094822896bcb215514b9144184acbd04b6a40a9', # from svn revision 191160
   'chromium_git': 'https://chromium.googlesource.com',
   'chromiumos_git': 'https://chromium.googlesource.com/chromiumos',
   'pdfium_git': 'https://pdfium.googlesource.com',
@@ -42,12 +42,12 @@
   'boringssl_git': 'https://boringssl.googlesource.com',
   'libvpx_revision': '080710f043a2f85e100d508a53749cd321e4b57b',
   'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
-  'skia_revision': 'b675a73c1f3f4a433c4893199a0bd11126dfe130',
+  'skia_revision': '7ab42771859145884e1b28c8c45f0a5a728b22ac',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
   'v8_branch': 'trunk',
-  'v8_revision': '369eb13a86b0529acd80b3b73b6c2a796224f3a7',
+  'v8_revision': '3e7dee100ac4e951719ce264f79a214f6634cf11',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
@@ -207,7 +207,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'f5698b4f3e3e8eacad18d77cf69882fe14015de5',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'fbd8fd2847eb747d88dac20b1d5d723bd41f8b08',
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'bbfd3991a4a9b270c352ccba09b5d60b3222ef10',
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '13718c7b9fd376fde092cbd3c5347d15059ac652', # from svn revision 9167
@@ -231,7 +231,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' + '@' + '093c83b9ef8dab80548107376ed82fbe44e277a7',
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '1e5b7f78e95daa0e0cb8a6ddfee20011208154b6',
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py
index ad391d3c..8b642c4 100755
--- a/PRESUBMIT_test.py
+++ b/PRESUBMIT_test.py
@@ -775,5 +775,39 @@
             bot, master, PRESUBMIT.GetTryServerMasterForBot(bot)))
 
 
+class UserMetricsActionTest(unittest.TestCase):
+  def testUserMetricsActionInActions(self):
+    input_api = MockInputApi()
+    file_with_user_action = 'file_with_user_action.cc'
+    contents_with_user_action = [
+      'base::UserMetricsAction("AboutChrome")'
+    ]
+
+    input_api.files = [MockFile(file_with_user_action,
+                                contents_with_user_action)]
+
+    self.assertEqual(
+      [], PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi()))
+
+
+  def testUserMetricsActionNotAddedToActions(self):
+    input_api = MockInputApi()
+    file_with_user_action = 'file_with_user_action.cc'
+    contents_with_user_action = [
+      'base::UserMetricsAction("NotInActionsXml")'
+    ]
+
+    input_api.files = [MockFile(file_with_user_action,
+                                contents_with_user_action)]
+
+    output = PRESUBMIT._CheckUserActionUpdate(input_api, MockOutputApi())
+    self.assertEqual(
+      ('File %s line %d: %s is missing in '
+       'tools/metrics/actions/actions.xml. Please run '
+       'tools/metrics/actions/extract_actions.py to update.'
+       % (file_with_user_action, 1, 'NotInActionsXml')),
+      output[0].message)
+
+
 if __name__ == '__main__':
   unittest.main()
diff --git a/PRESUBMIT_test_mocks.py b/PRESUBMIT_test_mocks.py
index 03d9232..8e15d8c 100644
--- a/PRESUBMIT_test_mocks.py
+++ b/PRESUBMIT_test_mocks.py
@@ -32,6 +32,9 @@
   def AffectedSourceFiles(self, file_filter=None):
     return self.files
 
+  def LocalPaths(self):
+    return self.files
+
   def PresubmitLocalPath(self):
     return os.path.dirname(__file__)
 
@@ -62,22 +65,22 @@
       return self.message
 
   class PresubmitError(PresubmitResult):
-    def __init__(self, message, items, long_text=''):
+    def __init__(self, message, items=None, long_text=''):
       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
       self.type = 'error'
 
   class PresubmitPromptWarning(PresubmitResult):
-    def __init__(self, message, items, long_text=''):
+    def __init__(self, message, items=None, long_text=''):
       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
       self.type = 'warning'
 
   class PresubmitNotifyResult(PresubmitResult):
-    def __init__(self, message, items, long_text=''):
+    def __init__(self, message, items=None, long_text=''):
       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
       self.type = 'notify'
 
   class PresubmitPromptOrNotify(PresubmitResult):
-    def __init__(self, message, items, long_text=''):
+    def __init__(self, message, items=None, long_text=''):
       MockOutputApi.PresubmitResult.__init__(self, message, items, long_text)
       self.type = 'promptOrNotify'
 
@@ -103,6 +106,14 @@
   def LocalPath(self):
     return self._local_path
 
+  def rfind(self, p):
+    """os.path.basename is called on MockFile so we need an rfind method."""
+    return self._local_path.rfind(p)
+
+  def __getitem__(self, i):
+    """os.path.basename is called on MockFile so we need a get method."""
+    return self._local_path[i]
+
 
 class MockAffectedFile(MockFile):
   def AbsoluteLocalPath(self):
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
index 1826e78..3f0d514d 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/ContentSettingsAdapter.java
@@ -584,6 +584,14 @@
         return mAwSettings.getMixedContentMode();
     }
 
+    public void setOffscreenPreRaster(boolean enabled) {
+        mAwSettings.setOffscreenPreRaster(enabled);
+    }
+
+    public boolean getOffscreenPreRaster() {
+        return mAwSettings.getOffscreenPreRaster();
+    }
+
     @Override
     public void setVideoOverlayForEmbeddedEncryptedVideoEnabled(boolean flag) {
         mAwSettings.setVideoOverlayForEmbeddedVideoEnabled(flag);
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
index ef65bfe..619979c9 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwTestBase.java
@@ -21,7 +21,9 @@
 import org.chromium.content.browser.test.util.CallbackHelper;
 import org.chromium.content.browser.test.util.Criteria;
 import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper;
 import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.net.test.util.TestWebServer;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
@@ -509,4 +511,59 @@
         });
     }
 
+    /**
+     * Loads the main html then triggers the popup window.
+     */
+    public void triggerPopup(final AwContents parentAwContents,
+            TestAwContentsClient parentAwContentsClient, TestWebServer testWebServer,
+            String mainHtml, String popupHtml, String popupPath, String triggerScript)
+            throws Exception {
+        enableJavaScriptOnUiThread(parentAwContents);
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                parentAwContents.getSettings().setSupportMultipleWindows(true);
+                parentAwContents.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
+            }
+        });
+
+        final String parentUrl = testWebServer.setResponse("/popupParent.html", mainHtml, null);
+        testWebServer.setResponse(popupPath, popupHtml, null);
+
+        parentAwContentsClient.getOnCreateWindowHelper().setReturnValue(true);
+        loadUrlSync(parentAwContents, parentAwContentsClient.getOnPageFinishedHelper(), parentUrl);
+
+        TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper =
+                parentAwContentsClient.getOnCreateWindowHelper();
+        int currentCallCount = onCreateWindowHelper.getCallCount();
+        parentAwContents.evaluateJavaScript(triggerScript, null);
+        onCreateWindowHelper.waitForCallback(
+                currentCallCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * Supplies the popup window with AwContents then waits for the popup window to finish loading.
+     */
+    public AwContents connectPendingPopup(final AwContents parentAwContents) throws Exception {
+        TestAwContentsClient popupContentsClient;
+        AwTestContainerView popupContainerView;
+        final AwContents popupContents;
+        popupContentsClient = new TestAwContentsClient();
+        popupContainerView = createAwTestContainerViewOnMainSync(popupContentsClient);
+        popupContents = popupContainerView.getAwContents();
+        enableJavaScriptOnUiThread(popupContents);
+
+        getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                parentAwContents.supplyContentsForPopup(popupContents);
+            }
+        });
+
+        OnPageFinishedHelper onPageFinishedHelper = popupContentsClient.getOnPageFinishedHelper();
+        int callCount = onPageFinishedHelper.getCallCount();
+        onPageFinishedHelper.waitForCallback(callCount, 1, WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+
+        return popupContents;
+    }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
index a81e9070..3044ddc5 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -8,15 +8,11 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import org.chromium.android_webview.AwContents;
-import org.chromium.android_webview.test.util.AwTestTouchUtils;
 import org.chromium.android_webview.test.util.CommonResources;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.net.test.util.TestWebServer;
 
-import java.util.concurrent.Callable;
-import java.util.concurrent.TimeUnit;
-
 /**
  * Tests for pop up window flow.
  */
@@ -25,9 +21,6 @@
     private TestAwContentsClient mParentContentsClient;
     private AwTestContainerView mParentContainerView;
     private AwContents mParentContents;
-    private TestAwContentsClient mPopupContentsClient;
-    private AwTestContainerView mPopupContainerView;
-    private AwContents mPopupContents;
     private TestWebServer mWebServer;
 
     private static final String POPUP_TITLE = "Popup Window";
@@ -49,67 +42,22 @@
         super.tearDown();
     }
 
-    private void triggerPopup() throws Throwable {
-        enableJavaScriptOnUiThread(mParentContents);
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mParentContents.getSettings().setSupportMultipleWindows(true);
-                mParentContents.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
-            }
-        });
-
+    @SmallTest
+    @Feature({"AndroidWebView"})
+    public void testPopupWindow() throws Throwable {
         final String popupPath = "/popup.html";
-
-        final String parentPageHtml = CommonResources.makeHtmlPageFrom("",
-                "<script>"
+        final String parentPageHtml = CommonResources.makeHtmlPageFrom("", "<script>"
                         + "function tryOpenWindow() {"
                         + "  var newWindow = window.open('" + popupPath + "');"
-                        + "}</script>"
-                        + "<a class=\"full_view\" onclick=\"tryOpenWindow();\">Click me!</a>");
+                        + "}</script>");
+
         final String popupPageHtml = CommonResources.makeHtmlPageFrom(
                 "<title>" + POPUP_TITLE + "</title>",
                 "This is a popup window");
 
-        final String parentUrl = mWebServer.setResponse("/popupParent.html", parentPageHtml, null);
-        mWebServer.setResponse(popupPath, popupPageHtml, null);
-
-        mParentContentsClient.getOnCreateWindowHelper().setReturnValue(true);
-        loadUrlSync(mParentContents,
-                    mParentContentsClient.getOnPageFinishedHelper(),
-                    parentUrl);
-
-        TestAwContentsClient.OnCreateWindowHelper onCreateWindowHelper =
-                mParentContentsClient.getOnCreateWindowHelper();
-        int currentCallCount = onCreateWindowHelper.getCallCount();
-        AwTestTouchUtils.simulateTouchCenterOfView(mParentContainerView);
-        onCreateWindowHelper.waitForCallback(currentCallCount, 1, WAIT_TIMEOUT_MS,
-                TimeUnit.MILLISECONDS);
-    }
-
-    private void connectPendingPopup() throws Exception {
-        mPopupContentsClient = new TestAwContentsClient();
-        mPopupContainerView = createAwTestContainerViewOnMainSync(mPopupContentsClient);
-        mPopupContents = mPopupContainerView.getAwContents();
-
-        getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mParentContents.supplyContentsForPopup(mPopupContents);
-            }
-        });
-    }
-
-    @SmallTest
-    @Feature({"AndroidWebView"})
-    public void testPopupWindow() throws Throwable {
-        triggerPopup();
-        connectPendingPopup();
-        poll(new Callable<Boolean>() {
-            @Override
-            public Boolean call() throws Exception {
-                return POPUP_TITLE.equals(getTitleOnUiThread(mPopupContents));
-            }
-        });
+        triggerPopup(mParentContents, mParentContentsClient, mWebServer, parentPageHtml,
+                popupPageHtml, "/popup.html", "tryOpenWindow()");
+        AwContents popupContents = connectPendingPopup(mParentContents);
+        assertEquals(POPUP_TITLE, getTitleOnUiThread(popupContents));
     }
 }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
index 6d86ef3..44db7f1 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
@@ -763,4 +763,90 @@
         mMessageObject.waitForMessage();
         assertEquals(WORKER_MESSAGE, mMessageObject.getData());
     }
+
+    private static final String POPUP_MESSAGE = "from_popup";
+    private static final String POPUP_URL = "/popup.html";
+    private static final String IFRAME_URL = "/iframe.html";
+    private static final String MAIN_PAGE_FOR_POPUP_TEST = "<!DOCTYPE html><html>"
+            + "<head>"
+            + "    <script>"
+            + "        function createPopup() {"
+            + "            var popupWindow = window.open('" + POPUP_URL + "');"
+            + "            onmessage = function(e) {"
+            + "                popupWindow.postMessage(e.data, '*', e.ports);"
+            + "            };"
+            + "        }"
+            + "    </script>"
+            + "</head>"
+            + "</html>";
+
+    // Sends message and ports to the iframe.
+    private static final String POPUP_PAGE_WITH_IFRAME = "<!DOCTYPE html><html>"
+            + "<script>"
+            + "    onmessage = function(e) {"
+            + "        var iframe = document.getElementsByTagName('iframe')[0];"
+            + "        iframe.contentWindow.postMessage('" + POPUP_MESSAGE + "', '*', e.ports);"
+            + "    };"
+            + "</script>"
+            + "<body><iframe src='" + IFRAME_URL + "'></iframe></body>"
+            + "</html>";
+
+    // Test if WebView can post a message from/to a popup window owning a message port.
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-PostMessage"})
+    public void testPostMessageToPopup() throws Throwable {
+        triggerPopup(mAwContents, mContentsClient, mWebServer, MAIN_PAGE_FOR_POPUP_TEST, ECHO_PAGE,
+                POPUP_URL, "createPopup()");
+        connectPendingPopup(mAwContents);
+        final ChannelContainer channelContainer = new ChannelContainer();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                MessagePort[] channel = mAwContents.createMessageChannel();
+                channelContainer.set(channel);
+                channel[0].setWebEventHandler(new MessagePort.WebEventHandler() {
+                    @Override
+                    public void onMessage(String message) {
+                        channelContainer.setMessage(message);
+                    }
+                }, null);
+                mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, mWebServer.getBaseUrl(),
+                        new MessagePort[] {channel[1]});
+                channel[0].postMessage(HELLO, null);
+            }
+        });
+        channelContainer.waitForMessage();
+        assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage());
+    }
+
+    // Test if WebView can post a message from/to an iframe in a popup window.
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-PostMessage"})
+    public void testPostMessageToIframeInsidePopup() throws Throwable {
+        mWebServer.setResponse(IFRAME_URL, ECHO_PAGE, null);
+        triggerPopup(mAwContents, mContentsClient, mWebServer, MAIN_PAGE_FOR_POPUP_TEST,
+                POPUP_PAGE_WITH_IFRAME, POPUP_URL, "createPopup()");
+        connectPendingPopup(mAwContents);
+        final ChannelContainer channelContainer = new ChannelContainer();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                MessagePort[] channel = mAwContents.createMessageChannel();
+                channelContainer.set(channel);
+                channel[0].setWebEventHandler(new MessagePort.WebEventHandler() {
+                    @Override
+                    public void onMessage(String message) {
+                        channelContainer.setMessage(message);
+                    }
+                }, null);
+                mAwContents.postMessageToFrame(null, WEBVIEW_MESSAGE, mWebServer.getBaseUrl(),
+                        new MessagePort[] {channel[1]});
+                channel[0].postMessage(HELLO, null);
+            }
+        });
+        channelContainer.waitForMessage();
+        assertEquals(HELLO + JS_MESSAGE, channelContainer.getMessage());
+    }
 }
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc
index c0427fa..b9210e5e 100644
--- a/android_webview/native/aw_autofill_client.cc
+++ b/android_webview/native/aw_autofill_client.cc
@@ -199,7 +199,7 @@
   NOTIMPLEMENTED();
 }
 
-void AwAutofillClient::OnUnmaskVerificationResult(bool success) {
+void AwAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
   NOTIMPLEMENTED();
 }
 
diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h
index 9881f8d..d8e4651 100644
--- a/android_webview/native/aw_autofill_client.h
+++ b/android_webview/native/aw_autofill_client.h
@@ -65,7 +65,7 @@
   void ShowUnmaskPrompt(
       const autofill::CreditCard& card,
       base::WeakPtr<autofill::CardUnmaskDelegate> delegate) override;
-  void OnUnmaskVerificationResult(bool success) override;
+  void OnUnmaskVerificationResult(GetRealPanResult result) override;
   void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ed4cd13..7db48e06 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -352,48 +352,46 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  executable("ash_shell") {
-    testonly = true
-    sources = [
-      "shell/shell_main.cc",
-    ]
+executable("ash_shell") {
+  testonly = true
+  sources = [
+    "shell/shell_main.cc",
+  ]
 
-    deps = [
-      ":ash_shell_lib",
-      "//components/user_manager",
-    ]
+  deps = [
+    ":ash_shell_lib",
+    "//components/user_manager",
+  ]
 
-    if (is_win) {
-      configs -= [ "//build/config/win:console" ]
-      configs += [ "//build/config/win:windowed" ]
-      deps += [ "//sandbox" ]
-    }
-
-    if (is_chromeos) {
-      deps += [ "//device/bluetooth" ]
-    }
+  if (is_win) {
+    configs -= [ "//build/config/win:console" ]
+    configs += [ "//build/config/win:windowed" ]
+    deps += [ "//sandbox" ]
   }
 
-  test("ash_shell_unittests") {
-    sources = [
-      "shell/window_watcher_unittest.cc",
-      "test/ash_unittests.cc",
-    ]
+  if (is_chromeos) {
+    deps += [ "//device/bluetooth" ]
+  }
+}
 
-    deps = [
-      ":ash_shell_lib",
-      ":test_support",
-      "//base/test:test_support",
-      "//components/user_manager",
-      "//content/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/accessibility",
-    ]
+test("ash_shell_unittests") {
+  sources = [
+    "shell/window_watcher_unittest.cc",
+    "test/ash_unittests.cc",
+  ]
 
-    if (is_chromeos) {
-      deps += [ "//ui/display" ]
-    }
+  deps = [
+    ":ash_shell_lib",
+    ":test_support",
+    "//base/test:test_support",
+    "//components/user_manager",
+    "//content/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/accessibility",
+  ]
+
+  if (is_chromeos) {
+    deps += [ "//ui/display" ]
   }
 }
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc
index a50a1ae..f11743dd 100644
--- a/ash/ash_switches.cc
+++ b/ash/ash_switches.cc
@@ -64,10 +64,6 @@
 // Enables software based mirroring.
 const char kAshEnableSoftwareMirroring[] = "ash-enable-software-mirroring";
 
-// Enables gesture swipe to close windows while in Overview mode.
-const char kAshEnableSwipeToCloseInOverviewMode[] =
-    "ash-enable-swipe-to-close-in-overview-mode";
-
 // Enables touch view testing.
 // TODO(skuhne): Remove TOGGLE_TOUCH_VIEW_TESTING accelerator once this
 // flag is removed.
diff --git a/ash/ash_switches.h b/ash/ash_switches.h
index 2442aff..4edb61e 100644
--- a/ash/ash_switches.h
+++ b/ash/ash_switches.h
@@ -33,7 +33,6 @@
 ASH_EXPORT extern const char kAshEnableMirroredScreen[];
 ASH_EXPORT extern const char kAshEnablePowerButtonQuickLock[];
 ASH_EXPORT extern const char kAshEnableSoftwareMirroring[];
-ASH_EXPORT extern const char kAshEnableSwipeToCloseInOverviewMode[];
 ASH_EXPORT extern const char kAshEnableSystemSounds[];
 ASH_EXPORT extern const char kAshEnableTouchViewTesting[];
 ASH_EXPORT extern const char kAshHideNotificationsForFactory[];
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
index 7a3b6f9..5d5144b 100644
--- a/ash/display/display_controller.cc
+++ b/ash/display/display_controller.cc
@@ -39,6 +39,7 @@
 #include "ui/compositor/compositor_vsync_manager.h"
 #include "ui/gfx/display.h"
 #include "ui/gfx/screen.h"
+#include "ui/wm/core/coordinate_conversion.h"
 #include "ui/wm/public/activation_client.h"
 
 #if defined(OS_CHROMEOS)
@@ -266,6 +267,7 @@
       focus_activation_store_(new FocusActivationStore()),
       cursor_window_controller_(new CursorWindowController()),
       mirror_window_controller_(new MirrorWindowController()),
+      cursor_display_id_for_restore_(gfx::Display::kInvalidDisplayID),
       weak_ptr_factory_(this) {
 #if defined(OS_CHROMEOS)
   if (base::SysInfo::IsRunningOnChromeOS())
@@ -569,18 +571,44 @@
     if (closest_distance_squared < 0 ||
         closest_distance_squared > distance_squared) {
       aura::Window* root_window = GetRootWindowForDisplayId(display.id());
-      aura::client::ScreenPositionClient* client =
-          aura::client::GetScreenPositionClient(root_window);
-      client->ConvertPointFromScreen(root_window, &center);
+      ::wm::ConvertPointFromScreen(root_window, &center);
       root_window->GetHost()->ConvertPointToNativeScreen(&center);
       dst_root_window = root_window;
       target_location_in_native = center;
       closest_distance_squared = distance_squared;
     }
   }
+
+  gfx::Point target_location_in_root = target_location_in_native;
   dst_root_window->GetHost()->ConvertPointFromNativeScreen(
-      &target_location_in_native);
-  dst_root_window->MoveCursorTo(target_location_in_native);
+      &target_location_in_root);
+
+#if defined(USE_OZONE)
+  gfx::Point target_location_in_screen = target_location_in_root;
+  ::wm::ConvertPointToScreen(dst_root_window, &target_location_in_screen);
+  int64 target_display_id =
+      display_manager->FindDisplayContainingPoint(target_location_in_screen)
+          .id();
+
+  // Do not move the cursor if the cursor's location did not change. This avoids
+  // moving (and showing) the cursor on startup.
+  // - |cursor_location_in_screen_coords_for_restore_| is checked to ensure that
+  //   the cursor is moved when the cursor's native position does not change but
+  //   the scale factor or rotation of the display it is on have changed.
+  // - |cursor_display_id_for_restore_| is checked to ensure that the cursor is
+  //   moved when the cursor's native position and screen position do not change
+  //   but the display that it is on has changed. This occurs when swapping the
+  //   primary display.
+  if (target_location_in_native !=
+          cursor_location_in_native_coords_for_restore_ ||
+      target_location_in_screen !=
+          cursor_location_in_screen_coords_for_restore_ ||
+      target_display_id != cursor_display_id_for_restore_) {
+    dst_root_window->MoveCursorTo(target_location_in_root);
+  }
+#else
+  dst_root_window->MoveCursorTo(target_location_in_root);
+#endif
 }
 
 bool DisplayController::UpdateWorkAreaOfDisplayNearestWindow(
@@ -713,14 +741,16 @@
   focus_activation_store_->Store(clear_focus);
   gfx::Screen* screen = Shell::GetScreen();
   gfx::Point point_in_screen = screen->GetCursorScreenPoint();
-  gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen);
-  aura::Window* root_window = GetRootWindowForDisplayId(display.id());
+  cursor_location_in_screen_coords_for_restore_ = point_in_screen;
 
-  aura::client::ScreenPositionClient* client =
-      aura::client::GetScreenPositionClient(root_window);
-  client->ConvertPointFromScreen(root_window, &point_in_screen);
-  root_window->GetHost()->ConvertPointToNativeScreen(&point_in_screen);
-  cursor_location_in_native_coords_for_restore_ = point_in_screen;
+  gfx::Display display = screen->GetDisplayNearestPoint(point_in_screen);
+  cursor_display_id_for_restore_ = display.id();
+
+  gfx::Point point_in_native = point_in_screen;
+  aura::Window* root_window = GetRootWindowForDisplayId(display.id());
+  ::wm::ConvertPointFromScreen(root_window, &point_in_native);
+  root_window->GetHost()->ConvertPointToNativeScreen(&point_in_native);
+  cursor_location_in_native_coords_for_restore_ = point_in_native;
 }
 
 void DisplayController::PostDisplayConfigurationChange() {
diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h
index 73822e85..d9b2d63 100644
--- a/ash/display/display_controller.h
+++ b/ash/display/display_controller.h
@@ -211,10 +211,16 @@
   scoped_ptr<CursorWindowController> cursor_window_controller_;
   scoped_ptr<MirrorWindowController> mirror_window_controller_;
 
-  // Stores the curent cursor location (in native coordinates) used to
-  // restore the cursor location when display configuration
-  // changed.
+  // Stores the current cursor location (in native coordinates and screen
+  // coordinates respectively). The locations are used to restore the cursor
+  // location when the display configuration changes and to determine whether
+  // the mouse should be moved after a display configuration change.
   gfx::Point cursor_location_in_native_coords_for_restore_;
+  gfx::Point cursor_location_in_screen_coords_for_restore_;
+
+  // Stores the cursor's display. The id is used to determine whether the mouse
+  // should be moved after a display configuration change.
+  int64 cursor_display_id_for_restore_;
 
   base::WeakPtrFactory<DisplayController> weak_ptr_factory_;
 
diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc
index aa6475b..d88416e 100644
--- a/ash/touch/touch_transformer_controller.cc
+++ b/ash/touch/touch_transformer_controller.cc
@@ -204,8 +204,8 @@
       RootWindowController::ForWindow(root)->ash_host()->UpdateDisplayID(
           display1_id, display2_id);
       DisplayInfo source_display =
-          gfx::Display::InternalDisplayId() == display1_id ?
-          display1 : display2;
+          display_controller->GetPrimaryDisplayId() == display1_id ? display1
+                                                                   : display2;
       // Mapping from framebuffer size to the source display's native
       // resolution.
       device_manager->UpdateTouchInfoForDisplay(
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc
index 3ecc0bc2..2f46e5c 100644
--- a/ash/virtual_keyboard_controller.cc
+++ b/ash/virtual_keyboard_controller.cc
@@ -50,13 +50,19 @@
 }
 
 void VirtualKeyboardController::OnMaximizeModeStarted() {
-  if (!IsSmartVirtualKeyboardEnabled())
+  if (!IsSmartVirtualKeyboardEnabled()) {
     SetKeyboardEnabled(true);
+  } else {
+    UpdateKeyboardEnabled();
+  }
 }
 
 void VirtualKeyboardController::OnMaximizeModeEnded() {
-  if (!IsSmartVirtualKeyboardEnabled())
+  if (!IsSmartVirtualKeyboardEnabled()) {
     SetKeyboardEnabled(false);
+  } else {
+    UpdateKeyboardEnabled();
+  }
 }
 
 void VirtualKeyboardController::OnTouchscreenDeviceConfigurationChanged() {
@@ -103,11 +109,16 @@
                            ->IsMaximizeModeWindowManagerEnabled());
     return;
   }
-  SetKeyboardEnabled(!has_internal_keyboard_ && has_touchscreen_ &&
+  bool ignore_internal_keyboard = Shell::GetInstance()
+                                      ->maximize_mode_controller()
+                                      ->IsMaximizeModeWindowManagerEnabled();
+  bool is_internal_keyboard_active =
+      has_internal_keyboard_ && !ignore_internal_keyboard;
+  SetKeyboardEnabled(!is_internal_keyboard_active && has_touchscreen_ &&
                      (!has_external_keyboard_ || ignore_external_keyboard_));
   ash::Shell::GetInstance()
       ->system_tray_notifier()
-      ->NotifyVirtualKeyboardSuppressionChanged(!has_internal_keyboard_ &&
+      ->NotifyVirtualKeyboardSuppressionChanged(!is_internal_keyboard_active &&
                                                 has_touchscreen_ &&
                                                 has_external_keyboard_);
 }
diff --git a/ash/virtual_keyboard_controller_unittest.cc b/ash/virtual_keyboard_controller_unittest.cc
index f3d169b..7ca7a2a 100644
--- a/ash/virtual_keyboard_controller_unittest.cc
+++ b/ash/virtual_keyboard_controller_unittest.cc
@@ -154,7 +154,7 @@
 };
 
 // Tests that the onscreen keyboard is disabled if an internal keyboard is
-// present.
+// present and maximized mode is disabled.
 TEST_F(VirtualKeyboardControllerAutoTest, DisabledIfInternalKeyboardPresent) {
   std::vector<ui::TouchscreenDevice> screens;
   screens.push_back(ui::TouchscreenDevice(
@@ -235,6 +235,79 @@
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
 }
 
+// Tests maximized mode interaction without disabling the internal keyboard.
+TEST_F(VirtualKeyboardControllerAutoTest, EnabledDuringMaximizeMode) {
+  std::vector<ui::TouchscreenDevice> screens;
+  screens.push_back(ui::TouchscreenDevice(
+      1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1024, 768), 0));
+  UpdateTouchscreenDevices(screens);
+  std::vector<ui::KeyboardDevice> keyboards;
+  keyboards.push_back(
+      ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL));
+  UpdateKeyboardDevices(keyboards);
+  ASSERT_FALSE(keyboard::IsKeyboardEnabled());
+  // Toggle maximized mode on.
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(true);
+  ASSERT_TRUE(keyboard::IsKeyboardEnabled());
+  // Toggle maximized mode off.
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(false);
+  ASSERT_FALSE(keyboard::IsKeyboardEnabled());
+}
+
+// Tests that keyboard gets suppressed in maximized mode.
+TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInMaximizedMode) {
+  std::vector<ui::TouchscreenDevice> screens;
+  screens.push_back(ui::TouchscreenDevice(
+      1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL, gfx::Size(1024, 768), 0));
+  UpdateTouchscreenDevices(screens);
+  std::vector<ui::KeyboardDevice> keyboards;
+  keyboards.push_back(
+      ui::KeyboardDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL));
+  keyboards.push_back(
+      ui::KeyboardDevice(2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL));
+  UpdateKeyboardDevices(keyboards);
+  // Toggle maximized mode on.
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(true);
+  ASSERT_FALSE(keyboard::IsKeyboardEnabled());
+  ASSERT_TRUE(notified());
+  ASSERT_TRUE(IsVirtualKeyboardSuppressed());
+  // Toggle show keyboard. Keyboard should be visible.
+  ResetObserver();
+  Shell::GetInstance()
+      ->virtual_keyboard_controller()
+      ->ToggleIgnoreExternalKeyboard();
+  ASSERT_TRUE(keyboard::IsKeyboardEnabled());
+  ASSERT_TRUE(notified());
+  ASSERT_TRUE(IsVirtualKeyboardSuppressed());
+  // Toggle show keyboard. Keyboard should be hidden.
+  ResetObserver();
+  Shell::GetInstance()
+      ->virtual_keyboard_controller()
+      ->ToggleIgnoreExternalKeyboard();
+  ASSERT_FALSE(keyboard::IsKeyboardEnabled());
+  ASSERT_TRUE(notified());
+  ASSERT_TRUE(IsVirtualKeyboardSuppressed());
+  // Remove external keyboard. Should be notified that the keyboard is not
+  // suppressed.
+  ResetObserver();
+  keyboards.pop_back();
+  UpdateKeyboardDevices(keyboards);
+  ASSERT_TRUE(keyboard::IsKeyboardEnabled());
+  ASSERT_TRUE(notified());
+  ASSERT_FALSE(IsVirtualKeyboardSuppressed());
+  // Toggle maximized mode oFF.
+  Shell::GetInstance()
+      ->maximize_mode_controller()
+      ->EnableMaximizeModeWindowManager(false);
+  ASSERT_FALSE(keyboard::IsKeyboardEnabled());
+}
+
 class VirtualKeyboardControllerAlwaysEnabledTest
     : public VirtualKeyboardControllerAutoTest {
  public:
diff --git a/ash/wm/overview/overview_animation_type.h b/ash/wm/overview/overview_animation_type.h
index 5df51cb..dde3a15 100644
--- a/ash/wm/overview/overview_animation_type.h
+++ b/ash/wm/overview/overview_animation_type.h
@@ -14,8 +14,6 @@
   OVERVIEW_ANIMATION_NONE,
   // Used to fade in the close button and label.
   OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN,
-  // Used to fade out the close button.
-  OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT,
   // Used to position windows when entering/exiting overview mode and when a
   // window is closed while overview mode is active.
   OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS,
@@ -23,12 +21,7 @@
   OVERVIEW_ANIMATION_HIDE_WINDOW,
   // Used to restore windows to their original position when exiting overview
   // mode.
-  OVERVIEW_ANIMATION_RESTORE_WINDOW,
-  // Used to animate windows when a user performs a touch drag gesture.
-  OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM,
-  // Used to animate windows back in to position when a touch drag gesture is
-  // cancelled.
-  OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL
+  OVERVIEW_ANIMATION_RESTORE_WINDOW
 };
 
 }  // namespace ash
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc
index 3cb6bcb..e0cf977 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.cc
+++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -20,22 +20,15 @@
 // The time duration for widgets to fade in.
 const int kFadeInMilliseconds = 80;
 
-// The time duration for widgets to fade out.
-const int kFadeOutMilliseconds = 100;
-
 base::TimeDelta GetAnimationDuration(OverviewAnimationType animation_type) {
   switch (animation_type) {
     case OVERVIEW_ANIMATION_NONE:
-    case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM:
       return base::TimeDelta();
     case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_IN:
       return base::TimeDelta::FromMilliseconds(kFadeInMilliseconds);
-    case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT:
-      return base::TimeDelta::FromMilliseconds(kFadeOutMilliseconds);
     case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS:
     case OVERVIEW_ANIMATION_RESTORE_WINDOW:
     case OVERVIEW_ANIMATION_HIDE_WINDOW:
-    case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL:
       return base::TimeDelta::FromMilliseconds(kTransitionMilliseconds);
   }
   NOTREACHED();
@@ -51,7 +44,6 @@
 
   switch (animation_type) {
     case OVERVIEW_ANIMATION_NONE:
-    case OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM:
       animation_settings_.SetPreemptionStrategy(
           ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
       break;
@@ -63,10 +55,6 @@
       animation_settings_.SetPreemptionStrategy(
           ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
       break;
-    case OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT:
-      animation_settings_.SetPreemptionStrategy(
-          ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
-      break;
     case OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS:
     case OVERVIEW_ANIMATION_RESTORE_WINDOW:
       animation_settings_.SetPreemptionStrategy(
@@ -77,11 +65,6 @@
       animation_settings_.SetPreemptionStrategy(
           ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
       break;
-    case OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL:
-      animation_settings_.SetPreemptionStrategy(
-          ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-      animation_settings_.SetTweenType(gfx::Tween::EASE_IN_OUT);
-      break;
   }
   animation_settings_.SetTransitionDuration(
       GetAnimationDuration(animation_type));
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 6f21c8f..df14d27 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_state_delegate.h"
@@ -16,15 +15,12 @@
 #include "ash/wm/overview/window_selector.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
-#include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "ui/aura/window.h"
 
 namespace ash {
 
-WindowSelectorController::WindowSelectorController()
-    : swipe_to_close_enabled_(base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshEnableSwipeToCloseInOverviewMode)) {
+WindowSelectorController::WindowSelectorController() {
 }
 
 WindowSelectorController::~WindowSelectorController() {
diff --git a/ash/wm/overview/window_selector_controller.h b/ash/wm/overview/window_selector_controller.h
index 518d05de..8d4a625 100644
--- a/ash/wm/overview/window_selector_controller.h
+++ b/ash/wm/overview/window_selector_controller.h
@@ -48,8 +48,6 @@
   // are visible during overview mode.
   bool IsRestoringMinimizedWindows() const;
 
-  bool swipe_to_close_enabled() const { return swipe_to_close_enabled_; }
-
   // WindowSelectorDelegate:
   void OnSelectionEnded() override;
 
@@ -62,9 +60,6 @@
   scoped_ptr<WindowSelector> window_selector_;
   base::Time last_selection_time_;
 
-  // Tracks whether the "Swipe-to-close" feature is enabled.
-  bool swipe_to_close_enabled_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowSelectorController);
 };
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 7e74caf..f3e8eca2 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -37,13 +37,6 @@
 
 namespace {
 
-// The minimum fling velocity which will cause a window to be closed.  Unit is
-// pixels per second.
-const float kMinimumFlingVelocity = 4000.0f;
-
-// The minimum opacity used during touch scroll gestures.
-const float kMinimumOpacity = 0.2f;
-
 // In the conceptual overview table, the window margin is the space reserved
 // around the window within the cell. This margin does not overlap so the
 // closest distance between adjacent windows will be twice this amount.
@@ -91,24 +84,6 @@
   layer->SetOpacity(1.0f);
 }
 
-// Convenience method to fade out a window using the animation settings defined
-// by OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT.
-void SetupFadeOut(aura::Window* window) {
-  ScopedOverviewAnimationSettings animation_settings(
-      OverviewAnimationType::OVERVIEW_ANIMATION_ENTER_OVERVIEW_MODE_FADE_OUT,
-      window);
-  window->layer()->SetOpacity(0.0f);
-}
-
-// Calculates the window opacity from the given scroll |distance| and the
-// |min opacity_distance|.
-float CalculateOpacityFromScrollDistance(int distance,
-                                         int min_opacity_distance) {
-  float opacity =
-      1.0f - static_cast<float>(abs(distance)) / min_opacity_distance;
-  return std::min(1.0f, std::max(kMinimumOpacity, opacity));
-}
-
 // An image button with a close window icon.
 class OverviewCloseButton : public views::ImageButton {
  public:
@@ -136,10 +111,9 @@
 }  // namespace
 
 WindowSelectorItem::OverviewLabelButton::OverviewLabelButton(
-    WindowSelectorItem* selector_item,
+    views::ButtonListener* listener,
     const base::string16& text)
-    : LabelButton(selector_item, text),
-      selector_item_(selector_item),
+    : LabelButton(listener, text),
       top_padding_(0) {
 }
 
@@ -152,12 +126,6 @@
   return bounds;
 }
 
-void WindowSelectorItem::OverviewLabelButton::OnGestureEvent(
-    ui::GestureEvent* event) {
-  selector_item_->OnGestureEvent(event);
-  views::LabelButton::OnGestureEvent(event);
-}
-
 WindowSelectorItem::WindowSelectorItem(aura::Window* window)
     : dimmed_(false),
       root_window_(window->GetRootWindow()),
@@ -260,72 +228,6 @@
   wm::GetWindowState(transform_window_.window())->Activate();
 }
 
-void WindowSelectorItem::OnGestureEvent(ui::GestureEvent* event) {
-  if (!Shell::GetInstance()
-           ->window_selector_controller()
-           ->swipe_to_close_enabled())
-    return;
-
-  int delta_x = 0;
-  if (event->type() == ui::ET_GESTURE_SCROLL_BEGIN)
-    scroll_x_origin_ = event->x();
-  else
-    delta_x = event->x() - scroll_x_origin_;
-
-  switch (event->type()) {
-    case ui::ET_GESTURE_SCROLL_BEGIN: {
-      // We need to call SetHandled() for the ET_GESTURE_SCROLL_BEGIN event so
-      // that future ET_GESTURE_SCROLL_* events are sent here.
-      event->SetHandled();
-      close_button_->SetEnabled(false);
-      SetupFadeOut(close_button_widget_.GetNativeWindow());
-      break;
-    }
-    case ui::ET_GESTURE_SCROLL_UPDATE: {
-      event->SetHandled();
-      ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
-      transform_window_.BeginScopedAnimation(
-          OverviewAnimationType::OVERVIEW_ANIMATION_SCROLL_SELECTOR_ITEM,
-          &animation_settings);
-
-      gfx::Transform new_transform;
-      new_transform.Translate(delta_x, 0);
-      new_transform.PreconcatTransform(
-          transform_window_.get_overview_transform());
-      transform_window_.SetTransform(root_window(), new_transform);
-
-      const float opacity = CalculateOpacityFromScrollDistance(
-          delta_x, GetMinimumCloseDistance());
-      transform_window_.SetOpacity(opacity);
-      break;
-    }
-    case ui::ET_GESTURE_SCROLL_END: {
-      event->SetHandled();
-      if (abs(delta_x) > GetMinimumCloseDistance()) {
-        transform_window_.Close();
-        break;
-      }
-      ResetScrolledWindow();
-      break;
-    }
-    case ui::ET_SCROLL_FLING_START: {
-      event->SetHandled();
-      if (abs(delta_x) > GetMinimumCloseDistance() ||
-          fabs(event->details().velocity_x()) > kMinimumFlingVelocity) {
-        transform_window_.Close();
-        break;
-      }
-      ResetScrolledWindow();
-      break;
-    }
-    case ui::ET_GESTURE_END:
-      scroll_x_origin_ = 0;
-      break;
-    default:
-      break;
-  }
-}
-
 void WindowSelectorItem::OnWindowDestroying(aura::Window* window) {
   window->RemoveObserver(this);
   transform_window_.OnWindowDestroyed();
@@ -338,20 +240,6 @@
   UpdateCloseButtonAccessibilityName();
 }
 
-void WindowSelectorItem::ResetScrolledWindow() {
-  ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
-  transform_window_.BeginScopedAnimation(
-      OverviewAnimationType::OVERVIEW_ANIMATION_CANCEL_SELECTOR_ITEM_SCROLL,
-      &animation_settings);
-
-  transform_window_.SetTransform(root_window(),
-                                 transform_window_.get_overview_transform());
-  transform_window_.SetOpacity(1.0);
-
-  SetupFadeInAfterLayout(close_button_widget_.GetNativeWindow());
-  close_button_->SetEnabled(true);
-}
-
 void WindowSelectorItem::SetItemBounds(const gfx::Rect& target_bounds,
                                        OverviewAnimationType animation_type) {
   DCHECK(root_window_ == GetWindow()->GetRootWindow());
@@ -456,8 +344,4 @@
       GetWindow()->title()));
 }
 
-int WindowSelectorItem::GetMinimumCloseDistance() const {
-  return target_bounds_.size().width() / 2;
-}
-
 }  // namespace ash
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 0e4aa8fa..063b141e 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -33,25 +33,18 @@
  public:
   class OverviewLabelButton : public views::LabelButton {
    public:
-    OverviewLabelButton(WindowSelectorItem* selector_item,
+    OverviewLabelButton(views::ButtonListener* listener,
                         const base::string16& text);
 
     ~OverviewLabelButton() override;
 
     void set_top_padding(int top_padding) { top_padding_ = top_padding; }
 
-    // views::LabelButton:
-    void OnGestureEvent(ui::GestureEvent* event) override;
-
    protected:
     // views::LabelButton:
     gfx::Rect GetChildAreaBounds() override;
 
    private:
-    // The WindowSelectorItem that the touch gestures are delegated to.
-    // Not owned.
-    WindowSelectorItem* selector_item_;
-
     // Padding on top of the button.
     int top_padding_;
 
@@ -101,9 +94,6 @@
 
   const gfx::Rect& target_bounds() const { return target_bounds_; }
 
-  // Handles the gestures on the Window
-  void OnGestureEvent(ui::GestureEvent* event);
-
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
@@ -137,14 +127,6 @@
   // Updates the close buttons accessibility name.
   void UpdateCloseButtonAccessibilityName();
 
-  // Animates the |transform_window_| back to it's original overview mode
-  // position.
-  void ResetScrolledWindow();
-
-  // Returns the minimum distance at which a scroll gesture will cause this
-  // selector item to be closed.
-  int GetMinimumCloseDistance() const;
-
   // True if the item is being shown in the overview, false if it's being
   // filtered.
   bool dimmed_;
@@ -176,10 +158,6 @@
   // close_button_widget_.
   views::ImageButton* close_button_;
 
-  // The original X location for a scroll begin event. |original_x_| is in the
-  // local coordinate space of |window_label_button_view_|.
-  float scroll_x_origin_;
-
   DISALLOW_COPY_AND_ASSIGN(WindowSelectorItem);
 };
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index ec60952..5ebf669 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -3,11 +3,9 @@
 // found in the LICENSE file.
 
 #include <algorithm>
-#include <map>
 #include <vector>
 
 #include "ash/accessibility_delegate.h"
-#include "ash/ash_switches.h"
 #include "ash/drag_drop/drag_drop_controller.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
@@ -73,18 +71,6 @@
   }
 }
 
-// A short drag distance that will not cause an overview item to close.
-const int kShortDragDistance = 10;
-
-// A far drag distance that will cause an overview item to close.
-const int kFarDragDistance = 200;
-
-// A slow fling velocity that should not cause selctor items to close.
-const int kSlowFlingVelocity = 2000;
-
-// A fast fling velocity that should cause selector items to close.
-const int kFastFlingVelocity = 5000;
-
 }  // namespace
 
 // TODO(bruthig): Move all non-simple method definitions out of class
@@ -279,24 +265,6 @@
   DISALLOW_COPY_AND_ASSIGN(WindowSelectorTest);
 };
 
-class WindowSelectorSwipeToCloseEnabledTest : public WindowSelectorTest {
- public:
-  WindowSelectorSwipeToCloseEnabledTest() {}
-  ~WindowSelectorSwipeToCloseEnabledTest() override {}
-
-  // WindowSelectorTest:
-  void SetUp() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WindowSelectorSwipeToCloseEnabledTest);
-};
-
-void WindowSelectorSwipeToCloseEnabledTest::SetUp() {
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      switches::kAshEnableSwipeToCloseInOverviewMode);
-  WindowSelectorTest::SetUp();
-}
-
 // Tests that an a11y alert is sent on entering overview mode.
 TEST_F(WindowSelectorTest, A11yAlertOnOverviewMode) {
   gfx::Rect bounds(0, 0, 400, 400);
@@ -1274,210 +1242,4 @@
   EXPECT_FALSE(IsSelecting());
 }
 
-// Verify swipe to close doesn't work when swipe to close is not enabled.
-TEST_F(WindowSelectorTest, WindowTapDragFarDistance) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-  ASSERT_TRUE(IsSelecting());
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint());
-  gfx::Point end(start.x() - kFarDragDistance, start.y());
-  event_generator.GestureScrollSequence(
-      start, end, base::TimeDelta::FromMilliseconds(10), 5);
-
-  EXPECT_FALSE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_TRUE(IsSelecting());
-}
-
-// Verify the window moves and fades as it is dragged.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest,
-       VerifyWindowBehaviourDuringTapDrag) {
-  scoped_ptr<aura::Window> window(CreateWindow(gfx::Rect(0, 0, 400, 400)));
-
-  ToggleOverview();
-
-  gfx::Rect bounds =
-      ToNearestRect(GetTransformedBoundsInRootWindow(window.get()));
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  const gfx::Point drag_start_point(bounds.CenterPoint());
-  const gfx::Point drag_left_point(drag_start_point.x() - kFarDragDistance,
-                                   drag_start_point.y());
-  const gfx::Point drag_right_point(drag_start_point.x() + kFarDragDistance,
-                                    drag_start_point.y());
-
-  const int drag_left_delta_x = drag_start_point.x() - drag_left_point.x();
-  const int drag_right_delta_x = drag_start_point.x() - drag_right_point.x();
-
-  const gfx::Rect original_bounds = window->GetBoundsInScreen();
-
-  ASSERT_EQ(1.0f, window->layer()->opacity());
-
-  event_generator.set_current_location(drag_start_point);
-  event_generator.PressTouch();
-
-  EXPECT_EQ(1.0f, window->layer()->opacity());
-
-  event_generator.MoveTouch(drag_left_point);
-
-  EXPECT_EQ(original_bounds.x() - drag_left_delta_x,
-            window->GetBoundsInScreen().x());
-  EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
-
-  EXPECT_LT(window->layer()->opacity(), 0.5f);
-
-  event_generator.MoveTouch(drag_start_point);
-
-  EXPECT_EQ(original_bounds.x(), window->GetBoundsInScreen().x());
-  EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
-  EXPECT_EQ(1.0f, window->layer()->opacity());
-
-  event_generator.MoveTouch(drag_right_point);
-
-  EXPECT_EQ(original_bounds.x() - drag_right_delta_x,
-            window->GetBoundsInScreen().x());
-  EXPECT_EQ(original_bounds.y(), window->GetBoundsInScreen().y());
-
-  EXPECT_LT(window->layer()->opacity(), 0.5f);
-}
-
-// Test dragging a window a short distance.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest, WindowTapDragShortDistance) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint());
-  gfx::Point end(start.x() - kShortDragDistance, start.y());
-  event_generator.GestureScrollSequence(
-      start, end, base::TimeDelta::FromMilliseconds(10), 5);
-
-  EXPECT_FALSE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_TRUE(IsSelecting());
-}
-
-// Test dragging a window a far distance.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest, WindowTapDragFarDistance) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-  ASSERT_TRUE(IsSelecting());
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::Rect bounds = ToNearestRect(GetTransformedBoundsInRootWindow(window));
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint());
-  gfx::Point end(start.x() - kFarDragDistance, start.y());
-  event_generator.GestureScrollSequence(
-      start, end, base::TimeDelta::FromMilliseconds(10), 5);
-
-  EXPECT_TRUE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_FALSE(IsSelecting());
-}
-
-// Test a slow velocity fling.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest, SlowVelocityFling) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
-  gfx::Point end(start.x() - kShortDragDistance, start.y());
-  const base::TimeDelta kScrollDuration =
-      event_generator.CalculateScrollDurationForFlingVelocity(
-          start, end, kSlowFlingVelocity, 10);
-  event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
-
-  EXPECT_FALSE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_TRUE(IsSelecting());
-}
-
-// Test a fast velocity fling.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest, FastVelocityFling) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-  ASSERT_TRUE(IsSelecting());
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
-  gfx::Point end(start.x() - kShortDragDistance, start.y());
-  const base::TimeDelta kScrollDuration =
-      event_generator.CalculateScrollDurationForFlingVelocity(
-          start, end, kFastFlingVelocity, 10);
-  event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
-
-  EXPECT_TRUE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_FALSE(IsSelecting());
-}
-
-// Test a fast velocity fling.
-TEST_F(WindowSelectorSwipeToCloseEnabledTest, SlowVelocityFlingAtAFarDistance) {
-  scoped_ptr<views::Widget> widget =
-      CreateWindowWidget(gfx::Rect(0, 0, 400, 400));
-
-  ToggleOverview();
-  ASSERT_TRUE(IsSelecting());
-
-  aura::Window* window = widget->GetNativeWindow();
-  gfx::RectF bounds = GetTransformedBoundsInRootWindow(window);
-  ui::test::EventGenerator event_generator(window->GetRootWindow());
-
-  ASSERT_FALSE(widget->IsClosed());
-
-  gfx::Point start(bounds.CenterPoint().x(), bounds.CenterPoint().y());
-  gfx::Point end(start.x() - kFarDragDistance, start.y());
-  const base::TimeDelta kScrollDuration =
-      event_generator.CalculateScrollDurationForFlingVelocity(
-          start, end, kSlowFlingVelocity, 10);
-  event_generator.GestureScrollSequence(start, end, kScrollDuration, 10);
-
-  EXPECT_TRUE(widget->IsClosed());
-
-  RunAllPendingInMessageLoop();
-  EXPECT_FALSE(IsSelecting());
-}
-
 }  // namespace ash
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
index 2795b19..25d937e 100644
--- a/base/mac/sdk_forward_declarations.h
+++ b/base/mac/sdk_forward_declarations.h
@@ -285,6 +285,10 @@
 - (NSString*)UUIDString;
 @end
 
+@interface NSControl (MountainLionSDK)
+@property BOOL allowsExpansionToolTips;
+@end
+
 #endif  // MAC_OS_X_VERSION_10_8
 
 
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h
index 59c5d5b5..e3b437c 100644
--- a/base/memory/discardable_shared_memory.h
+++ b/base/memory/discardable_shared_memory.h
@@ -74,7 +74,7 @@
   // must have been mapped via Map().
   void* memory() const;
 
-  // Returns the last know usage time for DiscardableSharedMemory object. This
+  // Returns the last known usage time for DiscardableSharedMemory object. This
   // may be earlier than the "true" usage time when memory has been used by a
   // different process. Returns NULL time if purged.
   Time last_known_usage() const { return last_known_usage_; }
@@ -84,7 +84,7 @@
   // for two reasons; object might be locked or our last known usage timestamp
   // might be out of date. Last known usage time is updated to |current_time|
   // if locked or the actual last usage timestamp if unlocked. It is often
-  // neccesary to call this function twice for the object to successfully be
+  // necessary to call this function twice for the object to successfully be
   // purged. First call, updates |last_known_usage_|. Second call, successfully
   // purges the object using the updated |last_known_usage_|.
   // Note: there is no guarantee that multiple calls to this function will
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 3430169..cbed238 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 
+#include "base/atomic_sequence_num.h"
 #include "base/compiler_specific.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/process_memory_dump.h"
@@ -15,7 +16,27 @@
 namespace trace_event {
 
 namespace {
+
 MemoryDumpManager* g_instance_for_testing = nullptr;
+const int kTraceEventNumArgs = 1;
+const char* kTraceEventArgNames[] = {"dumps"};
+const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+StaticAtomicSequenceNumber g_next_guid;
+
+const char* DumpPointTypeToString(const DumpPointType& dump_point_type) {
+  switch (dump_point_type) {
+    case DumpPointType::TASK_BEGIN:
+      return "TASK_BEGIN";
+    case DumpPointType::TASK_END:
+      return "TASK_END";
+    case DumpPointType::PERIODIC_INTERVAL:
+      return "PERIODIC_INTERVAL";
+    case DumpPointType::EXPLICITLY_TRIGGERED:
+      return "EXPLICITLY_TRIGGERED";
+  }
+  NOTREACHED();
+  return "UNKNOWN";
+}
 }
 
 // TODO(primiano): this should be smarter and should do something similar to
@@ -76,13 +97,18 @@
     dump_providers_enabled_.erase(it);
 }
 
-void MemoryDumpManager::RequestDumpPoint(DumpPointType type) {
-  // TODO(primiano): this will have more logic, IPC broadcast & co.
+void MemoryDumpManager::RequestDumpPoint(DumpPointType dump_point_type) {
+  // TODO(primiano): this will have more logic to coordinate dump points across
+  // multiple processes via IPC. See crbug.com/462930.
+
   // Bail out immediately if tracing is not enabled at all.
   if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
     return;
 
-  CreateLocalDumpPoint();
+  // TODO(primiano): Make guid actually unique (cross-process) by hashing it
+  // with the PID. See crbug.com/462931 for details.
+  const uint64 guid = g_next_guid.GetNext();
+  CreateLocalDumpPoint(dump_point_type, guid);
 }
 
 void MemoryDumpManager::BroadcastDumpRequest() {
@@ -90,23 +116,28 @@
 }
 
 // Creates a dump point for the current process and appends it to the trace.
-void MemoryDumpManager::CreateLocalDumpPoint() {
-  AutoLock lock(lock_);
+void MemoryDumpManager::CreateLocalDumpPoint(DumpPointType dump_point_type,
+                                             uint64 guid) {
   bool did_any_provider_dump = false;
   scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump());
 
-  for (auto it = dump_providers_enabled_.begin();
-       it != dump_providers_enabled_.end();) {
-    MemoryDumpProvider* dump_provider = *it;
-    if (!dump_provider->DumpInto(pmd.get())) {
-      LOG(ERROR) << "The memory dumper " << dump_provider->GetFriendlyName()
-                 << " failed, possibly due to sandboxing (crbug.com/461788), "
-                    "disabling it for current process. Try restarting chrome "
-                    "with the --no-sandbox switch.";
-      it = dump_providers_enabled_.erase(it);
-    } else {
-      did_any_provider_dump = true;
-      ++it;
+  // Serialize dump point generation so that memory dump providers don't have to
+  // deal with thread safety.
+  {
+    AutoLock lock(lock_);
+    for (auto it = dump_providers_enabled_.begin();
+         it != dump_providers_enabled_.end();) {
+      MemoryDumpProvider* dump_provider = *it;
+      if (dump_provider->DumpInto(pmd.get())) {
+        did_any_provider_dump = true;
+        ++it;
+      } else {
+        LOG(ERROR) << "The memory dumper " << dump_provider->GetFriendlyName()
+                   << " failed, possibly due to sandboxing (crbug.com/461788), "
+                      "disabling it for current process. Try restarting chrome "
+                      "with the --no-sandbox switch.";
+        it = dump_providers_enabled_.erase(it);
+      }
     }
   }
 
@@ -114,9 +145,15 @@
   if (!did_any_provider_dump)
     return;
 
-  scoped_refptr<TracedValue> value(new TracedValue());
-  pmd->AsValueInto(value.get());
-  // TODO(primiano): add the dump point to the trace at this point.
+  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+  pmd->AsValueInto(static_cast<TracedValue*>(event_value.get()));
+  const char* const event_name = DumpPointTypeToString(dump_point_type);
+
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      TRACE_EVENT_PHASE_MEMORY_DUMP,
+      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name, guid,
+      kTraceEventNumArgs, kTraceEventArgNames, kTraceEventArgTypes,
+      NULL /* arg_values */, &event_value, TRACE_EVENT_FLAG_HAS_ID);
 }
 
 void MemoryDumpManager::OnTraceLogEnabled() {
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 1a22e61..8a9b3b7e 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -43,7 +43,7 @@
 
   // Requests a memory dump. The dump might happen or not depending on the
   // filters and categories specified when enabling tracing.
-  void RequestDumpPoint(DumpPointType type);
+  void RequestDumpPoint(DumpPointType dump_point_type);
 
   // TraceLog::EnabledStateObserver implementation.
   void OnTraceLogEnabled() override;
@@ -65,7 +65,7 @@
   void BroadcastDumpRequest();
 
   // Creates a dump point for the current process and appends it to the trace.
-  void CreateLocalDumpPoint();
+  void CreateLocalDumpPoint(DumpPointType dump_point_type, uint64 guid);
 
   std::vector<MemoryDumpProvider*> dump_providers_registered_;  // Not owned.
   std::vector<MemoryDumpProvider*> dump_providers_enabled_;     // Not owned.
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index e12d8f42..c30a84a 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -1039,6 +1039,7 @@
 #define TRACE_EVENT_PHASE_CREATE_OBJECT ('N')
 #define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O')
 #define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
 
 // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
 #define TRACE_EVENT_FLAG_NONE         (static_cast<unsigned char>(0))
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 42fef18..80d7096 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -1,3 +1,4 @@
+H B Nm: The class name org.chromium.chrome.browser.UmaUtils shadows the simple name of the superclass org.chromium.chrome.browser.metrics.UmaUtils  At UmaUtils.java
 M M LI: Incorrect lazy initialization of static field org.chromium.chrome.browser.download.DownloadManagerService.sDownloadManagerService in org.chromium.chrome.browser.download.DownloadManagerService.getDownloadManagerService(Context)  At DownloadManagerService.java
 M D UrF: Unread public/protected field: org.chromium.chrome.browser.document.PendingDocumentData.extraHeaders  At DocumentTabModelSelector.java
 M D UrF: Unread public/protected field: org.chromium.chrome.browser.document.PendingDocumentData.postData  At DocumentTabModelSelector.java
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index 5a169c1..3214623 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -79,9 +79,6 @@
   </issue>
   <issue id="SetJavaScriptEnabled" severity="ignore"/>
   <issue id="UnusedResources">
-    <!-- TODO(aurimas): remove suppression once crbug.com/458328 is fixed. -->
-    <ignore path="content/public/android/java/res/layout/validation_message_bubble.xml" />
-
     <!-- These files are used by chrome_shell_apk and chrome_apk targets. -->
     <ignore path="chrome/android/java/res/layout/accessibility_tab_switcher.xml" />
     <ignore path="chrome/android/java/res/drawable/btn_back.xml" />
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py
index 6b3ea1d..6d63352 100755
--- a/build/android/provision_devices.py
+++ b/build/android/provision_devices.py
@@ -125,7 +125,7 @@
                          as_root=True)
 
 
-def WipeDeviceData(device):
+def WipeDeviceData(device, options):
   """Wipes data from device, keeping only the adb_keys for authorization.
 
   After wiping data on a device that has been authorized, adb can still
@@ -139,16 +139,22 @@
   """
   device_authorized = device.FileExists(constants.ADB_KEYS_FILE)
   if device_authorized:
-    adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, as_root=True)
+    adb_keys = device.ReadFile(constants.ADB_KEYS_FILE,
+                               as_root=True).splitlines()
   device.RunShellCommand('wipe data', as_root=True)
   if device_authorized:
-    WriteAdbKeysFile(device, adb_keys)
+    adb_keys_set = set(adb_keys)
+    for adb_key_file in options.adb_key_files or []:
+      with open(adb_key_file, 'r') as f:
+        adb_public_keys = f.readlines()
+      adb_keys_set.update(adb_public_keys)
+    WriteAdbKeysFile(device, '\n'.join(adb_keys_set))
 
 
-def WipeDeviceIfPossible(device, timeout):
+def WipeDeviceIfPossible(device, timeout, options):
   try:
     device.EnableRoot()
-    WipeDeviceData(device)
+    WipeDeviceData(device, options)
     device.Reboot(True, timeout=timeout, retries=0)
   except (errors.DeviceUnresponsiveError, device_errors.CommandFailedError):
     pass
@@ -177,17 +183,9 @@
   else:
     reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
 
-  if options.adb_key_files:
-    adb_keys = set()
-    for adb_key_file in options.adb_key_files:
-      with open(adb_key_file, 'r') as f:
-        adb_public_keys = f.readlines()
-      adb_keys.update(adb_public_keys)
-    WriteAdbKeysFile(device, '\n'.join(adb_keys))
-
   try:
     if not options.skip_wipe:
-      WipeDeviceIfPossible(device, reboot_timeout)
+      WipeDeviceIfPossible(device, reboot_timeout, options)
     try:
       device.EnableRoot()
     except device_errors.CommandFailedError as e:
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
index b05f7ee..e1a13666 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -15,6 +15,10 @@
 # Crashes
 RenderFrameHostManagerTest.IgnoreRendererDebugURLsWhenCrashed
 
+# Crashes due to using --disable-gpu.
+# Needs to investigate more in http://crbug.com/461624.
+ScreenOrientationBrowserTest.*
+
 # Plugins are not supported.
 BrowserPluginThreadedCompositorPixelTest.*
 BrowserPluginHostTest.*
@@ -67,3 +71,7 @@
 
 # http://crbug.com/343604
 MSE_ClearKey/EncryptedMediaTest.ConfigChangeVideo/0
+
+# http://crbug.com/463041
+ScreenOrientationBrowserTest.ScreenOrientationChange
+ScreenOrientationBrowserTest.WindowOrientationCange
diff --git a/build/android/pylib/remote/device/remote_device_environment.py b/build/android/pylib/remote/device/remote_device_environment.py
index 6e75afa3..3b0c029c 100644
--- a/build/android/pylib/remote/device/remote_device_environment.py
+++ b/build/android/pylib/remote/device/remote_device_environment.py
@@ -183,6 +183,7 @@
     os.environ['APPURIFY_API_PROTO'] = self._api_protocol
     os.environ['APPURIFY_API_HOST'] = self._api_address
     os.environ['APPURIFY_API_PORT'] = self._api_port
+    os.environ['APPURIFY_STATUS_BASE_URL'] = 'none'
     self._GetAccessToken()
     if self._trigger:
       self._SelectDevice()
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 7c06e59..3afba89 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -113,11 +113,6 @@
     # toolchains.
     cros_use_custom_toolchain = false
   }
-
-  # TODO(brettw) remove this flag (and therefore enable linking all targets) on
-  # Windows when we have sufficient bot capacity. In the meantime, you can
-  # enable linking for local compiles.
-  link_chrome_on_windows = true
 }
 
 # TODO(dpranke): Remove these asserts when os and cpu_arch are removed.
diff --git a/build/config/features.gni b/build/config/features.gni
index abafd1c..4d01a87 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -49,6 +49,29 @@
 
   # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3.
   proprietary_codecs = false
+
+  enable_configuration_policy = true
+
+  # Enables support for background apps.
+  enable_background = !is_ios && !is_android
+
+  enable_captive_portal_detection = !is_android && !is_ios
+
+  # Enables use of the session service, which is enabled by default.
+  # Android stores them separately on the Java side.
+  enable_session_service = !is_android && !is_ios
+
+  enable_plugin_installation = is_win || is_mac
+
+  enable_app_list = !is_ios && !is_android
+
+  enable_supervised_users = !is_ios
+
+  enable_autofill_dialog = !is_ios && !(is_android && is_android_webview_build)
+
+  enable_google_now = !is_ios && !is_android
+
+  enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
 }
 
 # Additional dependent variables -----------------------------------------------
@@ -113,11 +136,6 @@
   safe_browsing_mode = 1
 }
 
-enable_configuration_policy = true
-
-# Enables support for background apps.
-enable_background = !is_ios && !is_android
-
 enable_task_manager = !is_ios && !is_android
 
 use_cups = is_desktop_linux || is_mac
@@ -127,27 +145,14 @@
 # TODO(scottmg) remove this when we've fixed printing.
 win_pdf_metafile_for_printing = true
 
-enable_captive_portal_detection = !is_android && !is_ios
-
-# Enables use of the session service, which is enabled by default.
-# Android stores them separately on the Java side.
-enable_session_service = !is_android && !is_ios
-
 # Whether we are using the rlz library or not.  Platforms like Android send
 # rlz codes for searches but do not use the library.
 enable_rlz = is_chrome_branded && (is_win || is_mac || is_ios || is_chromeos)
 
-enable_plugin_installation = is_win || is_mac
-
-enable_app_list = !is_ios && !is_android
 enable_settings_app = enable_app_list && !is_chromeos
 
-enable_supervised_users = !is_ios
-
 enable_service_discovery = enable_mdns || is_mac
 
-enable_autofill_dialog = !is_ios && !(is_android && is_android_webview_build)
-
 enable_wifi_bootstrapping = is_win || is_mac
 
 # Image loader extension is enabled on ChromeOS only.
@@ -155,10 +160,6 @@
 
 enable_remoting = !is_ios && !is_android
 
-enable_google_now = !is_ios && !is_android
-
-enable_one_click_signin = is_win || is_mac || (is_linux && !is_chromeos)
-
 # Chrome OS: whether to also build the upcoming version of
 # ChromeVox, which can then be enabled via a command-line switch.
 enable_chromevox_next = false
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 24c24d6..d1e2223f 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -251,9 +251,6 @@
 // http://crbug.com/364006
 "race:gfx::ImageFamily::~ImageFamily\n"
 
-// http://crbug.com/364014
-"race:WTF::Latin1Encoding()::globalLatin1Encoding\n"
-
 // https://code.google.com/p/v8/issues/detail?id=3143
 "race:v8::internal::FLAG_track_double_fields\n"
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 7a97d38..99a8208f 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -731,162 +731,160 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("cc_unittests") {
-    sources = [
-      "animation/animation_unittest.cc",
-      "animation/keyframed_animation_curve_unittest.cc",
-      "animation/layer_animation_controller_unittest.cc",
-      "animation/scroll_offset_animation_curve_unittest.cc",
-      "animation/scrollbar_animation_controller_linear_fade_unittest.cc",
-      "animation/scrollbar_animation_controller_thinning_unittest.cc",
-      "animation/transform_operations_unittest.cc",
-      "base/float_quad_unittest.cc",
-      "base/math_util_unittest.cc",
-      "base/region_unittest.cc",
-      "base/rolling_time_delta_history_unittest.cc",
-      "base/scoped_ptr_vector_unittest.cc",
-      "base/simple_enclosed_region_unittest.cc",
-      "base/tiling_data_unittest.cc",
-      "base/util_unittest.cc",
-      "debug/frame_timing_tracker_unittest.cc",
-      "debug/micro_benchmark_controller_unittest.cc",
-      "input/top_controls_manager_unittest.cc",
-      "layers/contents_scaling_layer_unittest.cc",
-      "layers/delegated_frame_provider_unittest.cc",
-      "layers/delegated_frame_resource_collection_unittest.cc",
-      "layers/delegated_renderer_layer_impl_unittest.cc",
-      "layers/delegated_renderer_layer_unittest.cc",
-      "layers/heads_up_display_layer_impl_unittest.cc",
-      "layers/heads_up_display_unittest.cc",
-      "layers/io_surface_layer_impl_unittest.cc",
-      "layers/layer_impl_unittest.cc",
-      "layers/layer_iterator_unittest.cc",
-      "layers/layer_position_constraint_unittest.cc",
-      "layers/layer_unittest.cc",
-      "layers/layer_utils_unittest.cc",
-      "layers/nine_patch_layer_impl_unittest.cc",
-      "layers/nine_patch_layer_unittest.cc",
-      "layers/painted_scrollbar_layer_impl_unittest.cc",
-      "layers/picture_image_layer_impl_unittest.cc",
-      "layers/picture_image_layer_unittest.cc",
-      "layers/picture_layer_impl_unittest.cc",
-      "layers/picture_layer_unittest.cc",
-      "layers/render_surface_impl_unittest.cc",
-      "layers/render_surface_unittest.cc",
-      "layers/scrollbar_layer_unittest.cc",
-      "layers/solid_color_layer_impl_unittest.cc",
-      "layers/solid_color_scrollbar_layer_impl_unittest.cc",
-      "layers/surface_layer_impl_unittest.cc",
-      "layers/surface_layer_unittest.cc",
-      "layers/texture_layer_impl_unittest.cc",
-      "layers/texture_layer_unittest.cc",
-      "layers/tiled_layer_impl_unittest.cc",
-      "layers/tiled_layer_unittest.cc",
-      "layers/ui_resource_layer_impl_unittest.cc",
-      "layers/ui_resource_layer_unittest.cc",
-      "layers/video_layer_impl_unittest.cc",
-      "output/begin_frame_args_unittest.cc",
-      "output/delegating_renderer_unittest.cc",
-      "output/filter_operations_unittest.cc",
-      "output/gl_renderer_unittest.cc",
-      "output/output_surface_unittest.cc",
-      "output/overlay_unittest.cc",
-      "output/renderer_pixeltest.cc",
-      "output/renderer_unittest.cc",
-      "output/shader_unittest.cc",
-      "output/software_renderer_unittest.cc",
-      "quads/draw_quad_unittest.cc",
-      "quads/list_container_unittest.cc",
-      "quads/render_pass_unittest.cc",
-      "resources/display_item_list_unittest.cc",
-      "resources/layer_quad_unittest.cc",
-      "resources/picture_layer_tiling_set_unittest.cc",
-      "resources/picture_layer_tiling_unittest.cc",
-      "resources/picture_pile_impl_unittest.cc",
-      "resources/picture_pile_unittest.cc",
-      "resources/picture_unittest.cc",
-      "resources/platform_color_unittest.cc",
-      "resources/prioritized_resource_unittest.cc",
-      "resources/resource_provider_unittest.cc",
-      "resources/resource_update_controller_unittest.cc",
-      "resources/scoped_gpu_raster_unittest.cc",
-      "resources/scoped_resource_unittest.cc",
-      "resources/task_graph_runner_unittest.cc",
-      "resources/texture_mailbox_deleter_unittest.cc",
-      "resources/texture_uploader_unittest.cc",
-      "resources/tile_manager_unittest.cc",
-      "resources/tile_priority_unittest.cc",
-      "resources/tile_task_worker_pool_unittest.cc",
-      "resources/video_resource_updater_unittest.cc",
-      "scheduler/begin_frame_source_unittest.cc",
-      "scheduler/delay_based_time_source_unittest.cc",
-      "scheduler/scheduler_state_machine_unittest.cc",
-      "scheduler/scheduler_unittest.cc",
-      "test/layer_tree_json_parser_unittest.cc",
-      "test/test_web_graphics_context_3d_unittest.cc",
-      "trees/blocking_task_runner_unittest.cc",
-      "trees/damage_tracker_unittest.cc",
-      "trees/layer_sorter_unittest.cc",
-      "trees/layer_tree_host_common_unittest.cc",
-      "trees/layer_tree_host_impl_unittest.cc",
-      "trees/layer_tree_host_pixeltest_blending.cc",
-      "trees/layer_tree_host_pixeltest_filters.cc",
-      "trees/layer_tree_host_pixeltest_masks.cc",
-      "trees/layer_tree_host_pixeltest_readback.cc",
-      "trees/layer_tree_host_pixeltest_synchronous.cc",
-      "trees/layer_tree_host_unittest.cc",
-      "trees/layer_tree_host_unittest_animation.cc",
-      "trees/layer_tree_host_unittest_context.cc",
-      "trees/layer_tree_host_unittest_copyrequest.cc",
-      "trees/layer_tree_host_unittest_damage.cc",
-      "trees/layer_tree_host_unittest_delegated.cc",
-      "trees/layer_tree_host_unittest_no_message_loop.cc",
-      "trees/layer_tree_host_unittest_occlusion.cc",
-      "trees/layer_tree_host_unittest_picture.cc",
-      "trees/layer_tree_host_unittest_proxy.cc",
-      "trees/layer_tree_host_unittest_scroll.cc",
-      "trees/layer_tree_host_unittest_video.cc",
-      "trees/layer_tree_impl_unittest.cc",
-      "trees/occlusion_tracker_unittest.cc",
-      "trees/occlusion_unittest.cc",
-      "trees/property_tree_unittest.cc",
-      "trees/tree_synchronizer_unittest.cc",
+test("cc_unittests") {
+  sources = [
+    "animation/animation_unittest.cc",
+    "animation/keyframed_animation_curve_unittest.cc",
+    "animation/layer_animation_controller_unittest.cc",
+    "animation/scroll_offset_animation_curve_unittest.cc",
+    "animation/scrollbar_animation_controller_linear_fade_unittest.cc",
+    "animation/scrollbar_animation_controller_thinning_unittest.cc",
+    "animation/transform_operations_unittest.cc",
+    "base/float_quad_unittest.cc",
+    "base/math_util_unittest.cc",
+    "base/region_unittest.cc",
+    "base/rolling_time_delta_history_unittest.cc",
+    "base/scoped_ptr_vector_unittest.cc",
+    "base/simple_enclosed_region_unittest.cc",
+    "base/tiling_data_unittest.cc",
+    "base/util_unittest.cc",
+    "debug/frame_timing_tracker_unittest.cc",
+    "debug/micro_benchmark_controller_unittest.cc",
+    "input/top_controls_manager_unittest.cc",
+    "layers/contents_scaling_layer_unittest.cc",
+    "layers/delegated_frame_provider_unittest.cc",
+    "layers/delegated_frame_resource_collection_unittest.cc",
+    "layers/delegated_renderer_layer_impl_unittest.cc",
+    "layers/delegated_renderer_layer_unittest.cc",
+    "layers/heads_up_display_layer_impl_unittest.cc",
+    "layers/heads_up_display_unittest.cc",
+    "layers/io_surface_layer_impl_unittest.cc",
+    "layers/layer_impl_unittest.cc",
+    "layers/layer_iterator_unittest.cc",
+    "layers/layer_position_constraint_unittest.cc",
+    "layers/layer_unittest.cc",
+    "layers/layer_utils_unittest.cc",
+    "layers/nine_patch_layer_impl_unittest.cc",
+    "layers/nine_patch_layer_unittest.cc",
+    "layers/painted_scrollbar_layer_impl_unittest.cc",
+    "layers/picture_image_layer_impl_unittest.cc",
+    "layers/picture_image_layer_unittest.cc",
+    "layers/picture_layer_impl_unittest.cc",
+    "layers/picture_layer_unittest.cc",
+    "layers/render_surface_impl_unittest.cc",
+    "layers/render_surface_unittest.cc",
+    "layers/scrollbar_layer_unittest.cc",
+    "layers/solid_color_layer_impl_unittest.cc",
+    "layers/solid_color_scrollbar_layer_impl_unittest.cc",
+    "layers/surface_layer_impl_unittest.cc",
+    "layers/surface_layer_unittest.cc",
+    "layers/texture_layer_impl_unittest.cc",
+    "layers/texture_layer_unittest.cc",
+    "layers/tiled_layer_impl_unittest.cc",
+    "layers/tiled_layer_unittest.cc",
+    "layers/ui_resource_layer_impl_unittest.cc",
+    "layers/ui_resource_layer_unittest.cc",
+    "layers/video_layer_impl_unittest.cc",
+    "output/begin_frame_args_unittest.cc",
+    "output/delegating_renderer_unittest.cc",
+    "output/filter_operations_unittest.cc",
+    "output/gl_renderer_unittest.cc",
+    "output/output_surface_unittest.cc",
+    "output/overlay_unittest.cc",
+    "output/renderer_pixeltest.cc",
+    "output/renderer_unittest.cc",
+    "output/shader_unittest.cc",
+    "output/software_renderer_unittest.cc",
+    "quads/draw_quad_unittest.cc",
+    "quads/list_container_unittest.cc",
+    "quads/render_pass_unittest.cc",
+    "resources/display_item_list_unittest.cc",
+    "resources/layer_quad_unittest.cc",
+    "resources/picture_layer_tiling_set_unittest.cc",
+    "resources/picture_layer_tiling_unittest.cc",
+    "resources/picture_pile_impl_unittest.cc",
+    "resources/picture_pile_unittest.cc",
+    "resources/picture_unittest.cc",
+    "resources/platform_color_unittest.cc",
+    "resources/prioritized_resource_unittest.cc",
+    "resources/resource_provider_unittest.cc",
+    "resources/resource_update_controller_unittest.cc",
+    "resources/scoped_gpu_raster_unittest.cc",
+    "resources/scoped_resource_unittest.cc",
+    "resources/task_graph_runner_unittest.cc",
+    "resources/texture_mailbox_deleter_unittest.cc",
+    "resources/texture_uploader_unittest.cc",
+    "resources/tile_manager_unittest.cc",
+    "resources/tile_priority_unittest.cc",
+    "resources/tile_task_worker_pool_unittest.cc",
+    "resources/video_resource_updater_unittest.cc",
+    "scheduler/begin_frame_source_unittest.cc",
+    "scheduler/delay_based_time_source_unittest.cc",
+    "scheduler/scheduler_state_machine_unittest.cc",
+    "scheduler/scheduler_unittest.cc",
+    "test/layer_tree_json_parser_unittest.cc",
+    "test/test_web_graphics_context_3d_unittest.cc",
+    "trees/blocking_task_runner_unittest.cc",
+    "trees/damage_tracker_unittest.cc",
+    "trees/layer_sorter_unittest.cc",
+    "trees/layer_tree_host_common_unittest.cc",
+    "trees/layer_tree_host_impl_unittest.cc",
+    "trees/layer_tree_host_pixeltest_blending.cc",
+    "trees/layer_tree_host_pixeltest_filters.cc",
+    "trees/layer_tree_host_pixeltest_masks.cc",
+    "trees/layer_tree_host_pixeltest_readback.cc",
+    "trees/layer_tree_host_pixeltest_synchronous.cc",
+    "trees/layer_tree_host_unittest.cc",
+    "trees/layer_tree_host_unittest_animation.cc",
+    "trees/layer_tree_host_unittest_context.cc",
+    "trees/layer_tree_host_unittest_copyrequest.cc",
+    "trees/layer_tree_host_unittest_damage.cc",
+    "trees/layer_tree_host_unittest_delegated.cc",
+    "trees/layer_tree_host_unittest_no_message_loop.cc",
+    "trees/layer_tree_host_unittest_occlusion.cc",
+    "trees/layer_tree_host_unittest_picture.cc",
+    "trees/layer_tree_host_unittest_proxy.cc",
+    "trees/layer_tree_host_unittest_scroll.cc",
+    "trees/layer_tree_host_unittest_video.cc",
+    "trees/layer_tree_impl_unittest.cc",
+    "trees/occlusion_tracker_unittest.cc",
+    "trees/occlusion_unittest.cc",
+    "trees/property_tree_unittest.cc",
+    "trees/tree_synchronizer_unittest.cc",
 
-      # Surfaces test files.
-      "surfaces/surface_aggregator_test_helpers.cc",
-      "surfaces/surface_aggregator_test_helpers.h",
-      "surfaces/surface_aggregator_unittest.cc",
-      "surfaces/surface_unittest.cc",
-      "surfaces/surfaces_pixeltest.cc",
+    # Surfaces test files.
+    "surfaces/surface_aggregator_test_helpers.cc",
+    "surfaces/surface_aggregator_test_helpers.h",
+    "surfaces/surface_aggregator_unittest.cc",
+    "surfaces/surface_unittest.cc",
+    "surfaces/surfaces_pixeltest.cc",
 
-      # Setup.
-      "test/cc_test_suite.cc",
-      "test/run_all_unittests.cc",
-    ]
+    # Setup.
+    "test/cc_test_suite.cc",
+    "test/run_all_unittests.cc",
+  ]
 
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
-    deps = [
-      ":cc",
-      ":test_support",
-      "//base/test:test_support",
-      "//cc/surfaces",
-      "//cc/surfaces:surface_id",
-      "//gpu",
-      "//gpu:test_support",
-      "//gpu/command_buffer/client:gles2_interface",
-      "//gpu/command_buffer/common:gles2_utils",
-      "//media",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//ui/events:events_base",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gfx:test_support",
-      "//ui/gl",
-    ]
-  }
+  deps = [
+    ":cc",
+    ":test_support",
+    "//base/test:test_support",
+    "//cc/surfaces",
+    "//cc/surfaces:surface_id",
+    "//gpu",
+    "//gpu:test_support",
+    "//gpu/command_buffer/client:gles2_interface",
+    "//gpu/command_buffer/common:gles2_utils",
+    "//media",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//ui/events:events_base",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gfx:test_support",
+    "//ui/gl",
+  ]
 }
 
 test("cc_perftests") {
diff --git a/cc/blink/BUILD.gn b/cc/blink/BUILD.gn
index b9f86c0..1769efb 100644
--- a/cc/blink/BUILD.gn
+++ b/cc/blink/BUILD.gn
@@ -72,7 +72,7 @@
 
 # GYP version: //cc/blink/cc_blink_tests.gyp:cc_blink_unittests
 # TODO(GYP): make linking work on the mac.
-if (!is_mac && (!is_win || link_chrome_on_windows)) {
+if (!is_mac) {
   test("cc_blink_unittests") {
     sources = [
       "web_animation_unittest.cc",
diff --git a/cc/debug/debug_rect_history.cc b/cc/debug/debug_rect_history.cc
index cde77653..22a612c 100644
--- a/cc/debug/debug_rect_history.cc
+++ b/cc/debug/debug_rect_history.cc
@@ -163,10 +163,9 @@
 }
 
 void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) {
-  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
-      layer,
-      base::Bind(&DebugRectHistory::SaveTouchEventHandlerRectsCallback,
-                 base::Unretained(this)));
+  LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+    SaveTouchEventHandlerRectsCallback(layer);
+  });
 }
 
 void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) {
@@ -183,10 +182,9 @@
 }
 
 void DebugRectHistory::SaveWheelEventHandlerRects(LayerImpl* layer) {
-  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
-      layer,
-      base::Bind(&DebugRectHistory::SaveWheelEventHandlerRectsCallback,
-                 base::Unretained(this)));
+  LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+    SaveWheelEventHandlerRectsCallback(layer);
+  });
 }
 
 void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) {
@@ -204,10 +202,9 @@
 }
 
 void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) {
-  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
-      layer,
-      base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback,
-                 base::Unretained(this)));
+  LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+    SaveScrollEventHandlerRectsCallback(layer);
+  });
 }
 
 void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) {
@@ -225,10 +222,9 @@
 }
 
 void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) {
-  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
-      layer,
-      base::Bind(&DebugRectHistory::SaveNonFastScrollableRectsCallback,
-                 base::Unretained(this)));
+  LayerTreeHostCommon::CallFunctionForSubtree(layer, [this](LayerImpl* layer) {
+    SaveNonFastScrollableRectsCallback(layer);
+  });
 }
 
 void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
diff --git a/cc/debug/invalidation_benchmark.cc b/cc/debug/invalidation_benchmark.cc
index 1a6a2b8..bb98bcc 100644
--- a/cc/debug/invalidation_benchmark.cc
+++ b/cc/debug/invalidation_benchmark.cc
@@ -64,11 +64,7 @@
 void InvalidationBenchmark::DidUpdateLayers(LayerTreeHost* host) {
   LayerTreeHostCommon::CallFunctionForSubtree(
       host->root_layer(),
-      base::Bind(&InvalidationBenchmark::Run, base::Unretained(this)));
-}
-
-void InvalidationBenchmark::Run(Layer* layer) {
-  layer->RunMicroBenchmark(this);
+      [this](Layer* layer) { layer->RunMicroBenchmark(this); });
 }
 
 void InvalidationBenchmark::RunOnLayer(PictureLayer* layer) {
diff --git a/cc/debug/invalidation_benchmark.h b/cc/debug/invalidation_benchmark.h
index f17fdbd..9423d5d8 100644
--- a/cc/debug/invalidation_benchmark.h
+++ b/cc/debug/invalidation_benchmark.h
@@ -31,7 +31,6 @@
  private:
   enum Mode { FIXED_SIZE, LAYER, VIEWPORT, RANDOM };
 
-  void Run(Layer* layer);
   float LCGRandom();
 
   Mode mode_;
diff --git a/cc/debug/picture_record_benchmark.cc b/cc/debug/picture_record_benchmark.cc
index b1b8188..3ef4708 100644
--- a/cc/debug/picture_record_benchmark.cc
+++ b/cc/debug/picture_record_benchmark.cc
@@ -57,7 +57,7 @@
 void PictureRecordBenchmark::DidUpdateLayers(LayerTreeHost* host) {
   LayerTreeHostCommon::CallFunctionForSubtree(
       host->root_layer(),
-      base::Bind(&PictureRecordBenchmark::Run, base::Unretained(this)));
+      [this](Layer* layer) { layer->RunMicroBenchmark(this); });
 
   scoped_ptr<base::ListValue> results(new base::ListValue());
   for (std::map<std::pair<int, int>, TotalTime>::iterator it = times_.begin();
@@ -83,10 +83,6 @@
   NotifyDone(results.Pass());
 }
 
-void PictureRecordBenchmark::Run(Layer* layer) {
-  layer->RunMicroBenchmark(this);
-}
-
 void PictureRecordBenchmark::RunOnLayer(PictureLayer* layer) {
   ContentLayerClient* painter = layer->client();
   gfx::Size content_bounds = layer->content_bounds();
diff --git a/cc/debug/picture_record_benchmark.h b/cc/debug/picture_record_benchmark.h
index d6330fe1..3710d83b 100644
--- a/cc/debug/picture_record_benchmark.h
+++ b/cc/debug/picture_record_benchmark.h
@@ -27,8 +27,6 @@
   void RunOnLayer(PictureLayer* layer) override;
 
  private:
-  void Run(Layer* layer);
-
   typedef std::pair<base::TimeDelta, unsigned> TotalTime;
   std::map<std::pair<int, int>, TotalTime> times_;
   std::vector<std::pair<int, int>> dimensions_;
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index e56a1e13..e46dcfe 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -65,7 +65,7 @@
   host_ = host;
   LayerTreeHostCommon::CallFunctionForSubtree(
       host->root_layer(),
-      base::Bind(&RasterizeAndRecordBenchmark::Run, base::Unretained(this)));
+      [this](Layer* layer) { layer->RunMicroBenchmark(this); });
 
   DCHECK(!results_.get());
   results_ = make_scoped_ptr(new base::DictionaryValue);
@@ -102,10 +102,6 @@
                  weak_ptr_factory_.GetWeakPtr())));
 }
 
-void RasterizeAndRecordBenchmark::Run(Layer* layer) {
-  layer->RunMicroBenchmark(this);
-}
-
 void RasterizeAndRecordBenchmark::RunOnLayer(PictureLayer* layer) {
   DCHECK(host_);
 
diff --git a/cc/debug/rasterize_and_record_benchmark.h b/cc/debug/rasterize_and_record_benchmark.h
index 30dcde0..bed446d 100644
--- a/cc/debug/rasterize_and_record_benchmark.h
+++ b/cc/debug/rasterize_and_record_benchmark.h
@@ -37,7 +37,6 @@
       scoped_refptr<base::MessageLoopProxy> origin_loop) override;
 
  private:
-  void Run(Layer* layer);
   void RunOnDisplayListLayer(PictureLayer* layer,
                              const gfx::Rect& visible_content_rect);
   void RunOnPictureLayer(PictureLayer* layer,
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 5a9577b..443db8c 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -132,9 +132,10 @@
 void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit(
     LayerTreeHostImpl* host) {
   LayerTreeHostCommon::CallFunctionForSubtree(
-      host->RootLayer(),
-      base::Bind(&RasterizeAndRecordBenchmarkImpl::Run,
-                 base::Unretained(this)));
+      host->RootLayer(), [this](LayerImpl* layer) {
+        rasterize_results_.total_layers++;
+        layer->RunMicroBenchmark(this);
+      });
 
   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
   result->SetDouble("rasterize_time_ms",
@@ -157,11 +158,6 @@
   NotifyDone(result.Pass());
 }
 
-void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) {
-  rasterize_results_.total_layers++;
-  layer->RunMicroBenchmark(this);
-}
-
 void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) {
   rasterize_results_.total_picture_layers++;
   if (!layer->CanHaveTilings()) {
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.h b/cc/debug/rasterize_and_record_benchmark_impl.h
index e9ca27d..ae134ab2 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.h
+++ b/cc/debug/rasterize_and_record_benchmark_impl.h
@@ -31,8 +31,6 @@
   void RunOnLayer(PictureLayerImpl* layer) override;
 
  private:
-  void Run(LayerImpl* layer);
-
   struct RasterizeResults {
     RasterizeResults();
     ~RasterizeResults();
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index abc63fc..92e9c259 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -211,10 +211,6 @@
   proxy_->SetLayerTreeHostClientReady();
 }
 
-static void LayerTreeHostOnOutputSurfaceCreatedCallback(Layer* layer) {
-  layer->OnOutputSurfaceCreated();
-}
-
 void LayerTreeHost::DeleteContentsTexturesOnImplThread(
     ResourceProvider* resource_provider) {
   DCHECK(proxy_->IsImplThread());
@@ -427,7 +423,7 @@
 
   if (root_layer()) {
     LayerTreeHostCommon::CallFunctionForSubtree(
-        root_layer(), base::Bind(&LayerTreeHostOnOutputSurfaceCreatedCallback));
+        root_layer(), [](Layer* layer) { layer->OnOutputSurfaceCreated(); });
   }
 
   client_->DidInitializeOutputSurface();
@@ -873,17 +869,12 @@
   SetNeedsCommit();
 }
 
-static void LayerTreeHostReduceMemoryCallback(Layer* layer) {
-  layer->ReduceMemoryUsage();
-}
-
 void LayerTreeHost::ReduceMemoryUsage() {
   if (!root_layer())
     return;
 
   LayerTreeHostCommon::CallFunctionForSubtree(
-      root_layer(),
-      base::Bind(&LayerTreeHostReduceMemoryCallback));
+      root_layer(), [](Layer* layer) { layer->ReduceMemoryUsage(); });
 }
 
 void LayerTreeHost::SetPrioritiesForSurfaces(size_t surface_memory_bytes) {
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 86666176..6c03511 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -125,10 +125,9 @@
   static bool RenderSurfaceContributesToTarget(LayerType*,
                                                int target_surface_layer_id);
 
-  template <typename LayerType>
-  static void CallFunctionForSubtree(
-      LayerType* root_layer,
-      const base::Callback<void(LayerType* layer)>& function);
+  template <typename LayerType, typename Function>
+  static void CallFunctionForSubtree(LayerType* layer,
+                                     const Function& function);
 
   // Returns a layer with the given id if one exists in the subtree starting
   // from the given root layer (including mask and replica layers).
@@ -205,22 +204,21 @@
   return NULL;
 }
 
-template <typename LayerType>
-void LayerTreeHostCommon::CallFunctionForSubtree(
-    LayerType* root_layer,
-    const base::Callback<void(LayerType* layer)>& function) {
-  function.Run(root_layer);
+template <typename LayerType, typename Function>
+void LayerTreeHostCommon::CallFunctionForSubtree(LayerType* layer,
+                                                 const Function& function) {
+  function(layer);
 
-  if (LayerType* mask_layer = root_layer->mask_layer())
-    function.Run(mask_layer);
-  if (LayerType* replica_layer = root_layer->replica_layer()) {
-    function.Run(replica_layer);
+  if (LayerType* mask_layer = layer->mask_layer())
+    function(mask_layer);
+  if (LayerType* replica_layer = layer->replica_layer()) {
+    function(replica_layer);
     if (LayerType* mask_layer = replica_layer->mask_layer())
-      function.Run(mask_layer);
+      function(mask_layer);
   }
 
-  for (size_t i = 0; i < root_layer->children().size(); ++i) {
-    CallFunctionForSubtree(get_layer_as_raw_ptr(root_layer->children(), i),
+  for (size_t i = 0; i < layer->children().size(); ++i) {
+    CallFunctionForSubtree(get_layer_as_raw_ptr(layer->children(), i),
                            function);
   }
 }
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index eddbc60..c03f7f79 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1453,10 +1453,6 @@
   return metadata;
 }
 
-static void LayerTreeHostImplDidBeginTracingCallback(LayerImpl* layer) {
-  layer->DidBeginTracing();
-}
-
 void LayerTreeHostImpl::DrawLayers(FrameData* frame,
                                    base::TimeTicks frame_begin_time) {
   TRACE_EVENT0("cc", "LayerTreeHostImpl::DrawLayers");
@@ -1506,11 +1502,11 @@
     if (pending_tree_) {
       LayerTreeHostCommon::CallFunctionForSubtree(
           pending_tree_->root_layer(),
-          base::Bind(&LayerTreeHostImplDidBeginTracingCallback));
+          [](LayerImpl* layer) { layer->DidBeginTracing(); });
     }
     LayerTreeHostCommon::CallFunctionForSubtree(
         active_tree_->root_layer(),
-        base::Bind(&LayerTreeHostImplDidBeginTracingCallback));
+        [](LayerImpl* layer) { layer->DidBeginTracing(); });
   }
 
   {
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 62e4cd36..5114fdc 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -121,13 +121,18 @@
 }
 
 void LayerTreeImpl::ReleaseResources() {
-  if (root_layer_)
-    ProcessLayersRecursive(root_layer_.get(), &LayerImpl::ReleaseResources);
+  if (root_layer_) {
+    LayerTreeHostCommon::CallFunctionForSubtree(
+        root_layer_.get(), [](LayerImpl* layer) { layer->ReleaseResources(); });
+  }
 }
 
 void LayerTreeImpl::RecreateResources() {
-  if (root_layer_)
-    ProcessLayersRecursive(root_layer_.get(), &LayerImpl::RecreateResources);
+  if (root_layer_) {
+    LayerTreeHostCommon::CallFunctionForSubtree(
+        root_layer_.get(),
+        [](LayerImpl* layer) { layer->RecreateResources(); });
+  }
 }
 
 void LayerTreeImpl::SetRootLayer(scoped_ptr<LayerImpl> layer) {
@@ -475,10 +480,6 @@
                                            gfx::Rect(layer->content_bounds()));
 }
 
-static void ApplySentScrollDeltasFromAbortedCommitTo(LayerImpl* layer) {
-  layer->ApplySentScrollDeltasFromAbortedCommit();
-}
-
 void LayerTreeImpl::ApplySentScrollAndScaleDeltasFromAbortedCommit() {
   DCHECK(IsActiveTree());
 
@@ -490,7 +491,9 @@
     return;
 
   LayerTreeHostCommon::CallFunctionForSubtree(
-      root_layer(), base::Bind(&ApplySentScrollDeltasFromAbortedCommitTo));
+      root_layer(), [](LayerImpl* layer) {
+        layer->ApplySentScrollDeltasFromAbortedCommit();
+      });
 }
 
 void LayerTreeImpl::SetViewportLayersFromIds(
@@ -748,17 +751,6 @@
           currently_scrolling_layer_ ? currently_scrolling_layer_->id() : 0));
 }
 
-static void DidBecomeActiveRecursive(LayerImpl* layer) {
-  layer->DidBecomeActive();
-  if (layer->mask_layer())
-    layer->mask_layer()->DidBecomeActive();
-  if (layer->replica_layer() && layer->replica_layer()->mask_layer())
-    layer->replica_layer()->mask_layer()->DidBecomeActive();
-
-  for (size_t i = 0; i < layer->children().size(); ++i)
-    DidBecomeActiveRecursive(layer->children()[i]);
-}
-
 void LayerTreeImpl::DidBecomeActive() {
   if (next_activation_forces_redraw_) {
     layer_tree_host_impl_->SetFullRootLayerDamage();
@@ -774,8 +766,10 @@
   // if we were in a good state.
   layer_tree_host_impl_->ResetRequiresHighResToDraw();
 
-  if (root_layer())
-    DidBecomeActiveRecursive(root_layer());
+  if (root_layer()) {
+    LayerTreeHostCommon::CallFunctionForSubtree(
+        root_layer(), [](LayerImpl* layer) { layer->DidBecomeActive(); });
+  }
 
   devtools_instrumentation::DidActivateLayerTree(layer_tree_host_impl_->id(),
                                                  source_frame_number_);
@@ -1267,18 +1261,6 @@
   return layers_with_copy_output_request_;
 }
 
-void LayerTreeImpl::ProcessLayersRecursive(LayerImpl* current,
-                                           void (LayerImpl::*function)()) {
-  DCHECK(current);
-  (current->*function)();
-  if (current->mask_layer())
-    ProcessLayersRecursive(current->mask_layer(), function);
-  if (current->replica_layer())
-    ProcessLayersRecursive(current->replica_layer(), function);
-  for (size_t i = 0; i < current->children().size(); ++i)
-    ProcessLayersRecursive(current->children()[i], function);
-}
-
 template <typename LayerType>
 static inline bool LayerClipsSubtree(LayerType* layer) {
   return layer->masks_to_bounds() || layer->mask_layer();
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index f7b6ee41..3105e6f4 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -335,8 +335,6 @@
       scoped_refptr<SyncedProperty<ScaleGroup>> page_scale_factor,
       scoped_refptr<SyncedTopControls> top_controls_shown_ratio,
       scoped_refptr<SyncedElasticOverscroll> elastic_overscroll);
-  void ProcessLayersRecursive(LayerImpl* current,
-                              void (LayerImpl::*function)());
   float ClampPageScaleFactorToLimits(float page_scale_factor) const;
   void PushPageScaleFactorAndLimits(const float* page_scale_factor,
                                     float min_page_scale_factor,
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 8b0e6a3..b410882 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -12,16 +12,7 @@
   import("//build/config/android/rules.gni")
 }
 
-if (is_win && !link_chrome_on_windows) {
-  # When linking is disabled on Windows, create a dummy Chrome target to
-  # make targets work that depend on Chrome.
-  group("chrome") {
-  }
-  group("main_dll") {
-  }
-}
-
-if (!is_android && (!is_win || link_chrome_on_windows)) {
+if (!is_android) {
   # TODO(GYP) for Windows need to the the reorder-imports step which probably
   # means adding another target and renaming this to chrome_initial like in GYP.
   executable("chrome") {
@@ -153,89 +144,87 @@
   }
 }  # !is_android
 
-if (!is_win || link_chrome_on_windows) {
-  shared_library("main_dll") {
-    configs += [ "//build/config/compiler:wexit_time_destructors" ]
+shared_library("main_dll") {
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
-    deps = [
-      ":browser_dependencies",
-      "//base/allocator",
+  deps = [
+    ":browser_dependencies",
+    "//base/allocator",
+  ]
+  if (is_win) {
+    output_name = "chrome"
+
+    sources = [
+      "//base/win/dllmain.cc",
+      "app/chrome_command_ids.h",
+      "app/chrome_dll.rc",
+      "app/chrome_dll_resource.h",
+      "app/chrome_main.cc",
+      "app/chrome_main_delegate.cc",
+      "app/chrome_main_delegate.h",
+      "app/close_handle_hook_win.cc",
+      "app/close_handle_hook_win.h",
+      "app/delay_load_hook_win.cc",
+      "app/delay_load_hook_win.h",
     ]
-    if (is_win) {
-      output_name = "chrome"
 
-      sources = [
-        "//base/win/dllmain.cc",
-        "app/chrome_command_ids.h",
-        "app/chrome_dll.rc",
-        "app/chrome_dll_resource.h",
-        "app/chrome_main.cc",
-        "app/chrome_main_delegate.cc",
-        "app/chrome_main_delegate.h",
-        "app/close_handle_hook_win.cc",
-        "app/close_handle_hook_win.h",
-        "app/delay_load_hook_win.cc",
-        "app/delay_load_hook_win.h",
-      ]
-
-      deps += [
-        # On Windows, link the dependencies (libraries) that make up actual
-        # Chromium functionality into this .dll.
-        ":chrome_version_resources",
-        "//chrome/app/theme:chrome_unscaled_resources",
-        "//chrome_elf",
-        "//content/app/resources",
-        "//crypto",
-        "//net:net_resources",
-        "//third_party/wtl",
-        "//ui/views",
-      ]
-      if (enable_configuration_policy) {
-        deps += [ "//components/policy" ]
-      }
-      if (current_cpu == "x86") {
-        # Add a dependency to custom import library for user32 delay imports only
-        # in x86 builds.
-        #deps += [ 'chrome_user32_delay_imports' ]  TODO(GYP)
-      }
-
-      # TODO(GYP) incremental linking flags in debug builds
-      #'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
-
-      # TODO(GYP) Lots of VCLinkerTool stuff on Windows.
-
-      # TODO(GYP) chrome_pgo_phase on Windows.
+    deps += [
+      # On Windows, link the dependencies (libraries) that make up actual
+      # Chromium functionality into this .dll.
+      ":chrome_version_resources",
+      "//chrome/app/theme:chrome_unscaled_resources",
+      "//chrome_elf",
+      "//content/app/resources",
+      "//crypto",
+      "//net:net_resources",
+      "//third_party/wtl",
+      "//ui/views",
+    ]
+    if (enable_configuration_policy) {
+      deps += [ "//components/policy" ]
+    }
+    if (current_cpu == "x86") {
+      # Add a dependency to custom import library for user32 delay imports only
+      # in x86 builds.
+      #deps += [ 'chrome_user32_delay_imports' ]  TODO(GYP)
     }
 
-    if (use_aura) {
-      deps += [ "//ui/compositor" ]
-    }
+    # TODO(GYP) incremental linking flags in debug builds
+    #'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
 
-    #TODO(GYP) add chrome_multiple_dll support
-    if (false) {  #chrome_multiple_dll) {
-      defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ]
-      deps += [ "//content/public/app:browser" ]
-    } else {
-      deps += [
-        ":child_dependencies",
-        "//content/public/app:both",
-      ]
-    }
+    # TODO(GYP) Lots of VCLinkerTool stuff on Windows.
 
-    if (cld_version == 0 || cld_version == 2) {
-      deps += [ "//third_party/cld_2" ]
-    }
+    # TODO(GYP) chrome_pgo_phase on Windows.
+  }
 
-    if (is_mac) {
-      #['OS=="mac" and component!="shared_library"', {  TODO(GYP)
-      #  'includes': [ 'chrome_dll_bundle.gypi' ],
-      #}],
-      # TODO(GYP) Lots of other stuff in the OS=="mac" block.
-    }
+  if (use_aura) {
+    deps += [ "//ui/compositor" ]
+  }
 
-    if (enable_plugins) {
-      deps += [ "//pdf" ]
-    }
+  #TODO(GYP) add chrome_multiple_dll support
+  if (false) {  #chrome_multiple_dll) {
+    defines = [ "CHROME_MULTIPLE_DLL_BROWSER" ]
+    deps += [ "//content/public/app:browser" ]
+  } else {
+    deps += [
+      ":child_dependencies",
+      "//content/public/app:both",
+    ]
+  }
+
+  if (cld_version == 0 || cld_version == 2) {
+    deps += [ "//third_party/cld_2" ]
+  }
+
+  if (is_mac) {
+    #['OS=="mac" and component!="shared_library"', {  TODO(GYP)
+    #  'includes': [ 'chrome_dll_bundle.gypi' ],
+    #}],
+    # TODO(GYP) Lots of other stuff in the OS=="mac" block.
+  }
+
+  if (enable_plugins) {
+    deps += [ "//pdf" ]
   }
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index c42c9fd..99950b9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=43
 MINOR=0
-BUILD=2320
+BUILD=2321
 PATCH=0
diff --git a/chrome/android/java/res/layout/fre_choose_account.xml b/chrome/android/java/res/layout/fre_choose_account.xml
index b5bcf65..82468b5c 100644
--- a/chrome/android/java/res/layout/fre_choose_account.xml
+++ b/chrome/android/java/res/layout/fre_choose_account.xml
@@ -93,6 +93,7 @@
         android:layout_gravity="bottom"
         android:orientation="horizontal" >
 
+        <!--suppress ButtonStyle -->
         <Button
             android:id="@+id/negative_button"
             android:layout_width="0dp"
@@ -107,6 +108,7 @@
             android:textColor="@color/light_normal_color"
             android:textSize="@dimen/fre_button_text_size" />
 
+        <!--suppress ButtonStyle -->
         <Button
             android:id="@+id/positive_button"
             android:layout_width="0dp"
diff --git a/chrome/android/java/res/layout/homepage_preferences.xml b/chrome/android/java/res/layout/homepage_preferences.xml
index b5c04a8..23452d9 100644
--- a/chrome/android/java/res/layout/homepage_preferences.xml
+++ b/chrome/android/java/res/layout/homepage_preferences.xml
@@ -42,6 +42,7 @@
         <ImageView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:contentDescription="@null"
             android:src="?android:attr/listDivider"
             android:scaleType="fitXY" />
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
index e9b474b..9eaf0bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/BookmarkUtils.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser;
 
+import android.annotation.TargetApi;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.Intent;
@@ -151,6 +152,7 @@
         return bitmap;
     }
 
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     private static Bitmap getBitmapFromResourceId(Context context, int id, int density) {
         Drawable drawable = null;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
index 316852a..a162c9e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeWebContentsDelegateAndroid.java
@@ -71,4 +71,5 @@
 
     protected static native boolean nativeIsCapturingAudio(WebContents webContents);
     protected static native boolean nativeIsCapturingVideo(WebContents webContents);
+    protected static native boolean nativeHasAudibleAudio(WebContents webContents);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java
index c011a6a..423456f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/LollipopTtsPlatformImpl.java
@@ -4,7 +4,9 @@
 
 package org.chromium.chrome.browser;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.speech.tts.TextToSpeech;
 import android.speech.tts.UtteranceProgressListener;
@@ -12,6 +14,7 @@
 /**
  * Subclass of TtsPlatformImpl for Lollipop to make use of newer APIs.
  */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class LollipopTtsPlatformImpl extends TtsPlatformImpl {
     protected LollipopTtsPlatformImpl(long nativeTtsPlatformImplAndroid, Context context) {
         super(nativeTtsPlatformImplAndroid, context);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java
index ff2e9d5..e4e2d1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/UmaUtils.java
@@ -4,51 +4,9 @@
 
 package org.chromium.chrome.browser;
 
-import org.chromium.base.CalledByNative;
 
 /**
- * Utilities to support startup metrics - Android version.
+ * TODO(yfriedman): Remove this after rolling downstream.
  */
-public class UmaUtils {
-
-    private static long sApplicationStartWallClockMs;
-
-    private static boolean sRunningApplicationStart;
-
-    /**
-     * Record the time at which the activity started. This should be called asap after
-     * the start of the activity's onCreate function.
-     */
-    public static void recordMainEntryPointTime() {
-        // We can't simply pass this down through a JNI call, since the JNI for chrome
-        // isn't initialized until we start the native content browser component, and we
-        // then need the start time in the C++ side before we return to Java. As such we
-        // save it in a static that the C++ can fetch once it has initialized the JNI.
-        sApplicationStartWallClockMs = System.currentTimeMillis();
-    }
-
-    /**
-     * Whether the application is in the early stage since the browser process start. The
-     * "application start" ends right after the last histogram related to browser startup is
-     * recorded. Currently, the very first navigation commit in the lifetime of the process ends the
-     * "application start".
-     * Must only be called on the UI thread.
-     */
-    public static boolean isRunningApplicationStart() {
-        return sRunningApplicationStart;
-    }
-
-    /**
-     * Marks/unmarks the "application start" stage of the browser process lifetime.
-     * Must only be called on the UI thread.
-     */
-    public static void setRunningApplicationStart(boolean isAppStart) {
-        sRunningApplicationStart = isAppStart;
-    }
-
-    @CalledByNative
-    private static long getMainEntryPointTime() {
-        return sApplicationStartWallClockMs;
-    }
-
+public class UmaUtils extends org.chromium.chrome.browser.metrics.UmaUtils {
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index 9b87940..bc1bcf1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.appmenu;
 
 import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.AnimatorSet;
 import android.content.Context;
 import android.content.res.Resources;
@@ -27,6 +28,7 @@
 import android.widget.PopupWindow;
 import android.widget.PopupWindow.OnDismissListener;
 
+import org.chromium.base.AnimationFrameTimeHistogram;
 import org.chromium.base.SysUtils;
 import org.chromium.chrome.R;
 
@@ -53,6 +55,9 @@
     private AppMenuHandler mHandler;
     private int mCurrentScreenRotation = -1;
     private boolean mIsByHardwareButton;
+    private AnimatorSet mMenuItemEnterAnimator;
+    private AnimatorListener mAnimationHistogramRecorder = AnimationFrameTimeHistogram
+            .getAnimatorRecorder("WrenchMenu.OpeningAnimationFrameTimes");
 
     /**
      * Creates and sets up the App Menu.
@@ -140,6 +145,10 @@
                 if (mPopup.getAnchorView() instanceof ImageButton) {
                     ((ImageButton) mPopup.getAnchorView()).setSelected(false);
                 }
+
+                if (mMenuItemEnterAnimator != null) mMenuItemEnterAnimator.cancel();
+
+                mHandler.appMenuDismissed();
                 mHandler.onMenuVisibilityChanged(false);
             }
         });
@@ -299,7 +308,6 @@
      * Dismisses the app menu and cancels the drag-to-scroll if it is taking place.
      */
     void dismiss() {
-        mHandler.appMenuDismissed();
         if (isShowing()) {
             mPopup.dismiss();
         }
@@ -361,7 +369,7 @@
     }
 
     private void runMenuItemEnterAnimations() {
-        AnimatorSet animation = new AnimatorSet();
+        mMenuItemEnterAnimator = new AnimatorSet();
         AnimatorSet.Builder builder = null;
 
         ViewGroup list = mPopup.getListView();
@@ -370,13 +378,14 @@
             Object animatorObject = view.getTag(R.id.menu_item_enter_anim_id);
             if (animatorObject != null) {
                 if (builder == null) {
-                    builder = animation.play((Animator) animatorObject);
+                    builder = mMenuItemEnterAnimator.play((Animator) animatorObject);
                 } else {
                     builder.with((Animator) animatorObject);
                 }
             }
         }
 
-        animation.start();
+        mMenuItemEnterAnimator.addListener(mAnimationHistogramRecorder);
+        mMenuItemEnterAnimator.start();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java
index e6b58dcd..4471c971 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuButtonHelper.java
@@ -9,7 +9,7 @@
 import android.view.View;
 import android.view.View.OnTouchListener;
 
-import org.chromium.chrome.browser.UmaBridge;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 
 /**
  * A helper class for a menu button to decide when to show the app menu and forward touch
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java
index 99d34c3..b41006cc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuDragHelper.java
@@ -18,7 +18,7 @@
 import android.widget.ListView;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.UmaBridge;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 
 import java.util.ArrayList;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
index 7229fc6..10e0ef55 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuHandler.java
@@ -17,7 +17,7 @@
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.UmaBridge;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 
 import java.util.ArrayList;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
index 9bd2b34..6865c439 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java
@@ -12,6 +12,7 @@
 import android.graphics.PorterDuffColorFilter;
 import android.os.Build;
 import android.os.Handler;
+import android.support.v4.view.ViewCompat;
 import android.text.Editable;
 import android.text.TextWatcher;
 import android.view.LayoutInflater;
@@ -101,8 +102,8 @@
                           .setView(v)
                           .setNegativeButton(R.string.cancel, null)
                           .setPositiveButton(R.string.card_unmask_confirm_button, null)
-                          .setOnDismissListener(this)
                           .create();
+        mDialog.setOnDismissListener(this);
 
         mShouldRequestExpirationDate = shouldRequestExpirationDate;
         mThisYear = Calendar.getInstance().get(Calendar.YEAR);
@@ -168,6 +169,7 @@
             mVerificationView.setText("Your card is verified");
             Handler h = new Handler();
             h.postDelayed(new Runnable() {
+                @Override
                 public void run() {
                     dismiss();
                 }
@@ -223,7 +225,7 @@
         mMonthInput.setEnabled(enabled);
         mYearInput.setEnabled(enabled);
         mMainContents.setAlpha(enabled ? 1.0f : 0.15f);
-        mMainContents.setImportantForAccessibility(
+        ViewCompat.setImportantForAccessibility(mMainContents,
                 enabled ? View.IMPORTANT_FOR_ACCESSIBILITY_AUTO
                         : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
         ((ViewGroup) mMainContents).setDescendantFocusability(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java
index 2f5107ca..32d60d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModel.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.enhanced_bookmarks;
 
 import org.chromium.base.ObserverList;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.BookmarksBridge;
 import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
 import org.chromium.chrome.browser.BookmarksBridge.BookmarkModelObserver;
@@ -63,6 +64,12 @@
         this();
     }
 
+    @VisibleForTesting
+    EnhancedBookmarksModel(Profile profile) {
+        mBookmarksBridge = new BookmarksBridge(profile);
+        mEnhancedBookmarksBridge = new EnhancedBookmarksBridge(profile);
+    }
+
     /**
      * Clean up all the bridges. This must be called after done using this class.
      */
@@ -275,7 +282,8 @@
     }
 
     /**
-     * @see EnhancedBookmarksBridge#moveBookmark(BookmarkId, BookmarkId)
+     * Calls {@link EnhancedBookmarksBridge#moveBookmark(BookmarkId, BookmarkId)} in a reversed
+     * order of the list, in order to let the last item appear at the top.
      */
     public void moveBookmarks(List<BookmarkId> bookmarkIds, BookmarkId newParentId) {
         for (int i = bookmarkIds.size() - 1; i >= 0; i--) {
@@ -394,4 +402,12 @@
     public void removeSearchObserver(SearchServiceObserver observer) {
         mEnhancedBookmarksBridge.removeSearchObserver(observer);
     }
+
+    /**
+     * @see BookmarksBridge#loadEmptyPartnerBookmarkShimForTesting()
+     */
+    @VisibleForTesting
+    public void loadEmptyPartnerBookmarkShimForTesting() {
+        mBookmarksBridge.loadEmptyPartnerBookmarkShimForTesting();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
index 77b19ea..2725ec3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AnimationHelper.java
@@ -9,6 +9,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.annotation.TargetApi;
 import android.os.Build;
 import android.view.View;
 import android.view.ViewTreeObserver;
@@ -217,6 +218,7 @@
                 mTargetWrapperView.startTransition();
             }
 
+            @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
             @Override
             public void onAnimationEnd(Animator animation) {
                 mTargetWrapperView.finishTransition();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
index 2f62227..970a51c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBar.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.support.v4.view.ViewCompat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -107,9 +108,9 @@
         }
 
         // Hide uninteresting views from accessibility.
-        ratingView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        ViewCompat.setImportantForAccessibility(ratingView, View.IMPORTANT_FOR_ACCESSIBILITY_NO);
         if (mIconView != null) {
-            mIconView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+            ViewCompat.setImportantForAccessibility(mIconView, View.IMPORTANT_FOR_ACCESSIBILITY_NO);
         }
 
         // Set up clicking on the controls to bring up the app details.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
index 1e94673..d7927eda 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/AsyncInitializationActivity.java
@@ -15,6 +15,8 @@
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 
+import org.chromium.chrome.browser.metrics.MemoryUma;
+
 /**
  * An activity that talks with application and activity level delegates for async initialization.
  */
@@ -30,6 +32,7 @@
     private Bundle mSavedInstanceState;
     private boolean mDestroyed;
     private NativeInitializationController mNativeInitializationController;
+    private MemoryUma mMemoryUma;
 
     public AsyncInitializationActivity() {
         mHandler = new Handler();
@@ -71,6 +74,7 @@
 
     @Override
     public void finishNativeInitialization() {
+        mMemoryUma = new MemoryUma();
         mNativeInitializationController.onNativeInitializationComplete();
     }
 
@@ -146,6 +150,7 @@
     @Override
     public void onStop() {
         super.onStop();
+        if (mMemoryUma != null) mMemoryUma.onStop();
         mNativeInitializationController.onStop();
     }
 
@@ -196,6 +201,19 @@
         return false;
     }
 
+    @Override
+    public void onLowMemory() {
+        super.onLowMemory();
+        if (mMemoryUma != null) mMemoryUma.onLowMemory();
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+        if (mMemoryUma != null) mMemoryUma.onTrimMemory(level);
+    }
+
+
     /**
      * Extending classes should implement this and call {@link Activity#setContentView(int)} in it.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java
new file mode 100644
index 0000000..5deefaa
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/MemoryUma.java
@@ -0,0 +1,89 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.metrics;
+
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_MODERATE;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+
+import android.os.Build;
+import android.os.SystemClock;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Centralizes UMA data collection for Android-specific memory conditions.
+ */
+public class MemoryUma {
+    // AndroidMemoryNotificationBackground defined in tools/metrics/histograms/histograms.xml.
+    private static final int BACKGROUND_TRIM_UI_HIDDEN = 0;
+    private static final int BACKGROUND_TRIM_BACKGROUND = 1;
+    private static final int BACKGROUND_TRIM_MODERATE = 2;
+    private static final int BACKGROUND_TRIM_COMPLETE = 3;
+    private static final int BACKGROUND_MAX = 4;
+
+    // AndroidMemoryNotificationForeground defined in tools/metrics/histograms/histograms.xml.
+    private static final int FOREGROUND_TRIM_MODERATE = 0;
+    private static final int FOREGROUND_TRIM_LOW = 1;
+    private static final int FOREGROUND_TRIM_CRITICAL = 2;
+    private static final int FOREGROUND_LOW = 3;
+    private static final int FOREGROUND_MAX = 4;
+
+    // Timestamp of the last time we received a LowMemory call since Chrome is in foreground.
+    private long mLastLowMemoryMsec = -1;
+
+    public void onStop() {
+        mLastLowMemoryMsec = -1;
+    }
+
+    public void onLowMemory() {
+        memoryNotificationForeground(FOREGROUND_LOW);
+        long now = SystemClock.elapsedRealtime();
+        if (mLastLowMemoryMsec >= 0) {
+            RecordHistogram.recordCustomTimesHistogram("MemoryAndroid.LowMemoryTimeBetween",
+                    now - mLastLowMemoryMsec, 0, TimeUnit.MINUTES.toMillis(10),
+                    TimeUnit.MILLISECONDS, 50);
+        }
+        mLastLowMemoryMsec = now;
+    }
+
+    public void onTrimMemory(int level) {
+        if (level >= TRIM_MEMORY_COMPLETE) {
+            memoryNotificationBackground(BACKGROUND_TRIM_COMPLETE);
+        } else if (level >= TRIM_MEMORY_MODERATE) {
+            memoryNotificationBackground(BACKGROUND_TRIM_MODERATE);
+        } else if (level >= TRIM_MEMORY_BACKGROUND) {
+            memoryNotificationBackground(BACKGROUND_TRIM_BACKGROUND);
+        } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
+            memoryNotificationBackground(BACKGROUND_TRIM_UI_HIDDEN);
+        } else if (level >= TRIM_MEMORY_RUNNING_CRITICAL) {
+            memoryNotificationForeground(FOREGROUND_TRIM_CRITICAL);
+        } else if (level >= TRIM_MEMORY_RUNNING_LOW) {
+            memoryNotificationForeground(FOREGROUND_TRIM_LOW);
+        } else if (level >= TRIM_MEMORY_RUNNING_MODERATE) {
+            memoryNotificationForeground(FOREGROUND_TRIM_MODERATE);
+        }
+    }
+
+    private static void memoryNotificationForeground(int notification) {
+        assert notification >= 0 && notification < FOREGROUND_MAX;
+        // Before Jelly Bean we have only LowMemory foreground notification.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return;
+        RecordHistogram.recordEnumeratedHistogram("MemoryAndroid.NotificationForeground",
+                notification, FOREGROUND_MAX);
+    }
+
+    private static void memoryNotificationBackground(int notification) {
+        assert notification >= 0 && notification < BACKGROUND_MAX;
+        RecordHistogram.recordEnumeratedHistogram("MemoryAndroid.NotificationBackground",
+                notification, BACKGROUND_MAX);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java
rename to chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java
index 48a7f9c..75bad02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/UmaBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser;
+package org.chromium.chrome.browser.metrics;
 
 import org.chromium.chrome.browser.preferences.bandwidth.BandwidthReductionPreferences;
 import org.chromium.chrome.browser.preferences.bandwidth.DataReductionPromoScreen;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
new file mode 100644
index 0000000..e3de19b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java
@@ -0,0 +1,189 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.metrics;
+
+import android.app.Activity;
+import android.content.ComponentCallbacks;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import org.chromium.base.ActivityState;
+import org.chromium.base.ApplicationStatus;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.preferences.privacy.CrashReportingPermissionManager;
+import org.chromium.chrome.browser.preferences.privacy.PrivacyPreferencesManager;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.net.NetworkChangeNotifier;
+
+/**
+ * Mainly sets up session stats for chrome. A session is defined as the duration when the
+ * application is in the foreground.  Also used to communicate information between Chrome
+ * and the framework's MetricService.
+ */
+public class UmaSessionStats implements NetworkChangeNotifier.ConnectionTypeObserver {
+    private static final String SAMSUNG_MULTWINDOW_PACKAGE = "com.sec.feature.multiwindow";
+
+    private static long sNativeUmaSessionStats = 0;
+
+    // TabModelSelector is needed to get the count of open tabs. We want to log the number of open
+    // tabs on every page load.
+    private TabModelSelector mTabModelSelector;
+    private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
+
+    private final Context mContext;
+    private final boolean mIsMultiWindowCapable;
+    private ComponentCallbacks mComponentCallbacks;
+
+    private boolean mKeyboardConnected = false;
+    private final CrashReportingPermissionManager mReportingPermissionManager;
+
+    public UmaSessionStats(Context context) {
+        mContext = context;
+        mIsMultiWindowCapable = context.getPackageManager().hasSystemFeature(
+                SAMSUNG_MULTWINDOW_PACKAGE);
+        mReportingPermissionManager = PrivacyPreferencesManager.getInstance(context);
+    }
+
+    private void recordPageLoadStats(int tabId) {
+        Tab tab = mTabModelSelector.getTabById(tabId);
+        if (tab == null) return;
+        WebContents webContents = tab.getWebContents();
+        boolean isDesktopUserAgent = webContents != null
+                && webContents.getNavigationController().getUseDesktopUserAgent();
+        nativeRecordPageLoaded(isDesktopUserAgent);
+        if (mKeyboardConnected) {
+            nativeRecordPageLoadedWithKeyboard();
+        }
+
+        TabModel regularModel = mTabModelSelector.getModel(false);
+        nativeRecordTabCountPerLoad(getTabCountFromModel(regularModel));
+    }
+
+    private int getTabCountFromModel(TabModel model) {
+        return model == null ? 0 : model.getCount();
+    }
+
+    /**
+     * Starts a new session for logging.
+     * @param tabModelSelector A TabModelSelector instance for recording tab counts on page loads.
+     * If null, UmaSessionStats does not record page loads and tab counts.
+     */
+    public void startNewSession(TabModelSelector tabModelSelector) {
+        ensureNativeInitialized();
+
+        mTabModelSelector = tabModelSelector;
+        if (mTabModelSelector != null) {
+            mComponentCallbacks = new ComponentCallbacks() {
+                @Override
+                public void onLowMemory() {
+                    // Not required
+                }
+
+                @Override
+                public void onConfigurationChanged(Configuration newConfig) {
+                    mKeyboardConnected = newConfig.keyboard != Configuration.KEYBOARD_NOKEYS;
+                }
+            };
+            mContext.registerComponentCallbacks(mComponentCallbacks);
+            mKeyboardConnected = mContext.getResources().getConfiguration()
+                    .keyboard != Configuration.KEYBOARD_NOKEYS;
+            mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelector) {
+                @Override
+                public void onPageLoadFinished(Tab tab) {
+                    recordPageLoadStats(tab.getId());
+                }
+            };
+        }
+
+        nativeUmaResumeSession(sNativeUmaSessionStats);
+        NetworkChangeNotifier.addConnectionTypeObserver(this);
+        updateMetricsServiceState();
+    }
+
+    private static void ensureNativeInitialized() {
+        // Lazily create the native object and the notification handler. These objects are never
+        // destroyed.
+        if (sNativeUmaSessionStats == 0) {
+            sNativeUmaSessionStats = nativeInit();
+        }
+    }
+
+    /**
+     * Logs screen ratio on Samsung MultiWindow devices.
+     */
+    public void logMultiWindowStats(int windowArea, int displayArea, int instanceCount) {
+        if (mIsMultiWindowCapable) {
+            if (displayArea == 0) return;
+            int areaPercent = (windowArea * 100) / displayArea;
+            int safePercent = areaPercent > 0 ? areaPercent : 0;
+            nativeRecordMultiWindowSession(safePercent, instanceCount);
+        }
+    }
+
+    /**
+     * Logs the current session.
+     */
+    public void logAndEndSession() {
+        if (mTabModelSelector != null) {
+            mContext.unregisterComponentCallbacks(mComponentCallbacks);
+            mTabModelSelectorTabObserver.destroy();
+            mTabModelSelector = null;
+        }
+
+        nativeUmaEndSession(sNativeUmaSessionStats);
+        NetworkChangeNotifier.removeConnectionTypeObserver(this);
+    }
+
+    public static void logRendererCrash(Activity activity) {
+        int activityState = ApplicationStatus.getStateForActivity(activity);
+        nativeLogRendererCrash(
+                activityState == ActivityState.PAUSED
+                || activityState == ActivityState.STOPPED
+                || activityState == ActivityState.DESTROYED);
+    }
+
+    /**
+     * Updates the state of the MetricsService to account for the user's preferences.
+     */
+    public void updateMetricsServiceState() {
+        boolean mayRecordStats = !PrivacyPreferencesManager.getInstance(mContext)
+                .isNeverUploadCrashDump();
+        boolean mayUploadStats = mReportingPermissionManager.isUploadPermitted();
+
+        // Re-start the MetricsService with the given parameters.
+        nativeUpdateMetricsServiceState(mayRecordStats, mayUploadStats);
+    }
+
+    @Override
+    public void onConnectionTypeChanged(int connectionType) {
+        updateMetricsServiceState();
+    }
+
+    public static void registerExternalExperiment(int studyId, int experimentId) {
+        nativeRegisterExternalExperiment(studyId, experimentId);
+    }
+
+    public static void registerSyntheticFieldTrial(String trialName, String groupName) {
+        nativeRegisterSyntheticFieldTrial(trialName, groupName);
+    }
+
+    private static native long nativeInit();
+    private native void nativeUpdateMetricsServiceState(boolean mayRecord, boolean mayUpload);
+    private native void nativeUmaResumeSession(long nativeUmaSessionStats);
+    private native void nativeUmaEndSession(long nativeUmaSessionStats);
+    private static native void nativeLogRendererCrash(boolean isPaused);
+    private static native void nativeRegisterExternalExperiment(int studyId,
+                                                                int experimentId);
+    private static native void nativeRegisterSyntheticFieldTrial(
+            String trialName, String groupName);
+    private static native void nativeRecordMultiWindowSession(int areaPercent, int instanceCount);
+    private static native void nativeRecordTabCountPerLoad(int numTabsOpen);
+    private static native void nativeRecordPageLoaded(boolean isDesktopUserAgent);
+    private static native void nativeRecordPageLoadedWithKeyboard();
+
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
new file mode 100644
index 0000000..5dc4d296
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.metrics;
+
+import org.chromium.base.CalledByNative;
+
+/**
+ * Utilities to support startup metrics - Android version.
+ */
+public class UmaUtils {
+
+    private static long sApplicationStartWallClockMs;
+
+    private static boolean sRunningApplicationStart;
+
+    /**
+     * Record the time at which the activity started. This should be called asap after
+     * the start of the activity's onCreate function.
+     */
+    public static void recordMainEntryPointTime() {
+        // We can't simply pass this down through a JNI call, since the JNI for chrome
+        // isn't initialized until we start the native content browser component, and we
+        // then need the start time in the C++ side before we return to Java. As such we
+        // save it in a static that the C++ can fetch once it has initialized the JNI.
+        sApplicationStartWallClockMs = System.currentTimeMillis();
+    }
+
+    /**
+     * Whether the application is in the early stage since the browser process start. The
+     * "application start" ends right after the last histogram related to browser startup is
+     * recorded. Currently, the very first navigation commit in the lifetime of the process ends the
+     * "application start".
+     * Must only be called on the UI thread.
+     */
+    public static boolean isRunningApplicationStart() {
+        return sRunningApplicationStart;
+    }
+
+    /**
+     * Marks/unmarks the "application start" stage of the browser process lifetime.
+     * Must only be called on the UI thread.
+     */
+    public static void setRunningApplicationStart(boolean isAppStart) {
+        sRunningApplicationStart = isAppStart;
+    }
+
+    @CalledByNative
+    private static long getMainEntryPointTime() {
+        return sApplicationStartWallClockMs;
+    }
+
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS
new file mode 100644
index 0000000..845f1d7b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/net/spdyproxy/OWNERS
@@ -0,0 +1 @@
+bengr@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java b/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java
index 4811d20..5603de7a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/nfc/BeamCallback.java
@@ -18,7 +18,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.UmaBridge;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 
 import java.net.MalformedURLException;
 import java.net.URL;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java
index 1eb5516..b84dbdb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPreferences.java
@@ -37,6 +37,8 @@
     private static final String PREF_AUTOFILL_CREDIT_CARDS = "autofill_credit_cards";
     private static final String PREF_AUTOFILL_WALLET = "autofill_wallet";
 
+    ChromeBasePreference mWalletPref;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -57,23 +59,13 @@
             }
         });
 
-        ChromeBasePreference walletPref =
-                (ChromeBasePreference) findPreference(PREF_AUTOFILL_WALLET);
-        if (!PersonalDataManager.isWalletImportFeatureAvailable()) {
-            getPreferenceScreen().removePreference(walletPref);
-            autofillSwitch.setDrawDivider(true);
-        } else {
-            walletPref.setSummary(getResources().getString(
-                    PersonalDataManager.isWalletImportEnabled() ? R.string.text_on
-                                                                : R.string.text_off));
-        }
-
+        mWalletPref = (ChromeBasePreference) findPreference(PREF_AUTOFILL_WALLET);
         setPreferenceCategoryIcons();
     }
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
-        rebuildLists();
+        refreshState();
         return true;
     }
 
@@ -92,9 +84,10 @@
     }
 
     /**
-     * Rebuild all the profile and credit card lists.
+     * Refresh state (profile and credit card lists, preference summaries, etc.).
      */
-    private void rebuildLists() {
+    private void refreshState() {
+        updateSummaries();
         rebuildProfileList();
         rebuildCreditCardList();
     }
@@ -140,6 +133,24 @@
         }
     }
 
+    private void updateSummaries() {
+        ChromeSwitchPreference autofillSwitch =
+                (ChromeSwitchPreference) findPreference(PREF_AUTOFILL_SWITCH);
+        if (!PersonalDataManager.isWalletImportFeatureAvailable()) {
+            getPreferenceScreen().removePreference(mWalletPref);
+            autofillSwitch.setDrawDivider(true);
+        } else {
+            if (getPreferenceScreen().findPreference(PREF_AUTOFILL_WALLET) == null) {
+                getPreferenceScreen().addPreference(mWalletPref);
+            }
+
+            mWalletPref.setSummary(getResources().getString(
+                    PersonalDataManager.isWalletImportEnabled() ? R.string.text_on
+                                                                : R.string.text_off));
+            autofillSwitch.setDrawDivider(false);
+        }
+    }
+
     @Override
     public void onResume() {
         super.onResume();
@@ -147,12 +158,12 @@
         // detect if profiles are added or deleted (GUID list
         // changes), the profile summary (name+addr) might be
         // different.  To be safe, we update all.
-        rebuildLists();
+        refreshState();
     }
 
     @Override
     public void onPersonalDataChanged() {
-        rebuildLists();
+        refreshState();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java
index abe2309..43d89378 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/BandwidthReductionPreferences.java
@@ -16,9 +16,9 @@
 import android.text.format.DateUtils;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.UmaBridge;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
 import org.chromium.chrome.browser.infobar.DataReductionProxyInfoBar;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
 import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java
index 60a379c..a3b3e753 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/bandwidth/DataReductionPromoScreen.java
@@ -19,7 +19,7 @@
 import org.chromium.base.ApplicationStatus;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromiumApplication;
-import org.chromium.chrome.browser.UmaBridge;
+import org.chromium.chrome.browser.metrics.UmaBridge;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
index 3cd23a4..be8e2d6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/AddExceptionPreference.java
@@ -16,14 +16,12 @@
 import android.preference.Preference.OnPreferenceClickListener;
 import android.provider.Settings;
 import android.text.Editable;
-import android.text.Spannable;
-import android.text.SpannableString;
 import android.text.TextWatcher;
-import android.text.style.ForegroundColorSpan;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
 import android.widget.EditText;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import org.chromium.chrome.R;
@@ -36,6 +34,7 @@
 public class AddExceptionPreference extends Preference implements OnPreferenceClickListener {
     // The callback to notify when the user adds a site.
     private SiteAddedCallback mSiteAddedCallback;
+    private int mPrefAccentColor;
 
     /**
      * An interface to implement to get a callback when a site has been added.
@@ -57,20 +56,22 @@
 
         setKey(key);
         Resources resources = getContext().getResources();
+        mPrefAccentColor = resources.getColor(R.color.pref_accent_color);
+
         Drawable plusIcon = resources.getDrawable(R.drawable.plus);
         plusIcon.mutate();
-        plusIcon.setColorFilter(
-                resources.getColor(R.color.pref_accent_color),
-                PorterDuff.Mode.SRC_IN);
+        plusIcon.setColorFilter(mPrefAccentColor, PorterDuff.Mode.SRC_IN);
         setIcon(plusIcon);
 
-        SpannableString titleSpan = new SpannableString(
-                resources.getString(
-                        R.string.website_settings_add_site).toUpperCase());
-        titleSpan.setSpan(new ForegroundColorSpan(
-                resources.getColor(R.color.pref_accent_color)), 0, titleSpan.length(),
-                Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-        setTitle(titleSpan);
+        setTitle(resources.getString(R.string.website_settings_add_site));
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        TextView titleView = (TextView) view.findViewById(android.R.id.title);
+        titleView.setAllCaps(true);
+        titleView.setTextColor(mPrefAccentColor);
     }
 
     @Override
@@ -89,6 +90,7 @@
         final EditText input = (EditText) view.findViewById(R.id.site);
 
         DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
+            @Override
             public void onClick(DialogInterface dialog, int button) {
                 if (button == AlertDialog.BUTTON_POSITIVE) {
                     String hostname = input.getText().toString().trim();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
index 2417954..5a11bae9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/SingleWebsitePreferences.java
@@ -391,8 +391,13 @@
                 new Website.StoredDataClearedCallback() {
                     @Override
                     public void onStoredDataCleared() {
-                        getPreferenceScreen().removePreference(
-                                getPreferenceScreen().findPreference(PREF_CLEAR_DATA));
+                        PreferenceScreen preferenceScreen = getPreferenceScreen();
+                        preferenceScreen.removePreference(
+                                preferenceScreen.findPreference(PREF_CLEAR_DATA));
+                        if (!hasUsagePreferences()) {
+                            preferenceScreen.removePreference(
+                                    preferenceScreen.findPreference(PREF_USAGE));
+                        }
                         popBackIfNoSettings();
                     }
                 });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java
index 2158617..17dab5a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/WebsitePreference.java
@@ -14,7 +14,6 @@
 import android.text.format.Formatter;
 import android.view.View;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import org.chromium.base.annotations.SuppressFBWarnings;
@@ -46,12 +45,9 @@
     // Metrics for favicon processing.
     private static final int FAVICON_CORNER_RADIUS_DP = 2;
     private static final int FAVICON_SIZE_DP = 16;
+    private static final int FAVICON_PADDING_DP = 4;
     private static final int FAVICON_TEXT_SIZE_SP = 10;
     private static final int FAVICON_BACKGROUND_COLOR = 0xff969696;
-    // The minimum width of the preference icon parent field.
-    private static final int FAVICON_PARENT_MINWIDTH_DP = 55;
-    // The padding for the preference icon parent field.
-    private static final int FAVICON_PARENT_PADDING_DP = 12;
 
     WebsitePreference(Context context, Website site, String categoryFilter) {
         super(context);
@@ -61,15 +57,11 @@
         setWidgetLayoutResource(R.layout.website_features);
 
         // To make sure the layout stays stable throughout, we assign a
-        // transparent drawable of the same size as the favicon. This is so that
+        // transparent drawable as the icon initially. This is so that
         // we can fetch the favicon in the background and not have to worry
         // about the title appearing to jump (http://crbug.com/453626) when the
         // favicon becomes available.
-        ColorDrawable drawable = new ColorDrawable(Color.TRANSPARENT);
-        int size = Math.round(FAVICON_SIZE_DP
-                * getContext().getResources().getDisplayMetrics().density);
-        drawable.setBounds(0, 0, size, size);
-        setIcon(drawable);
+        setIcon(new ColorDrawable(Color.TRANSPARENT));
 
         refresh();
     }
@@ -146,8 +138,8 @@
 
         TextView usageText = (TextView) view.findViewById(R.id.usage_text);
         usageText.setVisibility(View.GONE);
-        long totalUsage = mSite.getTotalUsage();
         if (mFilter.showStorageSites(mCategoryFilter)) {
+            long totalUsage = mSite.getTotalUsage();
             if (totalUsage > 0) {
                 usageText.setText(Formatter.formatShortFileSize(getContext(), totalUsage));
                 usageText.setTextSize(TEXT_SIZE_SP);
@@ -181,15 +173,9 @@
             mFaviconFetched = true;
         }
 
-        ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
-        View parent = (View) icon.getParent();
-        if (parent instanceof LinearLayout) {
-            LinearLayout parentLayout = (LinearLayout) parent;
-            int minWidth = Math.round(FAVICON_PARENT_MINWIDTH_DP * density);
-            int padding = Math.round(FAVICON_PARENT_PADDING_DP * density);
-            parentLayout.setMinimumWidth(minWidth);
-            parentLayout.setPadding(padding, 0, padding, 0);
-        }
+        int iconPadding = Math.round(FAVICON_PADDING_DP * density);
+        View iconView = view.findViewById(android.R.id.icon);
+        iconView.setPadding(iconPadding, iconPadding, iconPadding, iconPadding);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java
index 93b3c81..1385f1ad 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ButtonCompat.java
@@ -38,6 +38,7 @@
  * Note: To ensure the button's shadow is fully visible, you may need to set
  * android:clipToPadding="false" on the button's parent view.
  */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class ButtonCompat extends Button {
 
     private static final float PRE_L_PRESSED_BRIGHTNESS = 0.85f;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java
new file mode 100644
index 0000000..c4630fd
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/enhanced_bookmarks/EnhancedBookmarksModelTest.java
@@ -0,0 +1,229 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.enhanced_bookmarks;
+
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.shell.ChromeShellActivity;
+import org.chromium.chrome.shell.ChromeShellTab;
+import org.chromium.chrome.shell.ChromeShellTestBase;
+import org.chromium.components.bookmarks.BookmarkId;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Stack;
+
+/**
+ * Tests for {@link EnhancedBookmarksModel}, the data layer of Enhanced Bookmarks.
+ */
+public class EnhancedBookmarksModelTest extends ChromeShellTestBase{
+
+    private ChromeShellActivity mActivity;
+    private EnhancedBookmarksModel mBookmarksModel;
+    private BookmarkId mMobileNode;
+    private BookmarkId mOtherNode;
+    private BookmarkId mDesktopNode;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mActivity = launchChromeShellWithBlankPage();
+        assertTrue(waitForActiveShellToBeDoneLoading());
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                ChromeShellTab tab = mActivity.getActiveTab();
+                Profile profile = tab.getProfile();
+                mBookmarksModel = new EnhancedBookmarksModel(profile);
+                mBookmarksModel.loadEmptyPartnerBookmarkShimForTesting();
+                mMobileNode = mBookmarksModel.getMobileFolderId();
+                mDesktopNode = mBookmarksModel.getDesktopFolderId();
+                mOtherNode = mBookmarksModel.getOtherFolderId();
+            }
+        });
+    }
+
+    @UiThreadTest
+    @SmallTest
+    @Feature({"Bookmark"})
+    public void testGetAllBookmarkIDsOrderedByCreationDate() throws InterruptedException {
+        BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "a");
+        BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "b");
+
+        Stack<BookmarkId> stack = new Stack<BookmarkId>();
+        stack.push(mBookmarksModel.addBookmark(folderA, 0, "a", "http://www.medium.com"));
+        // If add bookmarks too fast, eventually some bookmarks will have the same timestamp, which
+        // confuses the bookmark model.
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(folderB, 0, "b", "http://aurimas.com"));
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://www.aurimas.com"));
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(mDesktopNode, 0, "d", "http://www.aurimas.org"));
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(mOtherNode, 0, "e", "http://www.google.com"));
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(folderA, 0, "f", "http://www.newt.com"));
+        Thread.sleep(20);
+        stack.push(mBookmarksModel.addBookmark(folderB, 0, "g", "http://kkimlabs.com"));
+
+        List<BookmarkId> bookmarks = mBookmarksModel.getAllBookmarkIDsOrderedByCreationDate();
+        assertEquals(bookmarks.size(), stack.size());
+        for (BookmarkId returnedBookmark : bookmarks) {
+            assertEquals(stack.pop(), returnedBookmark);
+        }
+    }
+
+    @UiThreadTest
+    @SmallTest
+    @Feature({"Bookmark"})
+    public void testBookmarkPropertySetters() {
+        BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "a");
+
+        BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com");
+        BookmarkId bookmarkB = mBookmarksModel.addBookmark(mMobileNode, 0, "a", "http://a.com");
+        BookmarkId bookmarkC = mBookmarksModel.addBookmark(mOtherNode, 0, "a", "http://a.com");
+        BookmarkId bookmarkD = mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com");
+
+        mBookmarksModel.setBookmarkTitle(folderA, "hauri");
+        assertEquals("hauri", mBookmarksModel.getBookmarkTitle(folderA));
+
+        mBookmarksModel.setBookmarkTitle(bookmarkA, "auri");
+        mBookmarksModel.setBookmarkUrl(bookmarkA, "http://auri.org/");
+        mBookmarksModel.setBookmarkDescription(bookmarkA, "auri");
+        verifyBookmark(bookmarkA, "auri", "http://auri.org/", false, mDesktopNode, "auri");
+
+        mBookmarksModel.setBookmarkTitle(bookmarkB, "lauri");
+        mBookmarksModel.setBookmarkUrl(bookmarkB, "http://lauri.org/");
+        mBookmarksModel.setBookmarkDescription(bookmarkB, "lauri");
+        verifyBookmark(bookmarkB, "lauri", "http://lauri.org/", false, mMobileNode, "lauri");
+
+        mBookmarksModel.setBookmarkTitle(bookmarkC, "mauri");
+        mBookmarksModel.setBookmarkUrl(bookmarkC, "http://mauri.org/");
+        mBookmarksModel.setBookmarkDescription(bookmarkC, "mauri");
+        verifyBookmark(bookmarkC, "mauri", "http://mauri.org/", false, mOtherNode, "mauri");
+
+        mBookmarksModel.setBookmarkTitle(bookmarkD, "kauri");
+        mBookmarksModel.setBookmarkUrl(bookmarkD, "http://kauri.org/");
+        mBookmarksModel.setBookmarkDescription(bookmarkD, "kauri");
+        verifyBookmark(bookmarkD, "kauri", "http://kauri.org/", false, folderA, "kauri");
+    }
+
+    @UiThreadTest
+    @SmallTest
+    @Feature({"Bookmark"})
+    public void testMoveBookmarks() {
+        BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com");
+        BookmarkId bookmarkB = mBookmarksModel.addBookmark(mOtherNode, 0, "b", "http://b.com");
+        BookmarkId bookmarkC = mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://c.com");
+        BookmarkId folderA = mBookmarksModel.addFolder(mOtherNode, 0, "fa");
+        BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "fb");
+        BookmarkId folderC = mBookmarksModel.addFolder(mMobileNode, 0, "fc");
+        BookmarkId bookmarkAA = mBookmarksModel.addBookmark(folderA, 0, "aa", "http://aa.com");
+        BookmarkId bookmarkCA = mBookmarksModel.addBookmark(folderC, 0, "ca", "http://ca.com");
+        BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa");
+
+        HashSet<BookmarkId> movedBookmarks = new HashSet<BookmarkId>(6);
+        movedBookmarks.add(bookmarkA);
+        movedBookmarks.add(bookmarkB);
+        movedBookmarks.add(bookmarkC);
+        movedBookmarks.add(folderC);
+        movedBookmarks.add(folderB);
+        movedBookmarks.add(bookmarkAA);
+        mBookmarksModel.moveBookmarks(new ArrayList<BookmarkId>(movedBookmarks), folderAA);
+
+        // Order of the moved bookmarks is not tested.
+        verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderAA, true, true),
+                movedBookmarks);
+    }
+
+    @UiThreadTest
+    @SmallTest
+    @Feature({"Bookmark"})
+    public void testGetChildIDs() {
+        BookmarkId folderA = mBookmarksModel.addFolder(mMobileNode, 0, "fa");
+        HashSet<BookmarkId> expectedChildren = new HashSet<>();
+        expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com"));
+        expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com"));
+        expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com"));
+        expectedChildren.add(mBookmarksModel.addBookmark(folderA, 0, "a", "http://a.com"));
+        BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa");
+        // urls only
+        verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, false, true),
+                expectedChildren);
+        // folders only
+        verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, true, false),
+                new HashSet<BookmarkId>(Arrays.asList(folderAA)));
+        // folders and urls
+        expectedChildren.add(folderAA);
+        verifyBookmarkListNoOrder(mBookmarksModel.getChildIDs(folderA, true, true),
+                expectedChildren);
+    }
+
+    // Moved from BookmarksBridgeTest
+    @UiThreadTest
+    @SmallTest
+    @Feature({"Bookmark"})
+    public void testAddBookmarksAndFolders() {
+        BookmarkId bookmarkA = mBookmarksModel.addBookmark(mDesktopNode, 0, "a", "http://a.com");
+        verifyBookmark(bookmarkA, "a", "http://a.com/", false, mDesktopNode, "");
+
+        BookmarkId bookmarkB = mBookmarksModel.addBookmark(mOtherNode, 0, "b", "http://b.com");
+        verifyBookmark(bookmarkB, "b", "http://b.com/", false, mOtherNode, "");
+
+        BookmarkId bookmarkC = mBookmarksModel.addBookmark(mMobileNode, 0, "c", "http://c.com");
+        verifyBookmark(bookmarkC, "c", "http://c.com/", false, mMobileNode, "");
+
+        BookmarkId folderA = mBookmarksModel.addFolder(mOtherNode, 0, "fa");
+        verifyBookmark(folderA, "fa", null, true, mOtherNode, "");
+
+        BookmarkId folderB = mBookmarksModel.addFolder(mDesktopNode, 0, "fb");
+        verifyBookmark(folderB, "fb", null, true, mDesktopNode, "");
+
+        BookmarkId folderC = mBookmarksModel.addFolder(mMobileNode, 0, "fc");
+        verifyBookmark(folderC, "fc", null, true, mMobileNode, "");
+
+        BookmarkId bookmarkAA = mBookmarksModel.addBookmark(folderA, 0, "aa", "http://aa.com");
+        verifyBookmark(bookmarkAA, "aa", "http://aa.com/", false, folderA, "");
+
+        BookmarkId folderAA = mBookmarksModel.addFolder(folderA, 0, "faa");
+        verifyBookmark(folderAA, "faa", null, true, folderA, "");
+    }
+
+    private void verifyBookmark(BookmarkId idToVerify, String expectedTitle,
+            String expectedUrl, boolean isFolder, BookmarkId expectedParent,
+            String expectedDescription) {
+        assertNotNull(idToVerify);
+        BookmarkItem item = mBookmarksModel.getBookmarkById(idToVerify);
+        assertEquals(expectedTitle, item.getTitle());
+        assertEquals(isFolder, item.isFolder());
+        if (!isFolder) assertEquals(expectedUrl, item.getUrl());
+        assertEquals(expectedParent, item.getParentId());
+        assertEquals(expectedDescription, mBookmarksModel.getBookmarkDescription(idToVerify));
+    }
+
+    /**
+     * Before using this helper method, always make sure @param listToVerify does not contain
+     * duplicates.
+     */
+    private void verifyBookmarkListNoOrder(List<BookmarkId> listToVerify,
+            HashSet<BookmarkId> expectedIds) {
+        HashSet<BookmarkId> expectedIdsCopy = new HashSet<>(expectedIds);
+        assertEquals(expectedIdsCopy.size(), listToVerify.size());
+        for (BookmarkId id : listToVerify) {
+            assertNotNull(id);
+            assertTrue("List contains wrong element: ", expectedIdsCopy.contains(id));
+            expectedIdsCopy.remove(id);
+        }
+        assertTrue("List does not contain some expected bookmarks: ", expectedIdsCopy.isEmpty());
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
index 5201bd10..77169a25 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/notifications/NotificationUIManagerTest.java
@@ -7,6 +7,7 @@
 import android.app.Notification;
 import android.graphics.Bitmap;
 import android.os.Build;
+import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.SparseArray;
 
@@ -34,7 +35,6 @@
 public class NotificationUIManagerTest extends ChromeShellTestBase {
     private static final String NOTIFICATION_TEST_PAGE =
             TestHttpServerClient.getUrl("chrome/test/data/notifications/android_test.html");
-    private static final String PERMISSION_GRANTED = "\"granted\"";
 
     private MockNotificationManagerProxy mMockNotificationManager;
 
@@ -48,7 +48,8 @@
     /**
      * Sets the permission to use Web Notifications for the test HTTP server's origin to |setting|.
      */
-    private void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting) {
+    private void setNotificationContentSettingForCurrentOrigin(final ContentSetting setting)
+            throws InterruptedException, TimeoutException {
         final String origin = getOrigin();
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
@@ -59,6 +60,15 @@
                 pushNotificationInfo.setContentSetting(setting);
             }
         });
+
+        String permission = runJavaScriptCodeInCurrentTab("Notification.permission");
+        if (setting == ContentSetting.ALLOW) {
+            assertEquals("\"granted\"", permission);
+        } else if (setting == ContentSetting.BLOCK) {
+            assertEquals("\"denied\"", permission);
+        } else {
+            assertEquals("\"default\"", permission);
+        }
     }
 
     /**
@@ -133,10 +143,8 @@
     @Feature({"Browser", "Notifications"})
     public void testDefaultNotificationProperties() throws Exception {
         setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
-        assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission"));
 
         Notification notification = showAndGetNotification("MyNotification", "{ body: 'Hello' }");
-        assertNotNull(notification);
 
         // Validate the contents of the notification.
         assertEquals("MyNotification", notification.extras.getString(Notification.EXTRA_TITLE));
@@ -165,10 +173,8 @@
     @Feature({"Browser", "Notifications"})
     public void testShowNotificationWithIcon() throws Exception {
         setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
-        assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission"));
 
         Notification notification = showAndGetNotification("MyNotification", "{icon: 'icon.png'}");
-        assertNotNull(notification);
 
         assertEquals("MyNotification", notification.extras.getString(Notification.EXTRA_TITLE));
         assertNotNull(notification.largeIcon);
@@ -187,10 +193,8 @@
     @Feature({"Browser", "Notifications"})
     public void testShowNotificationWithoutIcon() throws Exception {
         setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
-        assertEquals(PERMISSION_GRANTED, runJavaScriptCodeInCurrentTab("Notification.permission"));
 
         Notification notification = showAndGetNotification("NoIconNotification", "{}");
-        assertNotNull(notification);
 
         assertEquals("NoIconNotification", notification.extras.getString(Notification.EXTRA_TITLE));
         assertNotNull(notification.largeIcon);
@@ -207,4 +211,51 @@
         assertEquals(generatedIcon.getWidth(), notification.largeIcon.getWidth());
         assertEquals(generatedIcon.getHeight(), notification.largeIcon.getHeight());
     }
+
+    /*
+     * Verifies that starting the PendingIntent stored as the notification's content intent will
+     * start up the associated Service Worker, where the JavaScript code will close the notification
+     * by calling event.notification.close().
+     */
+    @LargeTest
+    @Feature({"Browser", "Notifications"})
+    public void testNotificationContentIntentClosesNotification() throws Exception {
+        setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
+
+        Notification notification = showAndGetNotification("MyNotification", "{}");
+
+        // Sending the PendingIntent resembles activating the notification.
+        assertNotNull(notification.contentIntent);
+        notification.contentIntent.send();
+
+        // The Service Worker will close the notification upon receiving the notificationclick
+        // event. This will eventually bubble up to a call to cancel() in the NotificationManager.
+        assertTrue(waitForNotificationManagerMutation());
+
+        SparseArray<Notification> notifications = mMockNotificationManager.getNotifications();
+        assertEquals(0, notifications.size());
+    }
+
+    /**
+     * Verifies that creating a notification with an associated "tag" will cause any previous
+     * notification with the same tag to be dismissed prior to being shown.
+     */
+    @MediumTest
+    @Feature({"Browser", "Notifications"})
+    public void testNotificationTagReplacement() throws Exception {
+        setNotificationContentSettingForCurrentOrigin(ContentSetting.ALLOW);
+
+        Notification notification = showAndGetNotification("MyNotification", "{tag: 'myTag'}");
+
+        // Show the second notification with the same tag. We can't use showAndGetNotification for
+        // this purpose since a second notification would be shown.
+        runJavaScriptCodeInCurrentTab("showNotification('SecondNotification', {tag: 'myTag'});");
+        assertTrue(waitForNotificationManagerMutation());
+
+        // Verify that the notification was successfully replaced.
+        SparseArray<Notification> notifications = mMockNotificationManager.getNotifications();
+        assertEquals(1, notifications.size());
+        assertEquals("SecondNotification",
+                notifications.valueAt(0).extras.getString(Notification.EXTRA_TITLE));
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java
index 9d071cf..9b18925 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/BasePartnerBrowserCustomizationUnitTest.java
@@ -9,6 +9,7 @@
 import android.net.Uri;
 import android.test.AndroidTestCase;
 
+import org.chromium.base.CommandLine;
 import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsDelayedProvider;
 import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsProvider;
 
@@ -50,6 +51,12 @@
     }
 
     @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        CommandLine.init(null);
+    }
+
+    @Override
     public Context getContext() {
         ContextWrapper context = new ContextWrapper(super.getContext()) {
             @Override
diff --git a/chrome/app/android/chrome_main_delegate_android.cc b/chrome/app/android/chrome_main_delegate_android.cc
index e0bd8e4..840b66b 100644
--- a/chrome/app/android/chrome_main_delegate_android.cc
+++ b/chrome/app/android/chrome_main_delegate_android.cc
@@ -8,7 +8,7 @@
 #include "base/trace_event/trace_event.h"
 #include "chrome/browser/android/chrome_jni_registrar.h"
 #include "chrome/browser/android/chrome_startup_flags.h"
-#include "chrome/browser/android/uma_utils.h"
+#include "chrome/browser/android/metrics/uma_utils.h"
 #include "components/startup_metric_utils/startup_metric_utils.h"
 #include "content/public/browser/browser_main_runner.h"
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index a34c349..47742aa 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1985,9 +1985,6 @@
   <message name="IDS_OPTIONS_SETTINGS_STORAGE_DESCRIPTION" desc="The 'Storage' button on the chrome://settings page.">
     Stored data...
   </message>
-  <message name="IDS_OPTIONS_SETTINGS_TIME_SYNCED_EXPLANATION" desc="In the settings tab, the text indicating that the date and time are set automatically.">
-    Date and time are set automatically.
-  </message>
   <message name="IDS_OPTIONS_SETTINGS_SET_TIME_BUTTON" desc="In the settings tab, the prompt on the button to open a dialog to set date and time.">
     Set date and time
   </message>
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 0e02897d..1ade4ba 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6174,12 +6174,6 @@
         <message name="IDS_FLAGS_DISABLE_TOUCH_FEEDBACK_DESCRIPTION" desc="Description for the flag that disables additional visual feedback for touch.">
           Certain UI components will stop displaying visual feedback upon touch interactions.
         </message>
-        <message name="IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_NAME" desc="Title for the flag to enable swipe gestures to close windows while in overview mode.">
-          Swipe to dismiss windows in overview mode.
-        </message>
-        <message name="IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_DESCRIPTION" desc="Description for the flag to enable swipe gestures to close windows while in overview mode.">
-          Enable swipe gesture to dismiss windows in overview mode.
-        </message>
         <message name="IDS_FLAGS_ASH_DISABLE_TEXT_FILTERING_IN_OVERVIEW_MODE_NAME" desc="Title for the flag to disable window filtering in overview mode by inputing text">
           Disable text filtering in Overview Mode.
         </message>
@@ -9389,7 +9383,7 @@
       </message>
 
       <message name="IDS_ERRORPAGES_ERROR_CODE" desc="At the bottom of error pages, a non-internationalized string or numeric code is displayed for debugging purposes">
-        Error code: <ph name="ERROR_NAME">$1<ex>ERR_FILE_NOT_FOUND</ex></ph>
+        <ph name="ERROR_NAME">$1<ex>ERR_FILE_NOT_FOUND</ex></ph>
       </message>
 
       <message name="IDS_ERRORPAGES_DETAILS_TIMED_OUT" desc="The error message displayed when a page takes too long to load.">
@@ -11185,6 +11179,15 @@
       <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_STORAGE_CHECKBOX" desc="Text for checkbox in card unmasking dialog that allows user to store a Wallet card on their local device. If checked, the dialog won't show up again for the given credit card.">
         Don't ask again for this card
       </message>
+      <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN" desc="Error message that encourages the user to try to re-enter their credit card CVC after a previous failed attempt.">
+        There was a problem verifying your card. Check your information and try again.
+      </message>
+      <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT" desc="Error message to show when a credit card cannot be verified and the user isn't allowed to retry.">
+        Chrome was unable to verify your card at this time. Please try again later.
+      </message>
+      <message name="IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK" desc="Error message to show when a credit card cannot be verified because Wallet servers can't be reached.">
+        There was a problem verifying your card. Check your internet connection and try again.
+      </message>
 
       <message name="IDS_APPEARANCE_GROUP_NAME" desc="The title of the appearance group">
         Appearance
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 975c68c..ce8af0fc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -93,6 +93,7 @@
     "//components/enhanced_bookmarks",
     "//components/favicon_base",
     "//components/favicon/core",
+    "//components/feedback",
     "//components/gcm_driver",
     "//components/google/core/browser",
     "//components/handoff",
@@ -582,7 +583,6 @@
                            ".",
                            "//chrome")
     deps += [
-      "//components/feedback",
       "//device/core",
       "//device/usb",
     ]
@@ -603,6 +603,7 @@
     ]
     deps -= [
       "//third_party/libaddressinput",
+      "//components/feedback",
       "//components/storage_monitor",
       "//components/web_modal",
     ]
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 577ad8e..7f41b7f 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -953,14 +953,6 @@
     kOsAll,
     SINGLE_VALUE_TYPE(ash::switches::kAshDebugShortcuts),
   },
-  {
-    "ash-enable-swipe-to-close-in-overview-mode",
-    IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_NAME,
-    IDS_FLAGS_ASH_ENABLE_SWIPE_TO_CLOSE_IN_OVERVIEW_MODE_DESCRIPTION,
-    // TODO(bruthig): Add kOsWin when http://crbug.com/333758 is resolved.
-    kOsCrOS,
-    SINGLE_VALUE_TYPE(ash::switches::kAshEnableSwipeToCloseInOverviewMode),
-  },
   { "ash-enable-touch-view-testing",
     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_NAME,
     IDS_FLAGS_ASH_ENABLE_TOUCH_VIEW_TESTING_DESCRIPTION,
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 62091e0b6..0ff52278 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -32,6 +32,9 @@
 #include "chrome/browser/android/intent_helper.h"
 #include "chrome/browser/android/location_settings_impl.h"
 #include "chrome/browser/android/logo_bridge.h"
+#include "chrome/browser/android/metrics/uma_bridge.h"
+#include "chrome/browser/android/metrics/uma_session_stats.h"
+#include "chrome/browser/android/metrics/uma_utils.h"
 #include "chrome/browser/android/most_visited_sites.h"
 #include "chrome/browser/android/new_tab_page_prefs.h"
 #include "chrome/browser/android/omnibox/answers_image_bridge.h"
@@ -50,8 +53,6 @@
 #include "chrome/browser/android/signin/signin_manager_android.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/tab_state.h"
-#include "chrome/browser/android/uma_bridge.h"
-#include "chrome/browser/android/uma_utils.h"
 #include "chrome/browser/android/url_utilities.h"
 #include "chrome/browser/android/voice_search_tab_helper.h"
 #include "chrome/browser/autofill/android/personal_data_manager_android.h"
@@ -229,6 +230,7 @@
     {"TranslateInfoBarDelegate", RegisterTranslateInfoBarDelegate},
     {"TtsPlatformImpl", TtsPlatformImplAndroid::Register},
     {"UmaBridge", RegisterUmaBridge},
+    {"UmaSessionStats", RegisterUmaSessionStats},
     {"UrlUtilities", RegisterUrlUtilities},
     {"Variations", variations::android::RegisterVariations},
     {"VoiceSearchTabHelper", RegisterVoiceSearchTabHelper},
diff --git a/chrome/browser/android/chrome_web_contents_delegate_android.cc b/chrome/browser/android/chrome_web_contents_delegate_android.cc
index 8194f89d..ecc988d 100644
--- a/chrome/browser/android/chrome_web_contents_delegate_android.cc
+++ b/chrome/browser/android/chrome_web_contents_delegate_android.cc
@@ -371,3 +371,10 @@
   return indicator->IsCapturingVideo(web_contents);
 }
 
+jboolean HasAudibleAudio(JNIEnv* env,
+                         jclass clazz,
+                         jobject java_web_contents) {
+  content::WebContents* web_contents =
+      content::WebContents::FromJavaWebContents(java_web_contents);
+  return web_contents->WasRecentlyAudible();
+}
diff --git a/chrome/browser/android/metrics/OWNERS b/chrome/browser/android/metrics/OWNERS
new file mode 100644
index 0000000..7755f6b
--- /dev/null
+++ b/chrome/browser/android/metrics/OWNERS
@@ -0,0 +1,4 @@
+asvitkine@chromium.org
+dfalcantara@chromium.org
+mariakhomenko@chromium.org
+
diff --git a/chrome/browser/android/uma_bridge.cc b/chrome/browser/android/metrics/uma_bridge.cc
similarity index 97%
rename from chrome/browser/android/uma_bridge.cc
rename to chrome/browser/android/metrics/uma_bridge.cc
index 2b27ee5..9577106 100644
--- a/chrome/browser/android/uma_bridge.cc
+++ b/chrome/browser/android/metrics/uma_bridge.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/uma_bridge.h"
+#include "chrome/browser/android/metrics/uma_bridge.h"
 
 #include <jni.h>
 
diff --git a/chrome/browser/android/uma_bridge.h b/chrome/browser/android/metrics/uma_bridge.h
similarity index 68%
rename from chrome/browser/android/uma_bridge.h
rename to chrome/browser/android/metrics/uma_bridge.h
index c68c841..0badc05d 100644
--- a/chrome/browser/android/uma_bridge.h
+++ b/chrome/browser/android/metrics/uma_bridge.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_
-#define CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_
+#ifndef CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_
 
 #include <jni.h>
 
@@ -16,4 +16,4 @@
 }  // namespace android
 }  // namespace chrome
 
-#endif  // CHROME_BROWSER_ANDROID_UMA_BRIDGE_H_
+#endif  // CHROME_BROWSER_ANDROID_METRICS_UMA_BRIDGE_H_
diff --git a/chrome/browser/android/metrics/uma_session_stats.cc b/chrome/browser/android/metrics/uma_session_stats.cc
new file mode 100644
index 0000000..f4b2981
--- /dev/null
+++ b/chrome/browser/android/metrics/uma_session_stats.cc
@@ -0,0 +1,199 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/metrics/uma_session_stats.h"
+
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
+#include "chrome/browser/metrics/metrics_services_manager.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "components/metrics/metrics_service.h"
+#include "components/variations/metrics_util.h"
+#include "components/variations/variations_associated_data.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/user_metrics.h"
+#include "jni/UmaSessionStats_jni.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::UserMetricsAction;
+
+namespace {
+UmaSessionStats* g_uma_session_stats = NULL;
+}  // namespace
+
+UmaSessionStats::UmaSessionStats()
+    : active_session_count_(0) {
+}
+
+UmaSessionStats::~UmaSessionStats() {
+}
+
+void UmaSessionStats::UmaResumeSession(JNIEnv* env, jobject obj) {
+  DCHECK(g_browser_process);
+
+  if (active_session_count_ == 0) {
+    session_start_time_ = base::TimeTicks::Now();
+
+    // Tell the metrics service that the application resumes.
+    metrics::MetricsService* metrics = g_browser_process->metrics_service();
+    if (metrics) {
+      metrics->OnAppEnterForeground();
+    }
+  }
+  ++active_session_count_;
+}
+
+void UmaSessionStats::UmaEndSession(JNIEnv* env, jobject obj) {
+  --active_session_count_;
+  DCHECK(active_session_count_ >= 0);
+
+  if (active_session_count_ == 0) {
+    base::TimeDelta duration = base::TimeTicks::Now() - session_start_time_;
+    UMA_HISTOGRAM_LONG_TIMES("Session.TotalDuration", duration);
+
+    DCHECK(g_browser_process);
+    // Tell the metrics service it was cleanly shutdown.
+    metrics::MetricsService* metrics = g_browser_process->metrics_service();
+    if (metrics) {
+      metrics->OnAppEnterBackground();
+    }
+  }
+}
+
+// static
+void UmaSessionStats::RegisterSyntheticFieldTrialWithNameHash(
+    uint32_t trial_name_hash,
+    const std::string& group_name) {
+  ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameHash(
+      trial_name_hash, group_name);
+}
+
+// static
+void UmaSessionStats::RegisterSyntheticFieldTrial(
+    const std::string& trial_name,
+    const std::string& group_name) {
+  ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(trial_name,
+                                                            group_name);
+}
+
+// Starts/stops the MetricsService when permissions have changed.
+// There are three possible states:
+// * Logs are being recorded and being uploaded to the server.
+// * Logs are being recorded, but not being uploaded to the server.
+//   This happens when we've got permission to upload on Wi-Fi but we're on a
+//   mobile connection (for example).
+// * Logs are neither being recorded or uploaded.
+static void UpdateMetricsServiceState(JNIEnv* env, jobject obj,
+    jboolean may_record, jboolean may_upload) {
+  metrics::MetricsService* metrics = g_browser_process->metrics_service();
+  DCHECK(metrics);
+
+  if (metrics->recording_active() != may_record) {
+    // This function puts a consent file with the ClientID in the
+    // data directory. The ID is passed to the renderer for crash
+    // reporting when things go wrong.
+    content::BrowserThread::GetBlockingPool()->PostTask(FROM_HERE,
+        base::Bind(
+            base::IgnoreResult(GoogleUpdateSettings::SetCollectStatsConsent),
+            may_record));
+  }
+
+  g_browser_process->GetMetricsServicesManager()->UpdatePermissions(
+      may_record, may_upload);
+}
+
+// Renderer process crashed in the foreground.
+static void LogRendererCrash(JNIEnv* env, jclass clazz, jboolean is_paused) {
+  DCHECK(g_browser_process);
+
+  if (!is_paused) {
+    // Increment the renderer crash count in stability metrics.
+    PrefService* pref = g_browser_process->local_state();
+    DCHECK(pref);
+    int value = pref->GetInteger(prefs::kStabilityRendererCrashCount);
+    pref->SetInteger(prefs::kStabilityRendererCrashCount, value + 1);
+  }
+
+  // Note: When we are paused, any UI metric we increment may not make it to
+  // the disk before we are killed. Treat the count below as a lower bound.
+  content::RecordAction(base::UserMetricsAction("MobileRendererCrashed"));
+}
+
+static void RegisterExternalExperiment(JNIEnv* env,
+                                       jclass clazz,
+                                       jint study_id,
+                                       jint experiment_id) {
+  const std::string group_name_utf8 = base::IntToString(experiment_id);
+
+  variations::ActiveGroupId active_group;
+  active_group.name = static_cast<uint32>(study_id);
+  active_group.group = metrics::HashName(group_name_utf8);
+  variations::AssociateGoogleVariationIDForceHashes(
+      variations::GOOGLE_WEB_PROPERTIES, active_group,
+      static_cast<variations::VariationID>(experiment_id));
+
+  UmaSessionStats::RegisterSyntheticFieldTrialWithNameHash(
+      static_cast<uint32_t>(study_id), group_name_utf8);
+}
+
+static void RegisterSyntheticFieldTrial(JNIEnv* env,
+                                        jclass clazz,
+                                        jstring jtrial_name,
+                                        jstring jgroup_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  std::string group_name(ConvertJavaStringToUTF8(env, jgroup_name));
+  UmaSessionStats::RegisterSyntheticFieldTrial(trial_name, group_name);
+}
+
+static void RecordMultiWindowSession(JNIEnv*, jclass,
+                                     jint area_percent,
+                                     jint instance_count) {
+  UMA_HISTOGRAM_PERCENTAGE("MobileStartup.MobileMultiWindowSession",
+                           area_percent);
+  // Make sure the bucket count is the same as the range.  This currently
+  // expects no more than 10 simultaneous multi window instances.
+  UMA_HISTOGRAM_CUSTOM_COUNTS("MobileStartup.MobileMultiWindowInstances",
+                              instance_count,
+                              1 /* min */,
+                              10 /* max */,
+                              10 /* bucket count */);
+}
+
+static void RecordTabCountPerLoad(JNIEnv*, jclass, jint num_tabs) {
+  // Record how many tabs total are open.
+  UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", num_tabs, 1, 200, 50);
+}
+
+static void RecordPageLoaded(JNIEnv*, jclass, jboolean is_desktop_user_agent) {
+  // Should be called whenever a page has been loaded.
+  content::RecordAction(UserMetricsAction("MobilePageLoaded"));
+  if (is_desktop_user_agent) {
+    content::RecordAction(
+        UserMetricsAction("MobilePageLoadedDesktopUserAgent"));
+  }
+}
+
+static void RecordPageLoadedWithKeyboard(JNIEnv*, jclass) {
+  content::RecordAction(UserMetricsAction("MobilePageLoadedWithKeyboard"));
+}
+
+static jlong Init(JNIEnv* env, jclass obj) {
+  // We should have only one UmaSessionStats instance.
+  DCHECK(!g_uma_session_stats);
+  g_uma_session_stats = new UmaSessionStats();
+  return reinterpret_cast<intptr_t>(g_uma_session_stats);
+}
+
+// Register native methods
+bool RegisterUmaSessionStats(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
diff --git a/chrome/browser/android/metrics/uma_session_stats.h b/chrome/browser/android/metrics/uma_session_stats.h
new file mode 100644
index 0000000..173d342
--- /dev/null
+++ b/chrome/browser/android/metrics/uma_session_stats.h
@@ -0,0 +1,45 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_
+#define CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+class UserActionRateCounter;
+
+// The native part of java UmaSessionStats class.
+class UmaSessionStats {
+ public:
+  UmaSessionStats();
+
+  void UmaResumeSession(JNIEnv* env, jobject obj);
+  void UmaEndSession(JNIEnv* env, jobject obj);
+
+  static void RegisterSyntheticFieldTrialWithNameHash(
+      uint32_t trial_name_hash,
+      const std::string& group_name);
+
+  static void RegisterSyntheticFieldTrial(
+      const std::string& trial_name,
+      const std::string& group_name);
+
+ private:
+  ~UmaSessionStats();
+
+  // Start of the current session, used for UMA.
+  base::TimeTicks session_start_time_;
+  int active_session_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(UmaSessionStats);
+};
+
+// Registers the native methods through jni
+bool RegisterUmaSessionStats(JNIEnv* env);
+
+#endif  // CHROME_BROWSER_ANDROID_METRICS_UMA_SESSION_STATS_H_
diff --git a/chrome/browser/android/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc
similarity index 91%
rename from chrome/browser/android/uma_utils.cc
rename to chrome/browser/android/metrics/uma_utils.cc
index 0e9152d..12d9f18 100644
--- a/chrome/browser/android/uma_utils.cc
+++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/uma_utils.h"
+#include "chrome/browser/android/metrics/uma_utils.h"
 
 #include "jni/UmaUtils_jni.h"
 
diff --git a/chrome/browser/android/uma_utils.h b/chrome/browser/android/metrics/uma_utils.h
similarity index 70%
rename from chrome/browser/android/uma_utils.h
rename to chrome/browser/android/metrics/uma_utils.h
index 0853033..d455b126 100644
--- a/chrome/browser/android/uma_utils.h
+++ b/chrome/browser/android/metrics/uma_utils.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_UMA_UTILS_H_
-#define CHROME_BROWSER_ANDROID_UMA_UTILS_H_
+#ifndef CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_
+#define CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_
 
 #include <jni.h>
 
@@ -18,4 +18,4 @@
 }  // namespace android
 }  // namespace chrome
 
-#endif  // CHROME_BROWSER_ANDROID_UMA_UTILS_H_
+#endif  // CHROME_BROWSER_ANDROID_METRICS_UMA_UTILS_H_
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index 66369ac..e9289de 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -12,7 +12,7 @@
 #include "cc/layers/layer.h"
 #include "chrome/browser/android/chrome_web_contents_delegate_android.h"
 #include "chrome/browser/android/compositor/tab_content_manager.h"
-#include "chrome/browser/android/uma_utils.h"
+#include "chrome/browser/android/metrics/uma_utils.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/chrome_bookmark_client.h"
 #include "chrome/browser/bookmarks/chrome_bookmark_client_factory.h"
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 01feef4d..866f7c0 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -897,7 +897,9 @@
   // already loaded a new one, so the pointer needs to be updated;
   // otherwise we will try to start up a browser window with a pointer
   // to the old profile.
-  if (lastProfile_ && profilePath == lastProfile_->GetPath())
+  // In a browser test, the application is not brought to the front, so
+  // |lastProfile_| might be null.
+  if (!lastProfile_ || profilePath == lastProfile_->GetPath())
     lastProfile_ = g_browser_process->profile_manager()->GetLastUsedProfile();
 
   auto it = profileBookmarkMenuBridgeMap_.find(profilePath);
diff --git a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
index 8f4fb35..561280b 100644
--- a/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
+++ b/chrome/browser/apps/custom_launcher_page_browsertest_views.cc
@@ -20,8 +20,11 @@
 #include "ui/app_list/views/app_list_main_view.h"
 #include "ui/app_list/views/app_list_view.h"
 #include "ui/app_list/views/contents_view.h"
+#include "ui/app_list/views/search_box_view.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/webview/webview.h"
+#include "ui/views/focus/focus_manager.h"
 
 namespace {
 
@@ -383,3 +386,43 @@
   EXPECT_TRUE(model->custom_launcher_page_enabled());
   EXPECT_TRUE(custom_page_view->visible());
 }
+
+IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest,
+                       LauncherPageFocusTraversal) {
+  LoadAndLaunchPlatformApp(kCustomLauncherPagePath, "Launched");
+  app_list::AppListView* app_list_view = GetAppListView();
+  app_list::ContentsView* contents_view =
+      app_list_view->app_list_main_view()->contents_view();
+  app_list::SearchBoxView* search_box_view =
+      app_list_view->app_list_main_view()->search_box_view();
+
+  ASSERT_TRUE(
+      contents_view->IsStateActive(app_list::AppListModel::STATE_START));
+  EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
+            search_box_view->search_box());
+
+  {
+    ExtensionTestMessageListener listener("onPageProgressAt1", false);
+    contents_view->SetActivePage(contents_view->GetPageIndexForState(
+        app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE));
+    listener.WaitUntilSatisfied();
+    EXPECT_TRUE(contents_view->IsStateActive(
+        app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE));
+    EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
+              search_box_view->search_box());
+  }
+  {
+    ExtensionTestMessageListener listener("textfieldFocused", false);
+    app_list_view->GetFocusManager()->AdvanceFocus(false);
+    listener.WaitUntilSatisfied();
+    EXPECT_NE(app_list_view->GetFocusManager()->GetFocusedView(),
+              search_box_view->search_box());
+  }
+  {
+    ExtensionTestMessageListener listener("textfieldBlurred", false);
+    app_list_view->GetFocusManager()->AdvanceFocus(false);
+    listener.WaitUntilSatisfied();
+    EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
+              search_box_view->search_box());
+  }
+}
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc
index 04c96fe..fd1d298 100644
--- a/chrome/browser/apps/ephemeral_app_browsertest.cc
+++ b/chrome/browser/apps/ephemeral_app_browsertest.cc
@@ -23,7 +23,7 @@
 #include "content/public/browser/power_save_blocker.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
-#include "extensions/browser/api/power/power_api_manager.h"
+#include "extensions/browser/api/power/power_api.h"
 #include "extensions/browser/app_sorting.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/extension_prefs.h"
@@ -1028,9 +1028,7 @@
 // chrome.power.releaseKeepAwake() themselves.
 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReleasePowerKeepAwake) {
   PowerSettingsMock power_settings;
-  extensions::PowerApiManager* power_manager =
-      extensions::PowerApiManager::Get(profile());
-  power_manager->SetCreateBlockerFunctionForTesting(
+  extensions::PowerAPI::Get(profile())->SetCreateBlockerFunctionForTesting(
       base::Bind(&PowerSaveBlockerStub::Create, &power_settings));
 
   const Extension* app = InstallAndLaunchEphemeralApp(kPowerTestApp);
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index 455325b..52bcb4d 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -46,16 +46,6 @@
 }
 
 const std::vector<base::FilePath> GetTestFiles() {
-  static const base::FilePath::CharType* const kFilesToSkip[] = {
-    FILE_PATH_LITERAL("bug_459132.html"),
-    FILE_PATH_LITERAL("bug_454366b.html"),
-    FILE_PATH_LITERAL("bug_454366.html"),
-    FILE_PATH_LITERAL("25_checkout_m_llbean.com.html"),
-  };
-  std::set<base::FilePath> set_of_files_to_skip;
-  for (size_t i = 0; i < arraysize(kFilesToSkip); ++i)
-    set_of_files_to_skip.insert(base::FilePath(kFilesToSkip[i]));
-
   base::FilePath dir;
   CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &dir));
   dir = dir.AppendASCII("chrome/test/data/autofill")
@@ -65,8 +55,7 @@
   std::vector<base::FilePath> files;
   for (base::FilePath input_file = input_files.Next(); !input_file.empty();
        input_file = input_files.Next()) {
-    if (!ContainsKey(set_of_files_to_skip, input_file.BaseName()))
-      files.push_back(input_file);
+    files.push_back(input_file);
   }
   std::sort(files.begin(), files.end());
 
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 3af4c61..d0e92847 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -144,18 +144,18 @@
 #include "chrome/browser/metrics/thread_watcher_android.h"
 #else
 #include "chrome/browser/feedback/feedback_profile_observer.h"
-#endif
+#endif  // defined(OS_ANDROID)
 
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 #include "chrome/browser/first_run/upgrade_util_linux.h"
 #include "chrome/browser/sxs_linux.h"
-#endif
+#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/settings/cros_settings_names.h"
-#endif
+#endif  // defined(OS_CHROMEOS)
 
 // TODO(port): several win-only methods have been pulled out of this, but
 // BrowserMain() as a whole needs to be broken apart so that it's usable by
@@ -188,38 +188,38 @@
 
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "chrome/browser/mac/keystone_glue.h"
-#endif
+#endif  // defined(OS_MACOSX)
 
 #if !defined(OS_IOS)
 #include "chrome/browser/ui/app_modal/chrome_javascript_native_dialog_factory.h"
-#endif
+#endif  // !defined(OS_IOS)
 
 #if !defined(DISABLE_NACL)
 #include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
 #include "components/nacl/browser/nacl_process_host.h"
-#endif
+#endif  // !defined(DISABLE_NACL)
 
 #if defined(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/startup_helper.h"
 #include "extensions/browser/extension_protocols.h"
 #include "extensions/components/javascript_dialog_extensions_client/javascript_dialog_extension_client_impl.h"
-#endif
+#endif  // defined(ENABLE_EXTENSIONS)
 
 #if defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD)
 #include "printing/printed_document.h"
-#endif
+#endif  // defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD)
 
 #if defined(ENABLE_RLZ)
 #include "chrome/browser/rlz/rlz.h"
-#endif
+#endif  // defined(ENABLE_RLZ)
 
 #if defined(ENABLE_WEBRTC)
 #include "chrome/browser/media/webrtc_log_util.h"
-#endif
+#endif  // defined(ENABLE_WEBRTC)
 
 #if defined(USE_AURA)
 #include "ui/aura/env.h"
-#endif
+#endif  // defined(USE_AURA)
 
 using content::BrowserThread;
 
@@ -318,7 +318,7 @@
       local_state->SetString(prefs::kApplicationLocale, owner_locale);
     }
   }
-#endif
+#endif  // defined(OS_CHROMEOS)
 
   return local_state;
 }
@@ -379,7 +379,7 @@
       profile = g_browser_process->profile_manager()->GetProfile(
           ProfileManager::GetGuestProfilePath());
   }
-#endif
+#endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID)
   if (profile) {
     UMA_HISTOGRAM_LONG_TIMES(
         "Startup.CreateFirstProfile", base::Time::Now() - start);
@@ -391,7 +391,7 @@
   // user_data_dir.  It is better to CHECK-fail here than it is to
   // silently exit because of missing code in the above test.
   CHECK(profile) << "Cannot get default profile.";
-#endif
+#endif  // !defined(OS_WIN)
 
   return NULL;
 }
@@ -401,7 +401,7 @@
                           SecKeychainCallbackInfo* info, void* context) {
   return noErr;
 }
-#endif
+#endif  // defined(OS_MACOSX)
 
 void RegisterComponentsForUpdate() {
   component_updater::ComponentUpdateService* cus =
@@ -415,7 +415,7 @@
   RegisterPepperFlashComponent(cus);
   RegisterSwiftShaderComponent(cus);
   RegisterWidevineCdmComponent(cus);
-#endif
+#endif  // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
 
 #if !defined(DISABLE_NACL) && !defined(OS_ANDROID)
 #if defined(OS_CHROMEOS)
@@ -423,9 +423,9 @@
   // Chrome4ChromeOS on Linux doesn't contain PNaCl so enable component
   // installer when running on Linux. See crbug.com/422121 for more details.
   if (!base::SysInfo::IsRunningOnChromeOS())
-#endif
+#endif  // defined(OS_CHROMEOS)
     g_browser_process->pnacl_component_installer()->RegisterPnaclComponent(cus);
-#endif
+#endif  // !defined(DISABLE_NACL) && !defined(OS_ANDROID)
 
   // Registration of the CLD Component is a no-op unless the CLD data source has
   // been configured to be the "Component" data source.
@@ -450,13 +450,13 @@
     // 1. Android: Because it currently does not have the EV indicator.
     // 2. Chrome OS: On Chrome OS this registration is delayed until user login.
     RegisterEVWhitelistComponent(cus, path);
-#endif
+#endif  // defined(OS_ANDROID)
   }
 
 #if defined(OS_WIN)
   RegisterSwReporterComponent(cus, g_browser_process->local_state());
   RegisterCAPSComponent(cus);
-#endif
+#endif  // defined(OS_WIN)
 
   cus->Start();
 }
@@ -471,7 +471,7 @@
     browser_watcher::ExitFunnel::RecordSingleEvent(
         chrome::kBrowserExitCodesRegistryPath,
         L"ProcessSingletonIsShuttingDown");
-#endif
+#endif  // defined(OS_WIN)
 
     return false;
   }
@@ -556,13 +556,13 @@
 // localization data files.
 #if defined(OS_WIN)
 const char kMissingLocaleDataTitle[] = "Missing File Error";
-#endif
+#endif  // defined(OS_WIN)
 
 #if defined(OS_WIN)
 // TODO(port) This should be used on Linux Aura as well. http://crbug.com/338969
 const char kMissingLocaleDataMessage[] =
     "Unable to find locale data files. Please reinstall.";
-#endif
+#endif  // defined(OS_WIN)
 
 }  // namespace chrome_browser
 
@@ -702,7 +702,7 @@
   bool is_first_run = false;
 #else
   bool is_first_run = first_run::IsChromeFirstRun();
-#endif
+#endif  // defined(OS_ANDROID)
 
 // CurrentProcessInfo::CreationTime() is currently only implemented on some
 // platforms.
@@ -787,7 +787,7 @@
     // These members must be initialized before exiting this function normally.
     DCHECK(master_prefs_.get());
     DCHECK(browser_creator_.get());
-#endif
+#endif  // !defined(OS_ANDROID)
     for (size_t i = 0; i < chrome_extra_parts_.size(); ++i)
       chrome_extra_parts_[i]->PreCreateThreads();
   }
@@ -800,7 +800,7 @@
   run_message_loop_ = false;
 #if !defined(OS_ANDROID)
   chrome::MaybeShowInvalidUserDataDirWarningDialog();
-#endif
+#endif  // !defined(OS_ANDROID)
   if (!PathService::Get(chrome::DIR_USER_DATA, &user_data_dir_))
     return chrome::RESULT_CODE_MISSING_DATA;
 
@@ -814,7 +814,7 @@
 
   // Cache first run state early.
   first_run::IsChromeFirstRun();
-#endif
+#endif  // !defined(OS_ANDROID)
 
   scoped_refptr<base::SequencedTaskRunner> local_state_task_runner =
       JsonPrefStore::GetTaskRunnerForFile(
@@ -860,7 +860,7 @@
   browser_creator_.reset(new StartupBrowserCreator);
   // TODO(yfriedman): Refactor Android to re-use UMABrowsingActivityObserver
   chrome::UMABrowsingActivityObserver::Init();
-#endif
+#endif  // !defined(OS_ANDROID)
 
 #if !defined(OS_CHROMEOS)
   // Convert active labs into switches. This needs to be done before
@@ -877,7 +877,7 @@
                                         base::CommandLine::ForCurrentProcess(),
                                         about_flags::kAddSentinels);
   }
-#endif
+#endif  // !defined(OS_CHROMEOS)
 
   local_state_->UpdateCommandLinePrefStore(
       new CommandLinePrefStore(base::CommandLine::ForCurrentProcess()));
@@ -982,13 +982,13 @@
           master_prefs_->suppress_default_browser_prompt_for_version);
     }
   }
-#endif
+#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
 
 #if defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX)
   // Set the product channel for crash reports.
   base::debug::SetCrashKeyValue(crash_keys::kChannel,
       chrome::VersionInfo::GetVersionStringModifier());
-#endif
+#endif  // defined(OS_LINUX) || defined(OS_OPENBSD) || defined(OS_MACOSX)
 
   // Initialize tracking synchronizer system.
   tracking_synchronizer_ = new metrics::TrackingSynchronizer();
@@ -1001,13 +1001,13 @@
   // (Note that the callback mask here is empty. I don't want to register for
   // any callbacks, I just want to initialize the mechanism.)
   SecKeychainAddCallback(&KeychainCallback, 0, NULL);
-#endif
+#endif  // defined(OS_MACOSX)
 
 #if defined(OS_CHROMEOS)
   // Must be done after g_browser_process is constructed, before
   // SetupMetricsAndFieldTrials().
   chromeos::CrosSettings::Initialize();
-#endif
+#endif  // defined(OS_CHROMEOS)
 
   // Now the command line has been mutated based on about:flags, we can setup
   // metrics and initialize field trials. The field trials are needed by
@@ -1073,15 +1073,15 @@
         BrowserThread::FILE, FROM_HERE,
         base::Bind(&ProfileManager::CleanUpStaleProfiles, profiles_to_delete));
   }
-#endif  // OS_ANDROID
+#endif  // !defined(OS_ANDROID)
 
 #if defined(ENABLE_EXTENSIONS)
   javascript_dialog_extensions_client::InstallClient();
-#endif
+#endif  // defined(ENABLE_EXTENSIONS)
 
 #if !defined(OS_IOS)
   InstallChromeJavaScriptNativeDialogFactory();
-#endif
+#endif  // !defined(OS_IOS)
 }
 
 void ChromeBrowserMainParts::PostProfileInit() {
@@ -1106,7 +1106,7 @@
 #if !defined(OS_ANDROID)
   // Allow ProcessSingleton to process messages.
   process_singleton_->Unlock();
-#endif
+#endif  // !defined(OS_ANDROID)
 #if defined(ENABLE_WEBRTC)
   // Set up a task to delete old WebRTC log files for all profiles. Use a delay
   // to reduce the impact on startup time.
@@ -1115,18 +1115,19 @@
       FROM_HERE,
       base::Bind(&WebRtcLogUtil::DeleteOldWebRtcLogFilesForAllProfiles),
       base::TimeDelta::FromMinutes(1));
-#endif
+#endif  // defined(ENABLE_WEBRTC)
 }
 
 int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
   TRACE_EVENT0("startup", "ChromeBrowserMainParts::PreMainMessageLoopRunImpl");
   SCOPED_UMA_HISTOGRAM_LONG_TIMER("Startup.PreMainMessageLoopRunImplLongTime");
+  const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
   // Android updates the metrics service dynamically depending on whether the
   // application is in the foreground or not. Do not start here.
 #if !defined(OS_ANDROID)
   // Now that the file thread has been started, start recording.
   StartMetricsRecording();
-#endif
+#endif  // !defined(OS_ANDROID)
 
   if (!base::debug::BeingDebugged()) {
     // Create watchdog thread after creating all other threads because it will
@@ -1161,7 +1162,7 @@
 
   ui::SelectFileDialog::SetFactory(new ChromeSelectFileDialogFactory(
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
-#endif
+#endif  // defined(OS_WIN)
 
   if (parsed_command_line().HasSwitch(switches::kMakeDefaultBrowser)) {
     return ShellIntegration::SetAsDefaultBrowser() ?
@@ -1172,7 +1173,7 @@
 #if defined(USE_AURA)
   // Make sure aura::Env has been initialized.
   CHECK(aura::Env::GetInstance());
-#endif
+#endif  // defined(USE_AURA)
 
   // Android doesn't support extensions and doesn't implement ProcessSingleton.
 #if !defined(OS_ANDROID)
@@ -1203,9 +1204,11 @@
 
       case ProcessSingleton::PROCESS_NOTIFIED:
 #if defined(OS_POSIX) && !defined(OS_MACOSX)
+        // On POSIX systems, print a message notifying the process is running.
         printf("%s\n", base::SysWideToNativeMB(base::UTF16ToWide(
             l10n_util::GetStringUTF16(IDS_USED_EXISTING_BROWSER))).c_str());
-#endif
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
+
         // Having a differentiated return type for testing allows for tests to
         // verify proper handling of some switches. When not testing, stick to
         // the standard Unix convention of returning zero when things went as
@@ -1293,6 +1296,12 @@
   metrics::MetricsService::SetExecutionPhase(
       metrics::MetricsService::CREATE_PROFILE,
       g_browser_process->local_state());
+
+  UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep1Time",
+                      base::TimeTicks::Now() - start_time_step1);
+
+  // This step is costly and is already measured in Startup.CreateFirstProfile
+  // and more directly Profile.CreateAndInitializeProfile.
   profile_ = CreatePrimaryProfile(parameters(),
                                   user_data_dir_,
                                   parsed_command_line());
@@ -1300,6 +1309,7 @@
     return content::RESULT_CODE_NORMAL_EXIT;
 
 #if !defined(OS_ANDROID)
+  const base::TimeTicks start_time_step2 = base::TimeTicks::Now();
   // The first run sentinel must be created after the process singleton was
   // grabbed and no early return paths were otherwise hit above.
   first_run::CreateSentinelIfNeeded();
@@ -1309,7 +1319,7 @@
   // Autoload any profiles which are running background apps.
   // TODO(rlp): Do this on a separate thread. See http://crbug.com/99075.
   browser_process_->profile_manager()->AutoloadProfiles();
-#endif
+#endif  // defined(ENABLE_BACKGROUND)
   // Post-profile init ---------------------------------------------------------
 
   TranslateService::Initialize();
@@ -1325,7 +1335,7 @@
   NaClBrowserDelegateImpl* delegate =
       new NaClBrowserDelegateImpl(browser_process_->profile_manager());
   nacl::NaClBrowser::SetDelegate(delegate);
-#endif
+#endif  // !defined(DISABLE_NACL)
 
   // TODO(stevenjb): Move WIN and MACOSX specific code to appropriate Parts.
   // (requires supporting early exit).
@@ -1389,7 +1399,7 @@
         base::Bind(&NetworkProfileBubble::CheckNetworkProfile,
                    profile_->GetPath()));
   }
-#endif  // OS_WIN
+#endif  // defined(OS_WIN)
 
 #if defined(ENABLE_RLZ) && !defined(OS_CHROMEOS)
   // Init the RLZ library. This just binds the dll and schedules a task on the
@@ -1446,7 +1456,7 @@
         parsed_command_line().GetSwitchValuePath(switches::kDebugPrint);
     printing::PrintedDocument::set_debug_dump_path(path);
   }
-#endif
+#endif  // defined(ENABLE_PRINT_PREVIEW) && !defined(OFFICIAL_BUILD)
 
   HandleTestParameters(parsed_command_line());
   browser_process_->metrics_service()->RecordBreakpadHasDebugger(
@@ -1471,7 +1481,7 @@
 #if !defined(OS_ANDROID)
   // Start watching for a hang.
   browser_process_->metrics_service()->LogNeedForCleanShutdown();
-#endif
+#endif  // !defined(OS_ANDROID)
 
 #if defined(ENABLE_PRINT_PREVIEW)
   // Create the instance of the cloud print proxy service so that it can launch
@@ -1481,7 +1491,7 @@
   // BrowserContextKeyedServiceFactory::ServiceIsCreatedWithBrowserContext()
   // instead?
   CloudPrintProxyServiceFactory::GetForProfile(profile_);
-#endif
+#endif  // defined(ENABLE_PRINT_PREVIEW)
 
   // Start watching all browser threads for responsiveness.
   metrics::MetricsService::SetExecutionPhase(
@@ -1491,14 +1501,14 @@
 
 #if defined(OS_ANDROID)
   ThreadWatcherAndroid::RegisterApplicationStatusListener();
-#endif
+#endif  // defined(OS_ANDROID)
 
 #if !defined(DISABLE_NACL)
   BrowserThread::PostTask(
       BrowserThread::IO,
       FROM_HERE,
       base::Bind(nacl::NaClProcessHost::EarlyStartup));
-#endif
+#endif  // !defined(DISABLE_NACL)
 
   // Make sure initial prefs are recorded
   PrefMetricsService::Factory::GetForProfile(profile_);
@@ -1544,17 +1554,24 @@
 #else
   std::vector<Profile*> last_opened_profiles =
       g_browser_process->profile_manager()->GetLastOpenedProfiles();
-#endif
+#endif  // defined(OS_CHROMEOS)
 
-  if (browser_creator_->Start(parsed_command_line(), base::FilePath(),
-                              profile_, last_opened_profiles)) {
+  UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep2Time",
+                      base::TimeTicks::Now() - start_time_step2);
+
+  // This step is costly and is already measured in
+  // Startup.StartupBrowserCreator_Start.
+  bool started = browser_creator_->Start(
+      parsed_command_line(), base::FilePath(), profile_, last_opened_profiles);
+  const base::TimeTicks start_time_step3 = base::TimeTicks::Now();
+  if (started) {
 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
     // Initialize autoupdate timer. Timer callback costs basically nothing
     // when browser is not in persistent mode, so it's OK to let it ride on
     // the main thread. This needs to be done here because we don't want
     // to start the timer when Chrome is run inside a test harness.
     browser_process_->StartAutoupdateTimer();
-#endif
+#endif  // defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
 
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
     // On Linux, the running exe will be updated if an upgrade becomes
@@ -1562,7 +1579,7 @@
     // modified time of the exe, so we can compare to determine if there is
     // an upgrade while the browser is kept alive by a persistent extension.
     upgrade_util::SaveLastModifiedTimeOfExe();
-#endif
+#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
 
     // Record now as the last successful chrome start.
     GoogleUpdateSettings::SetLastRunTime();
@@ -1572,7 +1589,7 @@
     // because Start() will add things to it while creating the main window.
     if (parameters().autorelease_pool)
       parameters().autorelease_pool->Recycle();
-#endif
+#endif  // defined(OS_MACOSX)
 
     base::TimeDelta delay = base::TimeTicks::Now() - browser_open_start;
     UMA_HISTOGRAM_LONG_TIMES_100("Startup.BrowserOpenTabs", delay);
@@ -1589,7 +1606,7 @@
 
 #if defined(OS_WIN)
         variations_service->StartGoogleUpdateRegistrySync();
-#endif
+#endif  // defined(OS_WIN)
       }
 
       translate::TranslateDownloadManager::RequestLanguageList(
@@ -1605,7 +1622,7 @@
 #if !defined(OS_LINUX) || defined(OS_CHROMEOS)  // http://crbug.com/426393
   if (g_browser_process->metrics_service()->reporting_active())
     content::StartPowerUsageMonitor();
-#endif
+#endif  // !defined(OS_LINUX) || defined(OS_CHROMEOS)
 
   process_power_collector_.reset(new ProcessPowerCollector);
   process_power_collector_->Initialize();
@@ -1621,11 +1638,17 @@
 #if defined(OS_ANDROID)
   // We never run the C++ main loop on Android, since the UI thread message
   // loop is controlled by the OS, so this is as close as we can get to
-  // the start of the main loop
+  // the start of the main loop.
   if (result_code_ <= 0) {
     RecordBrowserStartupTime();
   }
-#endif
+#endif  // defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+  UMA_HISTOGRAM_TIMES("Startup.PreMainMessageLoopRunImplStep3Time",
+                      base::TimeTicks::Now() - start_time_step3);
+#endif  // !defined(OS_ANDROID)
+
   return result_code_;
 }
 
@@ -1658,7 +1681,7 @@
   run_loop.Run();
 
   return true;
-#endif
+#endif  // defined(OS_ANDROID)
 }
 
 void ChromeBrowserMainParts::PostMainMessageLoopRun() {
@@ -1701,7 +1724,7 @@
 
   restart_last_session_ = browser_shutdown::ShutdownPreThreadsStop();
   browser_process_->StartTearDown();
-#endif
+#endif  // defined(OS_ANDROID)
 }
 
 void ChromeBrowserMainParts::PostDestroyThreads() {
@@ -1728,8 +1751,8 @@
 
 #if defined(OS_CHROMEOS)
   chromeos::CrosSettings::Shutdown();
-#endif
-#endif
+#endif  // defined(OS_CHROMEOS)
+#endif  // defined(OS_ANDROID)
 }
 
 // Public members:
diff --git a/chrome/browser/chromeos/device/input_service_proxy.cc b/chrome/browser/chromeos/device/input_service_proxy.cc
index 861ef6c9..3d27ab1 100644
--- a/chrome/browser/chromeos/device/input_service_proxy.cc
+++ b/chrome/browser/chromeos/device/input_service_proxy.cc
@@ -15,6 +15,9 @@
 
 namespace chromeos {
 
+// static
+BrowserThread::ID InputServiceProxy::thread_identifier_ = BrowserThread::FILE;
+
 class InputServiceProxy::ServiceObserver : public InputServiceLinux::Observer {
  public:
   ServiceObserver() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); }
@@ -73,7 +76,7 @@
 
  private:
   bool CalledOnValidThread() const {
-    return BrowserThread::CurrentlyOn(BrowserThread::FILE);
+    return BrowserThread::CurrentlyOn(InputServiceProxy::thread_identifier_);
   }
 
   base::WeakPtr<InputServiceProxy> proxy_;
@@ -82,10 +85,12 @@
 };
 
 InputServiceProxy::InputServiceProxy()
-    : service_observer_(new ServiceObserver()), weak_factory_(this) {
+    : service_observer_(new ServiceObserver()),
+      task_runner_(BrowserThread::GetMessageLoopProxyForThread(
+          thread_identifier_)),
+      weak_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  BrowserThread::PostTask(
-      BrowserThread::FILE,
+  task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&InputServiceProxy::ServiceObserver::Initialize,
                  base::Unretained(service_observer_.get()),
@@ -94,8 +99,7 @@
 
 InputServiceProxy::~InputServiceProxy() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  BrowserThread::PostTask(
-      BrowserThread::FILE,
+  task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&InputServiceProxy::ServiceObserver::Shutdown,
                  base::Unretained(service_observer_.release())));
@@ -104,7 +108,7 @@
 // static
 void InputServiceProxy::WarmUp() {
   content::BrowserThread::PostTask(
-      content::BrowserThread::FILE,
+      thread_identifier_,
       FROM_HERE,
       base::Bind(base::IgnoreResult(&InputServiceLinux::GetInstance)));
 }
@@ -123,8 +127,8 @@
 
 void InputServiceProxy::GetDevices(const GetDevicesCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE,
+  base::PostTaskAndReplyWithResult(
+      task_runner_.get(),
       FROM_HERE,
       base::Bind(&InputServiceProxy::ServiceObserver::GetDevices,
                  base::Unretained(service_observer_.get())),
@@ -134,8 +138,7 @@
 void InputServiceProxy::GetDeviceInfo(const std::string& id,
                                       const GetDeviceInfoCallback& callback) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  BrowserThread::PostTask(
-      BrowserThread::FILE,
+  task_runner_->PostTask(
       FROM_HERE,
       base::Bind(&InputServiceProxy::ServiceObserver::GetDeviceInfo,
                  base::Unretained(service_observer_.release()),
@@ -143,6 +146,11 @@
                  callback));
 }
 
+// static
+void InputServiceProxy::SetThreadIdForTesting(BrowserThread::ID thread_id) {
+  InputServiceProxy::thread_identifier_ = thread_id;
+}
+
 void InputServiceProxy::OnDeviceAdded(
     const InputServiceLinux::InputDeviceInfo& info) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/chromeos/device/input_service_proxy.h b/chrome/browser/chromeos/device/input_service_proxy.h
index e41196f..44a0a63 100644
--- a/chrome/browser/chromeos/device/input_service_proxy.h
+++ b/chrome/browser/chromeos/device/input_service_proxy.h
@@ -11,7 +11,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "base/task_runner.h"
 #include "base/threading/thread_checker.h"
+#include "content/public/browser/browser_thread.h"
 #include "device/hid/input_service_linux.h"
 
 namespace chromeos {
@@ -47,7 +49,12 @@
   void GetDeviceInfo(const std::string& id,
                      const GetDeviceInfoCallback& callback);
 
+  // Should be called once before any InputServiceProxy instance is created.
+  static void SetThreadIdForTesting(content::BrowserThread::ID thread_id);
+
  private:
+  static content::BrowserThread::ID thread_identifier_;
+
   class ServiceObserver;
 
   void OnDeviceAdded(const device::InputServiceLinux::InputDeviceInfo& info);
@@ -58,6 +65,8 @@
 
   base::ThreadChecker thread_checker_;
 
+  scoped_refptr<base::TaskRunner> task_runner_;
+
   base::WeakPtrFactory<InputServiceProxy> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(InputServiceProxy);
diff --git a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
index c96dff0..65206db6b 100644
--- a/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
+++ b/chrome/browser/chromeos/extensions/file_system_provider/file_system_provider_apitest.cc
@@ -56,7 +56,7 @@
       << message_;
 }
 
-IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, DISABLED_BigFile) {
+IN_PROC_BROWSER_TEST_F(FileSystemProviderApiTest, BigFile) {
   ASSERT_TRUE(RunPlatformAppTestWithFlags("file_system_provider/big_file",
                                           kFlagLoadAsComponent))
       << message_;
diff --git a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
index 45890d0..41effc9c 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_jstest.cc
@@ -124,9 +124,9 @@
       "foreground/js/metadata/metadata_cache_set_unittest.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(FileManagerJsTest, NewMetadataProvider) {
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MultiMetadataProvider) {
   RunTest(base::FilePath(FILE_PATH_LITERAL(
-      "foreground/js/metadata/new_metadata_provider_unittest.html")));
+      "foreground/js/metadata/multi_metadata_provider_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ListThumbnailLoader) {
@@ -149,9 +149,9 @@
       "foreground/js/metadata/content_metadata_provider_unittest.html")));
 }
 
-IN_PROC_BROWSER_TEST_F(FileManagerJsTest, FileSystemMetadata) {
+IN_PROC_BROWSER_TEST_F(FileManagerJsTest, MetadataModel) {
   RunTest(base::FilePath(FILE_PATH_LITERAL(
-      "foreground/js/metadata/file_system_metadata_unittest.html")));
+      "foreground/js/metadata/metadata_model_unittest.html")));
 }
 
 IN_PROC_BROWSER_TEST_F(FileManagerJsTest, ThumbnailModel) {
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index d747f2a..7a10b51 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -90,6 +90,7 @@
     ::switches::kDisablePanelFitting,
     ::switches::kDisableSeccompFilterSandbox,
     ::switches::kDisableSetuidSandbox,
+    ::switches::kDisableSurfaces,
     ::switches::kDisableTextBlobs,
     ::switches::kDisableThreadedGpuRasterization,
     ::switches::kDisableThreadedScrolling,
diff --git a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc
deleted file mode 100644
index 4b21f533..0000000
--- a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 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/login/default_pinned_apps_field_trial.h"
-
-#include "base/basictypes.h"
-#include "base/prefs/pref_registry_simple.h"
-#include "base/prefs/pref_service.h"
-
-namespace chromeos {
-namespace default_pinned_apps_field_trial {
-
-namespace {
-
-// Name of a local state pref to store the list of users that participate
-// the experiment.
-const char kExperimentUsers[] = "DefaultPinnedAppsExperimentUsers";
-
-}  // namespace
-
-void RegisterPrefs(PrefRegistrySimple* registry) {
-  registry->RegisterListPref(kExperimentUsers);
-}
-
-void MigratePrefs(PrefService* local_state) {
-  // TODO(xiyuan): Remove everything in M34.
-  local_state->ClearPref(kExperimentUsers);
-}
-
-}  // namespace default_pinned_apps_field_trial
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h b/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h
deleted file mode 100644
index 5a1c6aa..0000000
--- a/chrome/browser/chromeos/login/default_pinned_apps_field_trial.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2013 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_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_
-#define CHROME_BROWSER_CHROMEOS_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_
-
-#include <string>
-
-namespace base {
-class ListValue;
-}
-
-class PrefRegistrySimple;
-class PrefService;
-
-namespace chromeos {
-namespace default_pinned_apps_field_trial {
-
-// Registers a local state that keeps track of users in experiment.
-void RegisterPrefs(PrefRegistrySimple* registry);
-
-// Migrate by removing the old local state.
-void MigratePrefs(PrefService* local_state);
-
-}  // namespace default_pinned_apps_field_trial
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_DEFAULT_PINNED_APPS_FIELD_TRIAL_H_
diff --git a/chrome/browser/chromeos/login/hid_detection_browsertest.cc b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
new file mode 100644
index 0000000..ebb23d20
--- /dev/null
+++ b/chrome/browser/chromeos/login/hid_detection_browsertest.cc
@@ -0,0 +1,124 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
+#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
+#include "chrome/browser/chromeos/login/ui/oobe_display.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/bluetooth/bluetooth_adapter_factory.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/hid/fake_input_service_linux.h"
+#include "device/hid/input_service_linux.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using content::BrowserThread;
+using device::InputServiceLinux;
+using testing::_;
+
+using InputDeviceInfo = InputServiceLinux::InputDeviceInfo;
+
+namespace {
+
+void SetUpBluetoothMock(
+    scoped_refptr<
+        testing::NiceMock<device::MockBluetoothAdapter> > mock_adapter,
+    bool is_present) {
+  device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
+
+  EXPECT_CALL(*mock_adapter, IsPresent())
+      .WillRepeatedly(testing::Return(is_present));
+
+  EXPECT_CALL(*mock_adapter, IsPowered())
+      .WillRepeatedly(testing::Return(true));
+  EXPECT_CALL(*mock_adapter, GetDevices()).WillRepeatedly(
+      testing::Return(device::BluetoothAdapter::ConstDeviceList()));
+}
+
+}  // namespace
+
+namespace chromeos {
+
+class HidDetectionTest : public OobeBaseTest {
+ public:
+  typedef device::InputServiceLinux::InputDeviceInfo InputDeviceInfo;
+
+  HidDetectionTest() : weak_ptr_factory_(this) {
+    InputServiceProxy::SetThreadIdForTesting(content::BrowserThread::UI);
+    HidDetectionTest::InitInputService();
+  }
+
+  ~HidDetectionTest() override {}
+
+  void InitInputService() {
+    input_service_linux_.reset(new device::FakeInputServiceLinux);
+    InputServiceLinux::SetForTesting(input_service_linux_.get());
+  }
+
+  void SetUpOnMainThread() override {
+    OobeBaseTest::SetUpOnMainThread();
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    OobeBaseTest::SetUpInProcessBrowserTestFixture();
+
+    mock_adapter_ = new testing::NiceMock<device::MockBluetoothAdapter>();
+    SetUpBluetoothMock(mock_adapter_, true);
+  }
+
+  void AddUsbMouse(const std::string& mouse_id) {
+    InputDeviceInfo mouse;
+    mouse.id = mouse_id;
+    mouse.subsystem = InputDeviceInfo::SUBSYSTEM_INPUT;
+    mouse.type = InputDeviceInfo::TYPE_USB;
+    mouse.is_mouse = true;
+    LOG(ERROR) << input_service_linux_.get();
+    input_service_linux_->AddDeviceForTesting(mouse);
+  }
+
+  void AddUsbKeyboard(const std::string& keyboard_id) {
+    InputDeviceInfo keyboard;
+    keyboard.id = keyboard_id;
+    keyboard.subsystem = InputDeviceInfo::SUBSYSTEM_INPUT;
+    keyboard.type = InputDeviceInfo::TYPE_USB;
+    keyboard.is_keyboard = true;
+    input_service_linux_->AddDeviceForTesting(keyboard);
+  }
+
+ private:
+  scoped_refptr<
+      testing::NiceMock<device::MockBluetoothAdapter> > mock_adapter_;
+
+  scoped_ptr<device::FakeInputServiceLinux> input_service_linux_;
+
+  base::WeakPtrFactory<HidDetectionTest> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(HidDetectionTest);
+};
+
+class HidDetectionSkipTest : public HidDetectionTest {
+ public:
+  HidDetectionSkipTest() {
+    AddUsbMouse("mouse");
+    AddUsbKeyboard("keyboard");
+  }
+
+  void SetUpOnMainThread() override {
+    HidDetectionTest::SetUpOnMainThread();
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(HidDetectionTest, NoDevicesConnected) {
+  OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_HID_DETECTION).Wait();
+}
+
+IN_PROC_BROWSER_TEST_F(HidDetectionSkipTest, BothDevicesPreConnected) {
+  OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_NETWORK).Wait();
+
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 20a9d98..ef44c39 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -307,6 +307,8 @@
           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
   wallpaper_loader_ = new UserImageLoader(ImageDecoder::ROBUST_JPEG_CODEC,
                                           task_runner_);
+
+  user_manager::UserManager::Get()->AddSessionStateObserver(this);
 }
 
 WallpaperManager::~WallpaperManager() {
@@ -314,6 +316,8 @@
   // http://crbug.com/171694
   DCHECK(!show_user_name_on_signin_subscription_);
 
+  user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
+
   ClearObsoleteWallpaperPrefs();
   weak_factory_.InvalidateWeakPtrs();
 }
@@ -966,6 +970,10 @@
   return loading_.size();
 }
 
+void WallpaperManager::UserChangedChildStatus(user_manager::User* user) {
+  SetUserWallpaperNow(user->email());
+}
+
 void WallpaperManager::OnDefaultWallpaperDecoded(
     const base::FilePath& path,
     const wallpaper::WallpaperLayout layout,
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
index 14eec18..536d752d 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -21,6 +21,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_image/user_image.h"
+#include "components/user_manager/user_manager.h"
 #include "components/wallpaper/wallpaper_layout.h"
 #include "components/wallpaper/wallpaper_manager_base.h"
 #include "content/public/browser/notification_observer.h"
@@ -30,7 +31,9 @@
 
 namespace chromeos {
 
-class WallpaperManager : public wallpaper::WallpaperManagerBase {
+class WallpaperManager :
+    public wallpaper::WallpaperManagerBase,
+    public user_manager::UserManager::UserSessionStateObserver {
  public:
   class PendingWallpaper;
 
@@ -115,6 +118,9 @@
   // Returns queue size.
   size_t GetPendingListSizeForTesting() const override;
 
+  // Overridden from user_manager::UserManager::UserSessionStateObserver:
+  void UserChangedChildStatus(user_manager::User* user) override;
+
  private:
   friend class TestApi;
   friend class WallpaperManagerBrowserTest;
diff --git a/chrome/browser/chromeos/policy/power_policy_browsertest.cc b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
index 37b89884..4345ab3 100644
--- a/chrome/browser/chromeos/policy/power_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/power_policy_browsertest.cc
@@ -49,7 +49,7 @@
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/test/test_utils.h"
-#include "extensions/browser/api/power/power_api_manager.h"
+#include "extensions/browser/api/power/power_api.h"
 #include "extensions/common/api/power.h"
 #include "policy/proto/device_management_backend.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -482,8 +482,8 @@
 
   // Pretend an extension grabs a screen wake lock.
   const char kExtensionId[] = "abcdefghijklmnopabcdefghijlkmnop";
-  extensions::PowerApiManager::Get(browser()->profile())->AddRequest(
-      kExtensionId, extensions::core_api::power::LEVEL_DISPLAY);
+  extensions::PowerAPI::Get(browser()->profile())
+      ->AddRequest(kExtensionId, extensions::core_api::power::LEVEL_DISPLAY);
   base::RunLoop().RunUntilIdle();
 
   // Check that the lock is in effect (ignoring ac_idle_action,
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index b7f0f9d..a517f18b 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -857,6 +857,8 @@
   if (target_url.SchemeIs(content::kChromeDevToolsScheme) &&
       target_url.path().rfind("toolbox.html") != std::string::npos) {
     CHECK(can_dock_);
+    if (toolbox_web_contents_)
+      delete toolbox_web_contents_;
     toolbox_web_contents_ = new_contents;
   }
 }
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc
index 5c249cd..c94b842 100644
--- a/chrome/browser/download/download_ui_controller.cc
+++ b/chrome/browser/download/download_ui_controller.cc
@@ -7,7 +7,6 @@
 #include "base/callback.h"
 #include "base/stl_util.h"
 #include "chrome/browser/download/download_item_model.h"
-#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/web_contents.h"
@@ -17,6 +16,8 @@
 #include "content/public/browser/android/download_controller_android.h"
 #else
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/host_desktop.h"
 #endif
 
 namespace {
diff --git a/chrome/browser/errorpage_browsertest.cc b/chrome/browser/errorpage_browsertest.cc
index 6c4708a..2ae8dbe 100644
--- a/chrome/browser/errorpage_browsertest.cc
+++ b/chrome/browser/errorpage_browsertest.cc
@@ -941,7 +941,7 @@
   EXPECT_EQ(2, interceptor()->requests());
 
   ToggleHelpBox(browser());
-  EXPECT_TRUE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET));
+  EXPECT_TRUE(IsDisplayingText(browser(), "error.page.auto.reload"));
 
   content::WebContents* web_contents =
     browser()->tab_strip_model()->GetActiveWebContents();
@@ -949,7 +949,7 @@
   web_contents->GetMainFrame()->ExecuteJavaScript(
       base::ASCIIToUTF16("document.getElementById('reload-button').click();"));
   nav_observer.Wait();
-  EXPECT_FALSE(IsDisplayingNetError(browser(), net::ERR_CONNECTION_RESET));
+  EXPECT_FALSE(IsDisplayingText(browser(), "error.page.auto.reload"));
 }
 
 // Interceptor that fails all requests with net::ERR_ADDRESS_UNREACHABLE.
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 337f58e1f..f2e9ac6f 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -96,6 +96,10 @@
     "Cannot modify the extension by policy.";
 const char kRequiresUserGestureError[] =
     "This action requires a user gesture.";
+const char kCouldNotShowSelectFileDialogError[] =
+    "Could not show a file chooser.";
+const char kFileSelectionCanceled[] =
+    "File selection was canceled.";
 
 const char kUnpackedAppsFolder[] = "apps_target";
 
@@ -867,67 +871,59 @@
 
 DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
 
-bool DeveloperPrivateLoadUnpackedFunction::RunAsync() {
-  base::string16 select_title =
-      l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
+ExtensionFunction::ResponseAction DeveloperPrivateLoadUnpackedFunction::Run() {
+  if (!ShowPicker(
+           ui::SelectFileDialog::SELECT_FOLDER,
+           l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY),
+           ui::SelectFileDialog::FileTypeInfo(),
+           0 /* file_type_index */)) {
+    return RespondNow(Error(kCouldNotShowSelectFileDialogError));
+  }
 
-  // Balanced in FileSelected / FileSelectionCanceled.
-  AddRef();
-  bool result = ShowPicker(
-      ui::SelectFileDialog::SELECT_FOLDER,
-      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
-      select_title,
-      ui::SelectFileDialog::FileTypeInfo(),
-      0);
-  return result;
+  AddRef();  // Balanced in FileSelected / FileSelectionCanceled.
+  return RespondLater();
 }
 
 void DeveloperPrivateLoadUnpackedFunction::FileSelected(
     const base::FilePath& path) {
-  ExtensionService* service = GetExtensionService(GetProfile());
-  UnpackedInstaller::Create(service)->Load(path);
-  DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path);
-  SendResponse(true);
-  Release();
+  UnpackedInstaller::Create(GetExtensionService(browser_context()))->Load(path);
+  DeveloperPrivateAPI::Get(browser_context())->SetLastUnpackedDirectory(path);
+  // TODO(devlin): Shouldn't we wait until the extension is loaded?
+  Respond(NoArguments());
+  Release();  // Balanced in Run().
 }
 
 void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
-  SendResponse(false);
-  Release();
+  // This isn't really an error, but we should keep it like this for
+  // backward compatability.
+  Respond(Error(kFileSelectionCanceled));
+  Release();  // Balanced in Run().
 }
 
 bool DeveloperPrivateChooseEntryFunction::ShowPicker(
     ui::SelectFileDialog::Type picker_type,
-    const base::FilePath& last_directory,
     const base::string16& select_title,
     const ui::SelectFileDialog::FileTypeInfo& info,
     int file_type_index) {
-  AppWindowRegistry* registry = AppWindowRegistry::Get(GetProfile());
-  DCHECK(registry);
-  AppWindow* app_window =
-      registry->GetAppWindowForRenderViewHost(render_view_host());
-  if (!app_window) {
+  content::WebContents* web_contents = GetSenderWebContents();
+  if (!web_contents)
     return false;
-  }
 
   // The entry picker will hold a reference to this function instance,
   // and subsequent sending of the function response) until the user has
   // selected a file or cancelled the picker. At that point, the picker will
   // delete itself.
   new EntryPicker(this,
-                  app_window->web_contents(),
+                  web_contents,
                   picker_type,
-                  last_directory,
+                  DeveloperPrivateAPI::Get(browser_context())->
+                      GetLastUnpackedDirectory(),
                   select_title,
                   info,
                   file_type_index);
   return true;
 }
 
-bool DeveloperPrivateChooseEntryFunction::RunAsync() {
-  return false;
-}
-
 DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
 
 void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
@@ -937,9 +933,8 @@
   response.message = base::UTF16ToUTF8(
       PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
   response.status = developer::PACK_STATUS_SUCCESS;
-  results_ = developer::PackDirectory::Results::Create(response);
-  SendResponse(true);
-  Release();
+  Respond(OneArgument(response.ToValue().release()));
+  Release();  // Balanced in Run().
 }
 
 void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
@@ -955,15 +950,14 @@
   } else {
     response.status = developer::PACK_STATUS_ERROR;
   }
-  results_ = developer::PackDirectory::Results::Create(response);
-  SendResponse(true);
-  Release();
+  Respond(OneArgument(response.ToValue().release()));
+  Release();  // Balanced in Run().
 }
 
-bool DeveloperPrivatePackDirectoryFunction::RunAsync() {
+ExtensionFunction::ResponseAction DeveloperPrivatePackDirectoryFunction::Run() {
   scoped_ptr<PackDirectory::Params> params(
       PackDirectory::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
+  EXTENSION_FUNCTION_VALIDATE(params);
 
   int flags = params->flags ? *params->flags : 0;
   item_path_str_ = params->path;
@@ -972,7 +966,6 @@
 
   base::FilePath root_directory =
       base::FilePath::FromUTF8Unsafe(item_path_str_);
-
   base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_);
 
   developer::PackDirectoryResponse response;
@@ -985,33 +978,29 @@
           IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
 
     response.status = developer::PACK_STATUS_ERROR;
-    results_ = developer::PackDirectory::Results::Create(response);
-    SendResponse(true);
-    return true;
+    return RespondNow(OneArgument(response.ToValue().release()));
   }
 
   if (!key_path_str_.empty() && key_file.empty()) {
     response.message = l10n_util::GetStringUTF8(
         IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
     response.status = developer::PACK_STATUS_ERROR;
-    results_ = developer::PackDirectory::Results::Create(response);
-    SendResponse(true);
-    return true;
+    return RespondNow(OneArgument(response.ToValue().release()));
   }
 
-  // Balanced in OnPackSuccess / OnPackFailure.
-  AddRef();
+  AddRef();  // Balanced in OnPackSuccess / OnPackFailure.
 
+  // TODO(devlin): Why is PackExtensionJob ref-counted?
   pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
   pack_job_->Start();
-  return true;
+  return RespondLater();
 }
 
-DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
-{}
+DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction() {
+}
 
-DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
-{}
+DeveloperPrivatePackDirectoryFunction::
+~DeveloperPrivatePackDirectoryFunction() {}
 
 DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
 
@@ -1246,16 +1235,16 @@
 DeveloperPrivateLoadDirectoryFunction::~DeveloperPrivateLoadDirectoryFunction()
     {}
 
-bool DeveloperPrivateChoosePathFunction::RunAsync() {
+ExtensionFunction::ResponseAction DeveloperPrivateChoosePathFunction::Run() {
   scoped_ptr<developer::ChoosePath::Params> params(
       developer::ChoosePath::Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
+  EXTENSION_FUNCTION_VALIDATE(params);
 
   ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
   ui::SelectFileDialog::FileTypeInfo info;
-  if (params->select_type == developer::SELECT_TYPE_FILE) {
+
+  if (params->select_type == developer::SELECT_TYPE_FILE)
     type = ui::SelectFileDialog::SELECT_OPEN_FILE;
-  }
   base::string16 select_title;
 
   int file_type_index = 0;
@@ -1264,8 +1253,8 @@
   } else if (params->file_type == developer::FILE_TYPE_PEM) {
     select_title = l10n_util::GetStringUTF16(
         IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
-    info.extensions.push_back(std::vector<base::FilePath::StringType>());
-    info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
+    info.extensions.push_back(std::vector<base::FilePath::StringType>(
+        1, FILE_PATH_LITERAL("pem")));
     info.extension_description_overrides.push_back(
         l10n_util::GetStringUTF16(
             IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
@@ -1275,26 +1264,28 @@
     NOTREACHED();
   }
 
-  // Balanced by FileSelected / FileSelectionCanceled.
-  AddRef();
-  bool result = ShowPicker(
-      type,
-      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
-      select_title,
-      info,
-      file_type_index);
-  return result;
+  if (!ShowPicker(
+           type,
+           select_title,
+           info,
+           file_type_index)) {
+    return RespondNow(Error(kCouldNotShowSelectFileDialogError));
+  }
+
+  AddRef();  // Balanced by FileSelected / FileSelectionCanceled.
+  return RespondLater();
 }
 
 void DeveloperPrivateChoosePathFunction::FileSelected(
     const base::FilePath& path) {
-  SetResult(new base::StringValue(base::UTF16ToUTF8(path.LossyDisplayName())));
-  SendResponse(true);
+  Respond(OneArgument(new base::StringValue(path.LossyDisplayName())));
   Release();
 }
 
 void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
-  SendResponse(false);
+  // This isn't really an error, but we should keep it like this for
+  // backward compatability.
+  Respond(Error(kFileSelectionCanceled));
   Release();
 }
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 2164d14..be0c25e 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -296,20 +296,14 @@
   std::string extension_id_;
 };
 
-class DeveloperPrivateChooseEntryFunction : public ChromeAsyncExtensionFunction,
+class DeveloperPrivateChooseEntryFunction : public UIThreadExtensionFunction,
                                             public EntryPickerClient {
  protected:
   ~DeveloperPrivateChooseEntryFunction() override;
-  bool RunAsync() override;
   bool ShowPicker(ui::SelectFileDialog::Type picker_type,
-                  const base::FilePath& last_directory,
                   const base::string16& select_title,
                   const ui::SelectFileDialog::FileTypeInfo& info,
                   int file_type_index);
-
-  // EntryPickerClient functions.
-  void FileSelected(const base::FilePath& path) override = 0;
-  void FileSelectionCanceled() override = 0;
 };
 
 
@@ -321,9 +315,9 @@
 
  protected:
   ~DeveloperPrivateLoadUnpackedFunction() override;
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
-  // EntryPickerCLient implementation.
+  // EntryPickerClient:
   void FileSelected(const base::FilePath& path) override;
   void FileSelectionCanceled() override;
 };
@@ -336,15 +330,15 @@
 
  protected:
   ~DeveloperPrivateChoosePathFunction() override;
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
-  // EntryPickerClient functions.
+  // EntryPickerClient:
   void FileSelected(const base::FilePath& path) override;
   void FileSelectionCanceled() override;
 };
 
 class DeveloperPrivatePackDirectoryFunction
-    : public ChromeAsyncExtensionFunction,
+    : public DeveloperPrivateAPIFunction,
       public PackExtensionJob::Client {
 
  public:
@@ -361,7 +355,7 @@
 
  protected:
   ~DeveloperPrivatePackDirectoryFunction() override;
-  bool RunAsync() override;
+  ResponseAction Run() override;
 
  private:
   scoped_refptr<PackExtensionJob> pack_job_;
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index 59bac37..43b9f20 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/host_desktop.h"
+#include "chrome/common/extensions/api/developer_private.h"
 #include "chrome/test/base/test_browser_window.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -43,6 +44,11 @@
   void TestExtensionPrefSetting(
       bool (*has_pref)(const std::string&, content::BrowserContext*));
 
+  testing::AssertionResult TestPackExtensionFunction(
+      const base::ListValue& args,
+      api::developer_private::PackStatus expected_status,
+      int expected_flags);
+
   Browser* browser() { return browser_.get(); }
 
  private:
@@ -134,6 +140,37 @@
   EXPECT_FALSE(has_pref(extension_id, profile()));
 }
 
+testing::AssertionResult DeveloperPrivateApiUnitTest::TestPackExtensionFunction(
+    const base::ListValue& args,
+    api::developer_private::PackStatus expected_status,
+    int expected_flags) {
+  scoped_refptr<UIThreadExtensionFunction> function(
+      new api::DeveloperPrivatePackDirectoryFunction());
+  if (!RunFunction(function, args))
+    return testing::AssertionFailure() << "Could not run function.";
+
+  // Extract the result. We don't have to test this here, since it's verified as
+  // part of the general extension api system.
+  const base::Value* response_value = nullptr;
+  CHECK(function->GetResultList()->Get(0u, &response_value));
+  scoped_ptr<api::developer_private::PackDirectoryResponse> response =
+      api::developer_private::PackDirectoryResponse::FromValue(*response_value);
+  CHECK(response);
+
+  if (response->status != expected_status) {
+    return testing::AssertionFailure() << "Expected status: " <<
+        expected_status << ", found status: " << response->status <<
+        ", message: " << response->message;
+  }
+
+  if (response->override_flags != expected_flags) {
+    return testing::AssertionFailure() << "Expected flags: " <<
+        expected_flags << ", found flags: " << response->override_flags;
+  }
+
+  return testing::AssertionSuccess();
+}
+
 void DeveloperPrivateApiUnitTest::SetUp() {
   ExtensionServiceTestBase::SetUp();
   InitializeEmptyExtensionService();
@@ -183,4 +220,48 @@
       &util::AllowFileAccess);
 }
 
+// Test developerPrivate.packDirectory.
+TEST_F(DeveloperPrivateApiUnitTest, DeveloperPrivatePackFunction) {
+  ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT);
+
+  base::FilePath root_path = data_dir().AppendASCII("good_unpacked");
+  base::FilePath crx_path = data_dir().AppendASCII("good_unpacked.crx");
+  base::FilePath pem_path = data_dir().AppendASCII("good_unpacked.pem");
+
+  // First, test a directory that should pack properly.
+  base::ListValue pack_args;
+  pack_args.AppendString(root_path.AsUTF8Unsafe());
+  EXPECT_TRUE(TestPackExtensionFunction(
+      pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0));
+
+  // Should have created crx file and pem file.
+  EXPECT_TRUE(base::PathExists(crx_path));
+  EXPECT_TRUE(base::PathExists(pem_path));
+
+  // Deliberately don't cleanup the files, and append the pem path.
+  pack_args.AppendString(pem_path.AsUTF8Unsafe());
+
+  // Try to pack again - we should get a warning abot overwriting the crx.
+  EXPECT_TRUE(TestPackExtensionFunction(
+      pack_args,
+      api::developer_private::PACK_STATUS_WARNING,
+      ExtensionCreator::kOverwriteCRX));
+
+  // Try to pack again, with the overwrite flag; this should succeed.
+  pack_args.AppendInteger(ExtensionCreator::kOverwriteCRX);
+  EXPECT_TRUE(TestPackExtensionFunction(
+      pack_args, api::developer_private::PACK_STATUS_SUCCESS, 0));
+
+  // Try to pack a final time when omitting (an existing) pem file. We should
+  // get an error.
+  base::DeleteFile(crx_path, false);
+  EXPECT_TRUE(pack_args.Remove(1u, nullptr));  // Remove the pem key argument.
+  EXPECT_TRUE(pack_args.Remove(1u, nullptr));  // Remove the flags argument.
+  EXPECT_TRUE(TestPackExtensionFunction(
+      pack_args, api::developer_private::PACK_STATUS_ERROR, 0));
+
+  base::DeleteFile(crx_path, false);
+  base::DeleteFile(pem_path, false);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/developer_private/entry_picker.cc b/chrome/browser/extensions/api/developer_private/entry_picker.cc
index 9e3b6af..9baaa1e 100644
--- a/chrome/browser/extensions/api/developer_private/entry_picker.cc
+++ b/chrome/browser/extensions/api/developer_private/entry_picker.cc
@@ -79,6 +79,13 @@
   delete this;
 }
 
+void EntryPicker::MultiFilesSelected(const std::vector<base::FilePath>& files,
+                                     void* params) {
+  NOTREACHED();
+  client_->FileSelectionCanceled();
+  delete this;
+}
+
 // static
 void EntryPicker::SkipPickerAndAlwaysSelectPathForTest(
     base::FilePath* path) {
diff --git a/chrome/browser/extensions/api/developer_private/entry_picker.h b/chrome/browser/extensions/api/developer_private/entry_picker.h
index 5fafbc64..da4421c 100644
--- a/chrome/browser/extensions/api/developer_private/entry_picker.h
+++ b/chrome/browser/extensions/api/developer_private/entry_picker.h
@@ -42,12 +42,13 @@
   ~EntryPicker() override;
 
  private:
-  // ui::SelectFileDialog::Listener implementation.
+  // ui::SelectFileDialog::Listener:
   void FileSelected(const base::FilePath& path,
                     int index,
                     void* params) override;
-
   void FileSelectionCanceled(void* params) override;
+  void MultiFilesSelected(const std::vector<base::FilePath>& files,
+                          void* params) override;
 
   scoped_refptr<ui::SelectFileDialog> select_file_dialog_;
   EntryPickerClient* client_;
diff --git a/chrome/browser/extensions/browser_context_keyed_service_factories.cc b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
index 86d48df..5830c48 100644
--- a/chrome/browser/extensions/browser_context_keyed_service_factories.cc
+++ b/chrome/browser/extensions/browser_context_keyed_service_factories.cc
@@ -55,7 +55,7 @@
 #include "extensions/browser/api/bluetooth/bluetooth_private_api.h"
 #include "extensions/browser/api/bluetooth_low_energy/bluetooth_low_energy_api.h"
 #include "extensions/browser/api/bluetooth_socket/bluetooth_socket_event_dispatcher.h"
-#include "extensions/browser/api/power/power_api_manager.h"
+#include "extensions/browser/api/power/power_api.h"
 #include "extensions/browser/api/usb/usb_device_resource.h"
 #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_private_api.h"
 #include "extensions/browser/api/web_request/web_request_api.h"
@@ -121,7 +121,7 @@
 #if defined(ENABLE_PLUGINS)
   extensions::PluginManager::GetFactoryInstance();
 #endif  // defined(ENABLE_PLUGINS)
-  extensions::PowerApiManager::GetFactoryInstance();
+  extensions::PowerAPI::GetFactoryInstance();
   extensions::PreferenceAPI::GetFactoryInstance();
   extensions::ProcessesAPI::GetFactoryInstance();
   extensions::PushMessagingAPI::GetFactoryInstance();
diff --git a/chrome/browser/extensions/extension_bindings_apitest.cc b/chrome/browser/extensions/extension_bindings_apitest.cc
index ca0f4d4..c78fb200 100644
--- a/chrome/browser/extensions/extension_bindings_apitest.cc
+++ b/chrome/browser/extensions/extension_bindings_apitest.cc
@@ -92,5 +92,9 @@
       << message_;
 }
 
+IN_PROC_BROWSER_TEST_F(ExtensionBindingsApiTest, ApiEnums) {
+  ASSERT_TRUE(RunExtensionTest("bindings/api_enums")) << message_;
+};
+
 }  // namespace
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_view_host.cc b/chrome/browser/extensions/extension_view_host.cc
index ee79eba..1d0ef9cf 100644
--- a/chrome/browser/extensions/extension_view_host.cc
+++ b/chrome/browser/extensions/extension_view_host.cc
@@ -107,9 +107,9 @@
   if (!ExtensionSystem::Get(browser_context())->
           runtime_data()->IsBackgroundPageReady(extension())) {
     // Make sure the background page loads before any others.
-    registrar()->Add(this,
-                     extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
-                     content::Source<Extension>(extension()));
+    registrar_.Add(this,
+                   extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
+                   content::Source<Extension>(extension()));
     return;
   }
 
@@ -296,13 +296,11 @@
 void ExtensionViewHost::Observe(int type,
                                 const content::NotificationSource& source,
                                 const content::NotificationDetails& details) {
-  if (type == extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY) {
-    DCHECK(ExtensionSystem::Get(browser_context())->
-               runtime_data()->IsBackgroundPageReady(extension()));
-    LoadInitialURL();
-    return;
-  }
-  ExtensionHost::Observe(type, source, details);
+  DCHECK_EQ(type, extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY);
+  DCHECK(ExtensionSystem::Get(browser_context())
+             ->runtime_data()
+             ->IsBackgroundPageReady(extension()));
+  LoadInitialURL();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/extension_view_host.h b/chrome/browser/extensions/extension_view_host.h
index 63cb61e..861d6be9 100644
--- a/chrome/browser/extensions/extension_view_host.h
+++ b/chrome/browser/extensions/extension_view_host.h
@@ -9,6 +9,8 @@
 #include "components/web_modal/popup_manager.h"
 #include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "extensions/browser/extension_host.h"
 
 class Browser;
@@ -29,7 +31,8 @@
 class ExtensionViewHost
     : public ExtensionHost,
       public web_modal::WebContentsModalDialogManagerDelegate,
-      public web_modal::WebContentsModalDialogHost {
+      public web_modal::WebContentsModalDialogHost,
+      public content::NotificationObserver {
  public:
   ExtensionViewHost(const Extension* extension,
                     content::SiteInstance* site_instance,
@@ -127,6 +130,8 @@
   // a parent window.
   scoped_ptr<web_modal::PopupManager> popup_manager_;
 
+  content::NotificationRegistrar registrar_;
+
   DISALLOW_COPY_AND_ASSIGN(ExtensionViewHost);
 };
 
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 9966755..b517af5 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -498,7 +498,7 @@
                                  oem_extension_creation_flags)));
   }
 #elif defined(OS_LINUX)
-  if (!profile->IsSupervised()) {
+  if (!profile->IsLegacySupervised()) {
     provider_list->push_back(
         linked_ptr<ExternalProviderInterface>(
             new ExternalProviderImpl(
@@ -514,7 +514,7 @@
   }
 #endif
 
-  if (!profile->IsSupervised()) {
+  if (!profile->IsLegacySupervised()) {
 #if defined(OS_WIN)
     provider_list->push_back(
         linked_ptr<ExternalProviderInterface>(
@@ -570,17 +570,17 @@
                 Extension::FROM_WEBSTORE |
                     Extension::WAS_INSTALLED_BY_DEFAULT)));
 #endif
-
-    provider_list->push_back(
-      linked_ptr<ExternalProviderInterface>(
-        new ExternalProviderImpl(
-            service,
-            new ExternalComponentLoader(profile),
-            profile,
-            Manifest::INVALID_LOCATION,
-            Manifest::EXTERNAL_COMPONENT,
-            Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT)));
   }
+
+  provider_list->push_back(
+    linked_ptr<ExternalProviderInterface>(
+      new ExternalProviderImpl(
+          service,
+          new ExternalComponentLoader(profile),
+          profile,
+          Manifest::INVALID_LOCATION,
+          Manifest::EXTERNAL_COMPONENT,
+          Extension::FROM_WEBSTORE | Extension::WAS_INSTALLED_BY_DEFAULT)));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/mac/keystone_glue.h b/chrome/browser/mac/keystone_glue.h
index 5c21c36..c6295a5 100644
--- a/chrome/browser/mac/keystone_glue.h
+++ b/chrome/browser/mac/keystone_glue.h
@@ -87,6 +87,7 @@
   // And the Keystone registration itself, with the active timer
   KSRegistration* registration_;  // strong
   NSTimer* timer_;  // strong
+  Class ksUnsignedReportingAttributeClass_;
 
   // The most recent kAutoupdateStatusNotification notification posted.
   base::scoped_nsobject<NSNotification> recentNotification_;
@@ -101,6 +102,10 @@
 
   // YES if an update was ever successfully installed by -installUpdate.
   BOOL updateSuccessfullyInstalled_;
+
+  // Profile count information.
+  uint32_t numProfiles_;
+  uint32_t numSignedInProfiles_;
 }
 
 // Return the default Keystone Glue object.
@@ -172,6 +177,10 @@
 // at the installed copy.
 - (void)setAppPath:(NSString*)appPath;
 
+// Sets the total number of profiles and the number of signed in profiles.
+- (void)updateProfileCountsWithNumProfiles:(uint32_t)profiles
+                       numSignedInProfiles:(uint32_t)signedInProfiles;
+
 @end  // @interface KeystoneGlue
 
 @interface KeystoneGlue(ExposedForTesting)
diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm
index bd0e12e8..42b6b49e 100644
--- a/chrome/browser/mac/keystone_glue.mm
+++ b/chrome/browser/mac/keystone_glue.mm
@@ -119,6 +119,9 @@
 // Called when Keystone registration completes.
 - (void)registrationComplete:(NSNotification*)notification;
 
+// Set the registration active and pass profile count parameters.
+- (void)setRegistrationActive;
+
 // Called periodically to announce activity by pinging the Keystone server.
 - (void)markActive:(NSTimer*)timer;
 
@@ -445,6 +448,8 @@
     return NO;
 
   registration_ = [ksr retain];
+  ksUnsignedReportingAttributeClass_ =
+      [ksrBundle classNamed:@"KSUnsignedReportingAttribute"];
   return YES;
 }
 
@@ -491,6 +496,47 @@
              nil];
 }
 
+- (void)setRegistrationActive {
+  if (!registration_)
+    return;
+
+  // Should never have zero profiles. Do not report this value.
+  if (!numProfiles_) {
+    [registration_ setActive];
+    return;
+  }
+
+  NSError* reportingError = nil;
+
+  KSReportingAttribute* numAccountsAttr =
+      [ksUnsignedReportingAttributeClass_
+          reportingAttributeWithValue:numProfiles_
+                                 name:@"_NumAccounts"
+                      aggregationType:kKSReportingAggregationSum
+                                error:&reportingError];
+  if (reportingError != nil)
+    VLOG(1) << [reportingError localizedDescription];
+  reportingError = nil;
+
+  KSReportingAttribute* numSignedInAccountsAttr =
+      [ksUnsignedReportingAttributeClass_
+          reportingAttributeWithValue:numSignedInProfiles_
+                                 name:@"_NumSignedIn"
+                      aggregationType:kKSReportingAggregationSum
+                                error:&reportingError];
+  if (reportingError != nil)
+    VLOG(1) << [reportingError localizedDescription];
+  reportingError = nil;
+
+  NSArray* profileCountsInformation =
+      [NSArray arrayWithObjects:numAccountsAttr, numSignedInAccountsAttr, nil];
+
+  if (![registration_ setActiveWithReportingAttributes:profileCountsInformation
+                                                 error:&reportingError]) {
+    VLOG(1) << [reportingError localizedDescription];
+  }
+}
+
 - (void)registerWithKeystone {
   [self updateStatus:kAutoupdateRegistering version:nil];
 
@@ -512,13 +558,13 @@
   // posted, and -registrationComplete: will be called.
 
   // Mark an active RIGHT NOW; don't wait an hour for the first one.
-  [registration_ setActive];
+  [self setRegistrationActive];
 
   // Set up hourly activity pings.
   timer_ = [NSTimer scheduledTimerWithTimeInterval:60 * 60  // One hour
                                             target:self
                                           selector:@selector(markActive:)
-                                          userInfo:registration_
+                                          userInfo:nil
                                            repeats:YES];
 }
 
@@ -541,8 +587,7 @@
 }
 
 - (void)markActive:(NSTimer*)timer {
-  KSRegistration* ksr = [timer userInfo];
-  [ksr setActive];
+  [self setRegistrationActive];
 }
 
 - (void)checkForUpdate {
@@ -1049,6 +1094,13 @@
   return tagSuffix;
 }
 
+
+- (void)updateProfileCountsWithNumProfiles:(uint32_t)profiles
+                       numSignedInProfiles:(uint32_t)signedInProfiles {
+  numProfiles_ = profiles;
+  numSignedInProfiles_ = signedInProfiles;
+}
+
 @end  // @implementation KeystoneGlue
 
 namespace {
diff --git a/chrome/browser/mac/keystone_glue_unittest.mm b/chrome/browser/mac/keystone_glue_unittest.mm
index 0021e84..3128fe9e 100644
--- a/chrome/browser/mac/keystone_glue_unittest.mm
+++ b/chrome/browser/mac/keystone_glue_unittest.mm
@@ -39,6 +39,11 @@
   return NO;
 }
 
+- (BOOL)setActiveWithReportingAttributes:(NSArray*)reportingAttributes
+                                   error:(NSError**)error {
+  return NO;
+}
+
 - (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated {
 }
 
diff --git a/chrome/browser/mac/keystone_registration.h b/chrome/browser/mac/keystone_registration.h
index 056dde1..3fa9197 100644
--- a/chrome/browser/mac/keystone_registration.h
+++ b/chrome/browser/mac/keystone_registration.h
@@ -48,10 +48,19 @@
 extern NSString* KSUpdateCheckSuccessfullyInstalledKey;
 
 extern NSString* KSRegistrationRemoveExistingTag;
+
+extern NSString* KSReportingAttributeValueKey;
+extern NSString* KSReportingAttributeExpirationDateKey;
+extern NSString* KSReportingAttributeAggregationTypeKey;
 #define KSRegistrationPreserveExistingTag nil
 
 }  // namespace keystone_registration
 
+typedef enum {
+  kKSReportingAggregationSum = 0,  // Adds attribute value across user accounts
+  kKSReportingAggregationDefault = kKSReportingAggregationSum,
+} KSReportingAggregationType;
+
 @interface KSRegistration : NSObject
 
 + (id)registrationWithProductID:(NSString*)productID;
@@ -62,10 +71,30 @@
                 authorization:(AuthorizationRef)authorization;
 
 - (BOOL)setActive;
+- (BOOL)setActiveWithReportingAttributes:(NSArray*)reportingAttributes
+                                   error:(NSError**)error;
 - (void)checkForUpdateWasUserInitiated:(BOOL)userInitiated;
 - (void)startUpdate;
 - (keystone_registration::KSRegistrationTicketType)ticketType;
 
 @end  // @interface KSRegistration
 
+
+// Declarations of the Keystone attribute reporting bits needed here.
+// Full definition is at:
+// //depot/googlemac/opensource/update-engine/Common/KSReportingAttribute.h
+@interface KSReportingAttribute : NSObject
+
+@end  // @interface KSReportingAttribute
+
+@interface KSUnsignedReportingAttribute : KSReportingAttribute
+
++ (KSUnsignedReportingAttribute *)reportingAttributeWithValue:(uint32_t)value
+               name:(NSString *)name
+    aggregationType:(KSReportingAggregationType)aggregationType
+              error:(NSError **)error;
+
+@end  // @interface KSUnsignedReportingAttribute
+
+
 #endif  // CHROME_BROWSER_MAC_KEYSTONE_REGISTRATION_H_
diff --git a/chrome/browser/mac/keystone_registration.mm b/chrome/browser/mac/keystone_registration.mm
index 779ec94..82e26599 100644
--- a/chrome/browser/mac/keystone_registration.mm
+++ b/chrome/browser/mac/keystone_registration.mm
@@ -39,4 +39,8 @@
 
 NSString* KSRegistrationRemoveExistingTag = @"";
 
+NSString* KSReportingAttributeValueKey = @"value";
+NSString* KSReportingAttributeExpirationDateKey = @"expiresAt";
+NSString* KSReportingAttributeAggregationTypeKey = @"aggregation";
+
 }  // namespace keystone_registration
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index a913c1c9..2480526 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -162,7 +162,6 @@
 #include "chrome/browser/chromeos/extensions/echo_private_api.h"
 #include "chrome/browser/chromeos/file_system_provider/registry.h"
 #include "chrome/browser/chromeos/first_run/first_run.h"
-#include "chrome/browser/chromeos/login/default_pinned_apps_field_trial.h"
 #include "chrome/browser/chromeos/login/saml/saml_offline_signin_limiter.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
@@ -223,19 +222,6 @@
 
 namespace {
 
-enum MigratedPreferences {
-  NO_PREFS = 0,
-  DNS_PREFS = 1 << 0,
-  WINDOWS_PREFS = 1 << 1,
-};
-
-// A previous feature (see
-// chrome/browser/protector/protected_prefs_watcher.cc in source
-// control history) used this string as a prefix for various prefs it
-// registered. We keep it here for now to clear out those old prefs in
-// MigrateUserPrefs.
-const char kBackupPref[] = "backup";
-
 #if !defined(OS_ANDROID)
 // The AutomaticProfileResetter service used this preference to save that the
 // profile reset prompt had already been shown, however, the preference has been
@@ -250,8 +236,6 @@
 namespace chrome {
 
 void RegisterLocalState(PrefRegistrySimple* registry) {
-  // Prefs in Local State.
-  registry->RegisterIntegerPref(prefs::kMultipleProfilePrefMigration, 0);
 
   // Please keep this list alphabetized.
   AppListService::RegisterPrefs(registry);
@@ -328,7 +312,6 @@
   chromeos::DataPromoNotification::RegisterPrefs(registry);
   chromeos::DeviceOAuth2TokenService::RegisterPrefs(registry);
   chromeos::device_settings_cache::RegisterPrefs(registry);
-  chromeos::default_pinned_apps_field_trial::RegisterPrefs(registry);
   chromeos::EnableDebuggingScreenHandler::RegisterPrefs(registry);
   chromeos::language_prefs::RegisterPrefs(registry);
   chromeos::KioskAppManager::RegisterPrefs(registry);
@@ -528,13 +511,6 @@
 #if defined(USE_ASH)
   ash::RegisterChromeLauncherUserPrefs(registry);
 #endif
-
-  // Preferences registered only for migration (clearing or moving to a new key)
-  // go here.
-  registry->RegisterDictionaryPref(
-      kBackupPref,
-      new base::DictionaryValue(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -557,82 +533,47 @@
 }
 #endif
 
-void MigrateUserPrefs(Profile* profile) {
-  PrefService* prefs = profile->GetPrefs();
-
-  // Cleanup prefs from now-removed protector feature.
-  prefs->ClearPref(kBackupPref);
+// This method should be periodically pruned of year+ old migrations.
+void MigrateObsoleteBrowserPrefs(Profile* profile, PrefService* local_state) {
+#if defined(TOOLKIT_VIEWS)
+  // Added 05/2014.
+  MigrateBrowserTabStripPrefs(local_state);
+#endif
 
 #if !defined(OS_ANDROID)
+  // Added 08/2014.
+  local_state->ClearPref(kLegacyProfileResetPromptMemento);
+#endif
+}
+
+// This method should be periodically pruned of year+ old migrations.
+void MigrateObsoleteProfilePrefs(Profile* profile) {
+  PrefService* profile_prefs = profile->GetPrefs();
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // Added 06/2014.
+  autofill::AutofillManager::MigrateUserPrefs(profile_prefs);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+  // Added 07/2014.
+  translate::TranslatePrefs::MigrateUserPrefs(profile_prefs,
+                                              prefs::kAcceptLanguages);
+
+#if !defined(OS_ANDROID)
+  // Added 08/2014.
   // Migrate kNetworkPredictionEnabled to kNetworkPredictionOptions when not on
   // Android.  On Android, platform-specific code performs preference migration.
   // TODO(bnc): https://crbug.com/401970  Remove migration code one year after
   // M38.
-  chrome_browser_net::MigrateNetworkPredictionUserPrefs(prefs);
+  chrome_browser_net::MigrateNetworkPredictionUserPrefs(profile_prefs);
 #endif
 
-  PromoResourceService::MigrateUserPrefs(prefs);
-  translate::TranslatePrefs::MigrateUserPrefs(prefs, prefs::kAcceptLanguages);
-
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-  autofill::AutofillManager::MigrateUserPrefs(prefs);
-#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
-
 #if defined(OS_CHROMEOS) && defined(ENABLE_APP_LIST)
+  // Added 02/2015.
   MigrateGoogleNowPrefs(profile);
 #endif
 }
 
-void MigrateBrowserPrefs(Profile* profile, PrefService* local_state) {
-  // Copy pref values which have been migrated to user_prefs from local_state,
-  // or remove them from local_state outright, if copying is not required.
-  int current_version =
-      local_state->GetInteger(prefs::kMultipleProfilePrefMigration);
-  PrefRegistrySimple* registry = static_cast<PrefRegistrySimple*>(
-      local_state->DeprecatedGetPrefRegistry());
-
-  if (!(current_version & DNS_PREFS)) {
-    registry->RegisterListPref(prefs::kDnsStartupPrefetchList);
-    local_state->ClearPref(prefs::kDnsStartupPrefetchList);
-
-    registry->RegisterListPref(prefs::kDnsHostReferralList);
-    local_state->ClearPref(prefs::kDnsHostReferralList);
-
-    current_version |= DNS_PREFS;
-    local_state->SetInteger(prefs::kMultipleProfilePrefMigration,
-                            current_version);
-  }
-
-  PrefService* user_prefs = profile->GetPrefs();
-  if (!(current_version & WINDOWS_PREFS)) {
-    registry->RegisterDictionaryPref(prefs::kBrowserWindowPlacement);
-    if (local_state->HasPrefPath(prefs::kBrowserWindowPlacement)) {
-      const PrefService::Preference* pref =
-          local_state->FindPreference(prefs::kBrowserWindowPlacement);
-      DCHECK(pref);
-      user_prefs->Set(prefs::kBrowserWindowPlacement,
-                      *(pref->GetValue()));
-    }
-    local_state->ClearPref(prefs::kBrowserWindowPlacement);
-
-    current_version |= WINDOWS_PREFS;
-    local_state->SetInteger(prefs::kMultipleProfilePrefMigration,
-                            current_version);
-  }
-
-#if !defined(OS_ANDROID)
-  local_state->ClearPref(kLegacyProfileResetPromptMemento);
-#endif
-
-#if defined(OS_CHROMEOS)
-  chromeos::default_pinned_apps_field_trial::MigratePrefs(local_state);
-#endif
-
-#if defined(TOOLKIT_VIEWS)
-  MigrateBrowserTabStripPrefs(local_state);
-#endif
-}
-
 // As part of the migration from per-profile to per-partition HostZoomMaps,
 // we need to detect if an existing per-profile set of preferences exist, and
 // if so convert them to be per-partition. We migrate any per-profile zoom
diff --git a/chrome/browser/prefs/browser_prefs.h b/chrome/browser/prefs/browser_prefs.h
index 9fa2829..122ebe4 100644
--- a/chrome/browser/prefs/browser_prefs.h
+++ b/chrome/browser/prefs/browser_prefs.h
@@ -30,11 +30,17 @@
 void RegisterLoginProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 #endif
 
-// Migrates prefs from |local_state| to |profile|'s pref store.
-void MigrateBrowserPrefs(Profile* profile, PrefService* local_state);
+// Migrate/cleanup deprecated prefs in |local_state|. Over time, long deprecated
+// prefs should be removed as new ones are added, but this call should never go
+// away (even if it becomes an empty call for some time) as it should remain
+// *the* place to drop deprecated browser prefs at.
+void MigrateObsoleteBrowserPrefs(Profile* profile, PrefService* local_state);
 
-// Migrates prefs in |profile|'s pref store.
-void MigrateUserPrefs(Profile* profile);
+// Migrate/cleanup deprecated prefs in |profile|'s pref store. Over time, long
+// deprecated prefs should be removed as new ones are added, but this call
+// should never go away (even if it becomes an empty call for some time) as it
+// should remain *the* place to drop deprecated profile prefs at.
+void MigrateObsoleteProfilePrefs(Profile* profile);
 
 // Migrates zoom level prefs in |profile|'s pref store to a per-StoragePartition
 // set of prefs.
diff --git a/chrome/browser/prefs/pref_service_browsertest.cc b/chrome/browser/prefs/pref_service_browsertest.cc
index ba72e21..1a87b041 100644
--- a/chrome/browser/prefs/pref_service_browsertest.cc
+++ b/chrome/browser/prefs/pref_service_browsertest.cc
@@ -52,41 +52,29 @@
 
 class PreferenceServiceTest : public InProcessBrowserTest {
  public:
-  explicit PreferenceServiceTest(bool new_profile) : new_profile_(new_profile) {
-  }
-
   bool SetUpUserDataDirectory() override {
     base::FilePath user_data_directory;
     PathService::Get(chrome::DIR_USER_DATA, &user_data_directory);
 
-    if (new_profile_) {
-      original_pref_file_ = ui_test_utils::GetTestFilePath(
-          base::FilePath().AppendASCII("profiles").
-                     AppendASCII("window_placement").
-                     AppendASCII("Default"),
-          base::FilePath().Append(chrome::kPreferencesFilename));
-      tmp_pref_file_ =
-          user_data_directory.AppendASCII(TestingProfile::kTestUserProfileDir);
-      CHECK(base::CreateDirectory(tmp_pref_file_));
-      tmp_pref_file_ = tmp_pref_file_.Append(chrome::kPreferencesFilename);
-    } else {
-      original_pref_file_ = ui_test_utils::GetTestFilePath(
-          base::FilePath().AppendASCII("profiles").
-                     AppendASCII("window_placement"),
-          base::FilePath().Append(chrome::kLocalStateFilename));
-      tmp_pref_file_ = user_data_directory.Append(chrome::kLocalStateFilename);
-    }
+    original_pref_file_ = ui_test_utils::GetTestFilePath(
+        base::FilePath()
+            .AppendASCII("profiles")
+            .AppendASCII("window_placement")
+            .AppendASCII("Default"),
+        base::FilePath().Append(chrome::kPreferencesFilename));
+    tmp_pref_file_ =
+        user_data_directory.AppendASCII(TestingProfile::kTestUserProfileDir);
+    EXPECT_TRUE(base::CreateDirectory(tmp_pref_file_));
+    tmp_pref_file_ = tmp_pref_file_.Append(chrome::kPreferencesFilename);
 
-    CHECK(base::PathExists(original_pref_file_));
-    // Copy only the Preferences file if |new_profile_|, or Local State if not,
-    // and the rest will be automatically created.
-    CHECK(base::CopyFile(original_pref_file_, tmp_pref_file_));
+    EXPECT_TRUE(base::PathExists(original_pref_file_));
+    EXPECT_TRUE(base::CopyFile(original_pref_file_, tmp_pref_file_));
 
 #if defined(OS_WIN)
     // Make the copy writable.  On POSIX we assume the umask allows files
     // we create to be writable.
-    CHECK(::SetFileAttributesW(tmp_pref_file_.value().c_str(),
-        FILE_ATTRIBUTE_NORMAL));
+    EXPECT_TRUE(::SetFileAttributesW(tmp_pref_file_.value().c_str(),
+                                     FILE_ATTRIBUTE_NORMAL));
 #endif
     return true;
   }
@@ -94,9 +82,6 @@
  protected:
   base::FilePath original_pref_file_;
   base::FilePath tmp_pref_file_;
-
- private:
-  bool new_profile_;
 };
 
 #if defined(OS_WIN) || defined(OS_MACOSX)
@@ -106,13 +91,7 @@
 // might be able to make this work on buildbots.
 // TODO(port): revisit this.
 
-class PreservedWindowPlacementIsLoaded : public PreferenceServiceTest {
- public:
-  PreservedWindowPlacementIsLoaded() : PreferenceServiceTest(true) {
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsLoaded, Test) {
+IN_PROC_BROWSER_TEST_F(PreferenceServiceTest, Test) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -164,69 +143,3 @@
   EXPECT_EQ(is_maximized, is_window_maximized);
 }
 #endif
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-
-class PreservedWindowPlacementIsMigrated : public PreferenceServiceTest {
- public:
-  PreservedWindowPlacementIsMigrated() : PreferenceServiceTest(false) {
-  }
-};
-
-IN_PROC_BROWSER_TEST_F(PreservedWindowPlacementIsMigrated, Test) {
-#if defined(OS_WIN) && defined(USE_ASH)
-  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAshBrowserTests))
-    return;
-#endif
-
-  // The window should open with the old reference profile, with window
-  // placement values stored in Local State.
-
-  JSONFileValueSerializer deserializer(original_pref_file_);
-  scoped_ptr<base::Value> root(deserializer.Deserialize(NULL, NULL));
-
-  ASSERT_TRUE(root.get());
-  ASSERT_TRUE(root->IsType(base::Value::TYPE_DICTIONARY));
-
-  // Retrieve the screen rect for the launched window
-  gfx::Rect bounds = browser()->window()->GetRestoredBounds();
-
-  // Values from old reference profile in Local State should have been
-  // correctly migrated to the user's Preferences -- if so, the window
-  // should be set to values taken from the user's Local State.
-  base::DictionaryValue* root_dict =
-      static_cast<base::DictionaryValue*>(root.get());
-
-  // Retrieve the expected rect values from User Preferences, where they
-  // should have been migrated from Local State.
-  int bottom = 0;
-  std::string kBrowserWindowPlacement(prefs::kBrowserWindowPlacement);
-  EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".bottom",
-      &bottom));
-  EXPECT_EQ(bottom, bounds.y() + bounds.height());
-
-  int top = 0;
-  EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".top",
-      &top));
-  EXPECT_EQ(top, bounds.y());
-
-  int left = 0;
-  EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".left",
-      &left));
-  EXPECT_EQ(left, bounds.x());
-
-  int right = 0;
-  EXPECT_TRUE(root_dict->GetInteger(kBrowserWindowPlacement + ".right",
-      &right));
-  EXPECT_EQ(right, bounds.x() + bounds.width());
-
-  // Find if launched window is maximized.
-  bool is_window_maximized = browser()->window()->IsMaximized();
-  bool is_maximized = false;
-  EXPECT_TRUE(root_dict->GetBoolean(kBrowserWindowPlacement + ".maximized",
-      &is_maximized));
-  EXPECT_EQ(is_maximized, is_window_maximized);
-}
-#endif
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 9b7389f..05bd533 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -851,11 +851,10 @@
     return;
   }
 
-  // TODO(mirandac): remove migration code after 6 months (crbug.com/69995).
+  // Migrate obsolete prefs.
   if (g_browser_process->local_state())
-    chrome::MigrateBrowserPrefs(this, g_browser_process->local_state());
-  // TODO(ivankr): remove cleanup code eventually (crbug.com/165672).
-  chrome::MigrateUserPrefs(this);
+    chrome::MigrateObsoleteBrowserPrefs(this, g_browser_process->local_state());
+  chrome::MigrateObsoleteProfilePrefs(this);
 
   // |kSessionExitType| was added after |kSessionExitedCleanly|. If the pref
   // value is empty fallback to checking for |kSessionExitedCleanly|.
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 36ee8e3d..7d3f1fb 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -558,8 +558,8 @@
 Profile* ProfileManager::GetProfileByPath(const base::FilePath& path) const {
   TRACE_EVENT0("browser", "ProfileManager::GetProfileByPath");
   ProfileInfo* profile_info = GetProfileInfoByPath(path);
-  return profile_info && profile_info->created ? profile_info->profile.get()
-                                               : nullptr;
+  return (profile_info && profile_info->created) ? profile_info->profile.get()
+                                                 : nullptr;
 }
 
 // static
@@ -650,7 +650,6 @@
     service->CancelDownloads();
   }
 
-  PrefService* local_state = g_browser_process->local_state();
   ProfileInfoCache& cache = GetProfileInfoCache();
 
   // If we're deleting the last (non-legacy-supervised) profile, then create a
@@ -682,51 +681,42 @@
 
     new_path = GenerateNextProfileDirectoryPath();
     CreateProfileAsync(new_path,
-                       callback,
+                       base::Bind(&ProfileManager::OnNewActiveProfileLoaded,
+                                  base::Unretained(this),
+                                  profile_dir,
+                                  new_path,
+                                  callback),
                        new_profile_name,
                        new_avatar_url,
                        std::string());
 
     ProfileMetrics::LogProfileAddNewUser(
         ProfileMetrics::ADD_NEW_USER_LAST_DELETED);
+    return;
   }
 
-  // Update the last used profile pref before closing browser windows. This
-  // way the correct last used profile is set for any notification observers.
+#if defined(OS_MACOSX)
+  // On the Mac, the browser process is not killed when all browser windows are
+  // closed, so just in case we are deleting the active profile, and no other
+  // profile has been loaded, we must pre-load a next one.
   const std::string last_used_profile =
-      local_state->GetString(prefs::kProfileLastUsed);
+      g_browser_process->local_state()->GetString(prefs::kProfileLastUsed);
   if (last_used_profile == profile_dir.BaseName().MaybeAsASCII() ||
       last_used_profile == GetGuestProfilePath().BaseName().MaybeAsASCII()) {
-    const std::string last_non_supervised_profile =
-        last_non_supervised_profile_path.BaseName().MaybeAsASCII();
-    if (last_non_supervised_profile.empty()) {
-      DCHECK(!new_path.empty());
-      local_state->SetString(prefs::kProfileLastUsed,
-                             new_path.BaseName().MaybeAsASCII());
-    } else {
-      // On the Mac, the browser process is not killed when all browser windows
-      // are closed, so just in case we are deleting the active profile, and no
-      // other profile has been loaded, we must pre-load a next one.
-#if defined(OS_MACOSX)
-      CreateProfileAsync(last_non_supervised_profile_path,
-                         base::Bind(&ProfileManager::OnNewActiveProfileLoaded,
-                                    base::Unretained(this),
-                                    profile_dir,
-                                    last_non_supervised_profile_path,
-                                    callback),
-                         base::string16(),
-                         base::string16(),
-                         std::string());
-      return;
-#else
-      // For OS_MACOSX the pref is updated in the callback to make sure that
-      // it isn't used before the profile is actually loaded.
-      local_state->SetString(prefs::kProfileLastUsed,
-                             last_non_supervised_profile);
-#endif
-    }
+    CreateProfileAsync(last_non_supervised_profile_path,
+                       base::Bind(&ProfileManager::OnNewActiveProfileLoaded,
+                                  base::Unretained(this),
+                                  profile_dir,
+                                  last_non_supervised_profile_path,
+                                  callback),
+                       base::string16(),
+                       base::string16(),
+                       std::string());
+    return;
   }
-  FinishDeletingProfile(profile_dir);
+#endif  // defined(OS_MACOSX)
+
+  FinishDeletingProfile(profile_dir, last_non_supervised_profile_path);
 }
 
 // static
@@ -1160,7 +1150,15 @@
   return profile;
 }
 
-void ProfileManager::FinishDeletingProfile(const base::FilePath& profile_dir) {
+void ProfileManager::FinishDeletingProfile(
+    const base::FilePath& profile_dir,
+    const base::FilePath& new_active_profile_dir) {
+  // Update the last used profile pref before closing browser windows. This
+  // way the correct last used profile is set for any notification observers.
+  g_browser_process->local_state()->SetString(
+      prefs::kProfileLastUsed,
+      new_active_profile_dir.BaseName().MaybeAsASCII());
+
   ProfileInfoCache& cache = GetProfileInfoCache();
   // TODO(sail): Due to bug 88586 we don't delete the profile instance. Once we
   // start deleting the profile instance we need to close background apps too.
@@ -1372,10 +1370,9 @@
 }
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
-#if defined(OS_MACOSX)
 void ProfileManager::OnNewActiveProfileLoaded(
     const base::FilePath& profile_to_delete_path,
-    const base::FilePath& last_non_supervised_profile_path,
+    const base::FilePath& new_active_profile_path,
     const CreateCallback& original_callback,
     Profile* loaded_profile,
     Profile::CreateStatus status) {
@@ -1383,22 +1380,21 @@
          status != Profile::CREATE_STATUS_REMOTE_FAIL);
 
   // Only run the code if the profile initialization has finished completely.
-  if (status == Profile::CREATE_STATUS_INITIALIZED) {
-    if (IsProfileMarkedForDeletion(last_non_supervised_profile_path)) {
-      // If the profile we tried to load as the next active profile has been
-      // deleted, then retry deleting this profile to redo the logic to load
-      // the next available profile.
-      ScheduleProfileForDeletion(profile_to_delete_path, original_callback);
-    } else {
-      // Update the local state as promised in the ScheduleProfileForDeletion.
-      g_browser_process->local_state()->SetString(
-          prefs::kProfileLastUsed,
-          last_non_supervised_profile_path.BaseName().MaybeAsASCII());
-      FinishDeletingProfile(profile_to_delete_path);
-    }
+  if (status != Profile::CREATE_STATUS_INITIALIZED)
+    return;
+
+  if (IsProfileMarkedForDeletion(new_active_profile_path)) {
+    // If the profile we tried to load as the next active profile has been
+    // deleted, then retry deleting this profile to redo the logic to load
+    // the next available profile.
+    ScheduleProfileForDeletion(profile_to_delete_path, original_callback);
+    return;
   }
+
+  FinishDeletingProfile(profile_to_delete_path, new_active_profile_path);
+  if (!original_callback.is_null())
+    original_callback.Run(loaded_profile, status);
 }
-#endif
 
 ProfileManagerWithoutInit::ProfileManagerWithoutInit(
     const base::FilePath& user_data_dir) : ProfileManager(user_data_dir) {
diff --git a/chrome/browser/profiles/profile_manager.h b/chrome/browser/profiles/profile_manager.h
index ff28e3d1..9436a459e 100644
--- a/chrome/browser/profiles/profile_manager.h
+++ b/chrome/browser/profiles/profile_manager.h
@@ -265,8 +265,10 @@
   // creation and adds it to the set managed by this ProfileManager.
   Profile* CreateAndInitializeProfile(const base::FilePath& profile_dir);
 
-  // Schedules the profile at the given path to be deleted on shutdown.
-  void FinishDeletingProfile(const base::FilePath& profile_dir);
+  // Schedules the profile at the given path to be deleted on shutdown,
+  // and marks the new profile as active.
+  void FinishDeletingProfile(const base::FilePath& profile_dir,
+                             const base::FilePath& new_active_profile_dir);
 
   // Registers profile with given info. Returns pointer to created ProfileInfo
   // entry.
@@ -317,7 +319,6 @@
   };
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
 
-#if defined(OS_MACOSX)
   // If the |loaded_profile| has been loaded successfully (according to
   // |status|) and isn't already scheduled for deletion, then finishes adding
   // |profile_to_delete_dir| to the queue of profiles to be deleted, and updates
@@ -329,7 +330,6 @@
       const CreateCallback& original_callback,
       Profile* loaded_profile,
       Profile::CreateStatus status);
-#endif
 
   content::NotificationRegistrar registrar_;
 
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index 820eb18..43df0d4b 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -40,10 +40,11 @@
 
 // An observer that returns back to test code after a new profile is
 // initialized.
-void OnUnblockOnProfileCreation(Profile* profile,
+void OnUnblockOnProfileCreation(base::RunLoop* run_loop,
+                                Profile* profile,
                                 Profile::CreateStatus status) {
   if (status == Profile::CREATE_STATUS_INITIALIZED)
-    base::MessageLoop::current()->Quit();
+    run_loop->Quit();
 }
 
 void ProfileCreationComplete(Profile* profile, Profile::CreateStatus status) {
@@ -91,26 +92,26 @@
 
 // The class serves to retrieve passwords from PasswordStore asynchronously. It
 // used by ProfileManagerBrowserTest.DeletePasswords on some platforms.
-class PasswordStoreConsumerVerifier :
-    public password_manager::PasswordStoreConsumer {
+class PasswordStoreConsumerVerifier
+    : public password_manager::PasswordStoreConsumer {
  public:
-  PasswordStoreConsumerVerifier() : called_(false) {}
-
   void OnGetPasswordStoreResults(
       ScopedVector<autofill::PasswordForm> results) override {
-    EXPECT_FALSE(called_);
-    called_ = true;
     password_entries_.swap(results);
+    run_loop_.Quit();
   }
 
-  bool IsCalled() const { return called_; }
+  void Wait() {
+    run_loop_.Run();
+  }
 
   const std::vector<autofill::PasswordForm*>& GetPasswords() const {
     return password_entries_.get();
   }
+
  private:
+  base::RunLoop run_loop_;
   ScopedVector<autofill::PasswordForm> password_entries_;
-  bool called_;
 };
 
 static base::FilePath GetFirstNonSigninProfile(const ProfileInfoCache& cache) {
@@ -160,20 +161,23 @@
   // Delete singleton profile.
   base::FilePath singleton_profile_path = cache.GetPathOfProfileAtIndex(0);
   EXPECT_FALSE(singleton_profile_path.empty());
-  profile_manager->ScheduleProfileForDeletion(singleton_profile_path,
-                                              ProfileManager::CreateCallback());
+  base::RunLoop run_loop;
+  profile_manager->ScheduleProfileForDeletion(
+      singleton_profile_path,
+      base::Bind(&OnUnblockOnProfileCreation, &run_loop));
 
-  // Spin things till profile is actually deleted.
-  content::RunAllPendingInMessageLoop();
+  // Run the message loop until the profile is actually deleted (as indicated
+  // by the callback above being called).
+  run_loop.Run();
 
   // Make sure a new profile was created automatically.
   EXPECT_EQ(cache.GetNumberOfProfiles(), 1U);
   base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0);
-  EXPECT_NE(new_profile_path, singleton_profile_path);
+  EXPECT_NE(new_profile_path.value(), singleton_profile_path.value());
 
   // Make sure that last used profile preference is set correctly.
   Profile* last_used = ProfileManager::GetLastUsedProfile();
-  EXPECT_EQ(new_profile_path, last_used->GetPath());
+  EXPECT_EQ(new_profile_path.value(), last_used->GetPath().value());
 
   // Make sure the last used profile was set correctly before the notification
   // was sent.
@@ -191,14 +195,14 @@
 
   // Create an additional profile.
   base::FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath();
-  profile_manager->CreateProfileAsync(new_path,
-                                      base::Bind(&OnUnblockOnProfileCreation),
-                                      base::string16(), base::string16(),
-                                      std::string());
+  base::RunLoop run_loop;
+  profile_manager->CreateProfileAsync(
+      new_path, base::Bind(&OnUnblockOnProfileCreation, &run_loop),
+      base::string16(), base::string16(), std::string());
 
-  // Spin to allow profile creation to take place, loop is terminated
-  // by OnUnblockOnProfileCreation when the profile is created.
-  content::RunMessageLoop();
+  // Run the message loop to allow profile creation to take place; the loop is
+  // terminated by OnUnblockOnProfileCreation when the profile is created.
+  run_loop.Run();
 
   ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
 
@@ -306,14 +310,14 @@
   // Create an additional profile.
   base::FilePath path_profile2 =
       profile_manager->GenerateNextProfileDirectoryPath();
-  profile_manager->CreateProfileAsync(path_profile2,
-                                      base::Bind(&OnUnblockOnProfileCreation),
-                                      base::string16(), base::string16(),
-                                      std::string());
+  base::RunLoop run_loop;
+  profile_manager->CreateProfileAsync(
+      path_profile2, base::Bind(&OnUnblockOnProfileCreation, &run_loop),
+      base::string16(), base::string16(), std::string());
 
-  // Spin to allow profile creation to take place, loop is terminated
-  // by OnUnblockOnProfileCreation when the profile is created.
-  content::RunMessageLoop();
+  // Run the message loop to allow profile creation to take place; the loop is
+  // terminated by OnUnblockOnProfileCreation when the profile is created.
+  run_loop.Run();
 
   chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
   BrowserList* browser_list = BrowserList::GetInstance(desktop_type);
@@ -445,27 +449,18 @@
   password_store->AddLogin(form);
   PasswordStoreConsumerVerifier verify_add;
   password_store->GetAutofillableLogins(&verify_add);
+  verify_add.Wait();
+  EXPECT_EQ(1u, verify_add.GetPasswords().size());
 
   ProfileManager* profile_manager = g_browser_process->profile_manager();
-  profile_manager->ScheduleProfileForDeletion(profile->GetPath(),
-                                              ProfileManager::CreateCallback());
-  content::RunAllPendingInMessageLoop();
-  PasswordStoreConsumerVerifier verify_delete;
-  password_store->GetAutofillableLogins(&verify_delete);
-
-  // Run the password background thread.
   base::RunLoop run_loop;
-  base::Closure task = base::Bind(
-      base::IgnoreResult(&content::BrowserThread::PostTask),
-      content::BrowserThread::UI,
-      FROM_HERE,
-      run_loop.QuitClosure());
-  EXPECT_TRUE(password_store->ScheduleTask(task));
+  profile_manager->ScheduleProfileForDeletion(
+      profile->GetPath(), base::Bind(&OnUnblockOnProfileCreation, &run_loop));
   run_loop.Run();
 
-  EXPECT_TRUE(verify_add.IsCalled());
-  EXPECT_EQ(1u, verify_add.GetPasswords().size());
-  EXPECT_TRUE(verify_delete.IsCalled());
+  PasswordStoreConsumerVerifier verify_delete;
+  password_store->GetAutofillableLogins(&verify_delete);
+  verify_delete.Wait();
   EXPECT_EQ(0u, verify_delete.GetPasswords().size());
 }
 #endif  // !defined(OS_WIN) && !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
diff --git a/chrome/browser/profiles/profile_metrics.cc b/chrome/browser/profiles/profile_metrics.cc
index 6dfcf73c..f9b3046 100644
--- a/chrome/browser/profiles/profile_metrics.cc
+++ b/chrome/browser/profiles/profile_metrics.cc
@@ -20,7 +20,10 @@
 
 namespace {
 
+#if defined(OS_WIN) || defined(OS_MACOSX)
 const int kMaximumReportedProfileCount = 5;
+#endif
+
 const int kMaximumDaysOfDisuse = 4 * 7;  // Should be integral number of weeks.
 
 size_t number_of_profile_switches_ = 0;
@@ -67,12 +70,6 @@
   return metric;
 }
 
-void UpdateReportedOSProfileStatistics(int active, int signedin) {
-#if defined(OS_WIN)
-  GoogleUpdateSettings::UpdateProfileCounts(active, signedin);
-#endif
-}
-
 void LogLockedProfileInformation(ProfileManager* manager) {
   const ProfileInfoCache& info_cache = manager->GetProfileInfoCache();
   size_t number_of_profiles = info_cache.GetNumberOfProfiles();
@@ -177,10 +174,11 @@
 }
 
 void ProfileMetrics::UpdateReportedProfilesStatistics(ProfileManager* manager) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
   ProfileCounts counts;
   if (CountProfileInformation(manager, &counts)) {
-    int limited_total = counts.total;
-    int limited_signedin = counts.signedin;
+    size_t limited_total = counts.total;
+    size_t limited_signedin = counts.signedin;
     if (limited_total > kMaximumReportedProfileCount) {
       limited_total = kMaximumReportedProfileCount + 1;
       limited_signedin =
@@ -189,6 +187,7 @@
     }
     UpdateReportedOSProfileStatistics(limited_total, limited_signedin);
   }
+#endif
 }
 
 void ProfileMetrics::LogNumberOfProfileSwitches() {
@@ -196,6 +195,14 @@
                            number_of_profile_switches_);
 }
 
+// The OS_MACOSX implementation of this function is in profile_metrics_mac.mm.
+#if defined(OS_WIN)
+void ProfileMetrics::UpdateReportedOSProfileStatistics(
+    size_t active, size_t signedin) {
+  GoogleUpdateSettings::UpdateProfileCounts(active, signedin);
+}
+#endif
+
 void ProfileMetrics::LogNumberOfProfiles(ProfileManager* manager) {
   ProfileCounts counts;
   bool success = CountProfileInformation(manager, &counts);
@@ -217,7 +224,10 @@
                              counts.auth_errors);
 
     LogLockedProfileInformation(manager);
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
     UpdateReportedOSProfileStatistics(counts.total, counts.signedin);
+#endif
   }
 }
 
diff --git a/chrome/browser/profiles/profile_metrics.h b/chrome/browser/profiles/profile_metrics.h
index 8feb60f..85ae5af 100644
--- a/chrome/browser/profiles/profile_metrics.h
+++ b/chrome/browser/profiles/profile_metrics.h
@@ -208,6 +208,11 @@
                                       ProfileCounts* counts);
 
   static void LogNumberOfProfileSwitches();
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // Update OS level tracking of profile counts.
+  static void UpdateReportedOSProfileStatistics(size_t active, size_t signedin);
+#endif
+
   static void LogNumberOfProfiles(ProfileManager* manager);
   static void LogProfileAddNewUser(ProfileAdd metric);
   static void LogProfileAvatarSelection(size_t icon_index);
diff --git a/chrome/browser/profiles/profile_metrics_mac.mm b/chrome/browser/profiles/profile_metrics_mac.mm
new file mode 100644
index 0000000..8b12871
--- /dev/null
+++ b/chrome/browser/profiles/profile_metrics_mac.mm
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/profiles/profile_metrics.h"
+
+#include "base/numerics/safe_conversions.h"
+#include "chrome/browser/mac/keystone_glue.h"
+
+void ProfileMetrics::UpdateReportedOSProfileStatistics(
+    size_t active, size_t signedin) {
+  if (base::IsValueInRangeForNumericType<uint32_t>(active) &&
+      base::IsValueInRangeForNumericType<uint32_t>(signedin)) {
+    [[KeystoneGlue defaultKeystoneGlue]
+        updateProfileCountsWithNumProfiles:active
+                       numSignedInProfiles:signedin];
+  }
+}
diff --git a/chrome/browser/resources/chromeos/network_ui/network_ui.css b/chrome/browser/resources/chromeos/network_ui/network_ui.css
index c3fbf87..874e916a 100644
--- a/chrome/browser/resources/chromeos/network_ui/network_ui.css
+++ b/chrome/browser/resources/chromeos/network_ui/network_ui.css
@@ -50,6 +50,11 @@
   font-weight: bold;
 }
 
+.state-table-icon-cell {
+  display: flex;
+  justify-content: center;
+}
+
 .state-table-expand-button-cell {
   text-align: center;
 }
diff --git a/chrome/browser/resources/extensions/extension_list.js b/chrome/browser/resources/extensions/extension_list.js
index c185b29b..16b1132 100644
--- a/chrome/browser/resources/extensions/extension_list.js
+++ b/chrome/browser/resources/extensions/extension_list.js
@@ -384,8 +384,7 @@
       // The 'allow file:// access' checkbox.
       row.setupColumn('.file-access-control input', 'localUrls', 'click',
                       function(e) {
-        chrome.send('extensionSettingsAllowFileAccess',
-                    [extension.id, String(e.target.checked)]);
+        chrome.developerPrivate.allowFileAccess(extension.id, e.target.checked);
       });
 
       // The 'Options' button or link, depending on its behaviour.
@@ -467,6 +466,17 @@
                                     function() {
           // TODO(devlin): What should we do if the uninstall fails?
           this.uninstallIsShowing_ = false;
+
+          if (trash.classList.contains('mouse-clicked'))
+            trash.blur();
+
+          if (chrome.runtime.lastError) {
+            // The uninstall failed (e.g. a cancel). Allow the trash to close.
+            trash.classList.remove('open');
+          } else {
+            // Leave the trash open if the uninstall succeded. Otherwise it can
+            // half-close right before it's removed when the DOM is modified.
+          }
         }.bind(this));
       }.bind(this));
       row.querySelector('.enable-controls').appendChild(trash);
@@ -900,13 +910,6 @@
     },
   };
 
-  ExtensionList.uninstallCancel = function() {
-    var trash = document.querySelector('.trash.open');
-    if (trash.classList.contains('mouse-clicked'))
-      trash.blur();
-    trash.classList.remove('open');
-  };
-
   return {
     ExtensionList: ExtensionList
   };
diff --git a/chrome/browser/resources/extensions/extensions.js b/chrome/browser/resources/extensions/extensions.js
index 20b486f6..6500f07c 100644
--- a/chrome/browser/resources/extensions/extensions.js
+++ b/chrome/browser/resources/extensions/extensions.js
@@ -343,28 +343,6 @@
     ExtensionList.decorate($('extension-settings-list'));
   };
 
-  // Indicate that warning |message| has occured for pack of |crx_path| and
-  // |pem_path| files.  Ask if user wants override the warning.  Send
-  // |overrideFlags| to repeated 'pack' call to accomplish the override.
-  ExtensionSettings.askToOverrideWarning =
-      function(message, crx_path, pem_path, overrideFlags) {
-    var closeAlert = function() {
-      ExtensionSettings.showOverlay(null);
-    };
-
-    alertOverlay.setValues(
-        loadTimeData.getString('packExtensionWarningTitle'),
-        message,
-        loadTimeData.getString('packExtensionProceedAnyway'),
-        loadTimeData.getString('cancel'),
-        function() {
-          chrome.send('pack', [crx_path, pem_path, overrideFlags]);
-          closeAlert();
-        },
-        closeAlert);
-    ExtensionSettings.showOverlay($('alertOverlay'));
-  };
-
   /**
    * Returns the current overlay or null if one does not exist.
    * @return {Element} The overlay element.
diff --git a/chrome/browser/resources/extensions/pack_extension_overlay.js b/chrome/browser/resources/extensions/pack_extension_overlay.js
index 186f841..8cb7725 100644
--- a/chrome/browser/resources/extensions/pack_extension_overlay.js
+++ b/chrome/browser/resources/extensions/pack_extension_overlay.js
@@ -48,24 +48,24 @@
     handleCommit_: function(e) {
       var extensionPath = $('extension-root-dir').value;
       var privateKeyPath = $('extension-private-key').value;
-      chrome.send('pack', [extensionPath, privateKeyPath, 0]);
+      chrome.developerPrivate.packDirectory(
+          extensionPath, privateKeyPath, 0, this.onPackResponse_.bind(this));
     },
 
     /**
      * Utility function which asks the C++ to show a platform-specific file
-     * select dialog, and fire |callback| with the |filePath| that resulted.
-     * |selectType| can be either 'file' or 'folder'. |operation| can be 'load'
-     * or 'pem' which are signals to the C++ to do some operation-specific
-     * configuration.
+     * select dialog, and set the value property of |node| to the selected path.
+     * @param {SelectType} selectType The type of selection to use.
+     * @param {FileType} fileType The type of file to select.
+     * @param {HTMLInputElement} node The node to set the value of.
      * @private
      */
-    showFileDialog_: function(selectType, operation, callback) {
-      window.handleFilePathSelected = function(filePath) {
-        callback(filePath);
-        window.handleFilePathSelected = function() {};
-      };
-
-      chrome.send('packExtensionSelectFilePath', [selectType, operation]);
+    showFileDialog_: function(selectType, fileType, node) {
+      chrome.developerPrivate.choosePath(selectType, fileType, function(path) {
+        // Last error is set if the user canceled the dialog.
+        if (!chrome.runtime.lastError && path)
+          node.value = path;
+      });
     },
 
     /**
@@ -74,9 +74,10 @@
      * @private
      */
     handleBrowseExtensionDir_: function(e) {
-      this.showFileDialog_('folder', 'load', function(filePath) {
-        $('extension-root-dir').value = filePath;
-      });
+      this.showFileDialog_(
+          'FOLDER',
+          'LOAD',
+          /** @type {HTMLInputElement} */ ($('extension-root-dir')));
     },
 
     /**
@@ -85,44 +86,78 @@
      * @private
      */
     handleBrowsePrivateKey_: function(e) {
-      this.showFileDialog_('file', 'pem', function(filePath) {
-        $('extension-private-key').value = filePath;
-      });
+      this.showFileDialog_(
+          'FILE',
+          'PEM',
+          /** @type {HTMLInputElement} */ ($('extension-private-key')));
     },
-  };
 
-  /**
-   * Wrap up the pack process by showing the success |message| and closing
-   * the overlay.
-   * @param {string} message The message to show to the user.
-   */
-  PackExtensionOverlay.showSuccessMessage = function(message) {
-    alertOverlay.setValues(
-        loadTimeData.getString('packExtensionOverlay'),
-        message,
-        loadTimeData.getString('ok'),
-        '',
-        function() {
-          extensions.ExtensionSettings.showOverlay(null);
-        });
-    extensions.ExtensionSettings.showOverlay($('alertOverlay'));
-  };
+    /**
+     * Handles a response from a packDirectory call.
+     * @param {PackDirectoryResponse} response The response of the pack call.
+     * @private
+     */
+    onPackResponse_: function(response) {
+      /** @type {string} */
+      var alertTitle;
+      /** @type {string} */
+      var alertOk;
+      /** @type {string} */
+      var alertCancel;
+      /** @type {function()} */
+      var alertOkCallback;
+      /** @type {function()} */
+      var alertCancelCallback;
 
-  /**
-   * Post an alert overlay showing |message|, and upon acknowledgement, close
-   * the alert overlay and return to showing the PackExtensionOverlay.
-   * @param {string} message The error message.
-   */
-  PackExtensionOverlay.showError = function(message) {
-    alertOverlay.setValues(
-        loadTimeData.getString('packExtensionErrorTitle'),
-        message,
-        loadTimeData.getString('ok'),
-        '',
-        function() {
-          extensions.ExtensionSettings.showOverlay($('pack-extension-overlay'));
-        });
-    extensions.ExtensionSettings.showOverlay($('alertOverlay'));
+      var closeAlert = function() {
+        extensions.ExtensionSettings.showOverlay(null);
+      };
+
+      // TODO(devlin): Once we expose enums on extension APIs, we should use
+      // those objects, instead of a string.
+      switch (response.status) {
+        case 'SUCCESS':
+          alertTitle = loadTimeData.getString('packExtensionOverlay');
+          alertOk = loadTimeData.getString('ok');
+          alertOkCallback = closeAlert;
+          // No 'Cancel' option.
+          break;
+        case 'WARNING':
+          alertTitle = loadTimeData.getString('packExtensionWarningTitle');
+          alertOk = loadTimeData.getString('packExtensionProceedAnyway');
+          alertCancel = loadTimeData.getString('cancel');
+          alertOkCallback = function() {
+            chrome.developerPrivate.packDirectory(
+                response.item_path,
+                response.pem_path,
+                response.override_flags,
+                this.onPackResponse_.bind(this));
+            closeAlert();
+          }.bind(this);
+          alertCancelCallback = closeAlert;
+          break;
+        case 'ERROR':
+          alertTitle = loadTimeData.getString('packExtensionErrorTitle');
+          alertOk = loadTimeData.getString('ok');
+          alertOkCallback = function() {
+            extensions.ExtensionSettings.showOverlay(
+                $('pack-extension-overlay'));
+          };
+          // No 'Cancel' option.
+          break;
+        default:
+          assertNotReached();
+          return;
+      }
+
+      alertOverlay.setValues(alertTitle,
+                             response.message,
+                             alertOk,
+                             alertCancel,
+                             alertOkCallback,
+                             alertCancelCallback);
+      extensions.ExtensionSettings.showOverlay($('alertOverlay'));
+    },
   };
 
   // Export
diff --git a/chrome/browser/resources/md_settings/md_settings.html b/chrome/browser/resources/md_settings/md_settings.html
index c3b5842..7e33367 100644
--- a/chrome/browser/resources/md_settings/md_settings.html
+++ b/chrome/browser/resources/md_settings/md_settings.html
@@ -8,6 +8,7 @@
   <link rel="import" href="chrome://resources/polymer/core-menu/core-menu.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_collapse/cr_collapse.html">
+  <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_toggle_button/cr_toggle_button.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
   <link rel="import" href="chrome://resources/cr_elements/cr_dropdown_menu/cr_dropdown_menu.html">
@@ -39,7 +40,7 @@
       </cr-dropdown-menu>
     </section>
     <section>
-      <h2>cr-collapse</h2>
+      <h3>cr-collapse</h3>
       <paper-button id="manage-button" raised onclick="toggleCollapse();">
         Toggle Collapse
       </paper-button>
@@ -52,6 +53,10 @@
       <cr-button>Flat button</cr-button>
       <cr-button raised>Raised Button</cr-button>
     </section>
+    <section>
+      <h3>cr-input</h3>
+      <cr-input label="Enter Something!"></cr-input>
+    </section>
   </div>
   <script>
     var collapse = document.getElementById('collapse');
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html
index 7c800e5e..ccf90c0 100644
--- a/chrome/browser/resources/options/browser_options.html
+++ b/chrome/browser/resources/options/browser_options.html
@@ -306,11 +306,6 @@
         </div>
       </div>
       <div class="checkbox settings-row">
-        <label>
-          <input id="use-24hour-clock" pref="settings.clock.use_24hour_clock"
-              metric="Options_Use24HourClockCheckbox" type="checkbox">
-          <span i18n-content="use24HourClock"></span>
-        </label>
         <div id="resolve-timezone-by-geolocation-selection" hidden>
           <label>
             <input id="resolve-timezone-by-geolocation"
@@ -319,9 +314,12 @@
             <span i18n-content="resolveTimezoneByGeoLocation"></span>
           </label>
         </div>
+        <label>
+          <input id="use-24hour-clock" pref="settings.clock.use_24hour_clock"
+              metric="Options_Use24HourClockCheckbox" type="checkbox">
+          <span i18n-content="use24HourClock"></span>
+        </label>
       </div>
-      <div id="time-synced-explanation" class="settings-row"
-          i18n-content="timeSyncedExplanation"></div>
       <div id="set-time" class="settings-row" hidden>
         <button id="set-time-button"
             i18n-content="setTimeButton"></button>
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 3efebf9f..8ba30db 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -407,6 +407,8 @@
         if (loadTimeData.getBoolean('enableTimeZoneTrackingOption')) {
           $('resolve-timezone-by-geolocation-selection').hidden = false;
           this.setSystemTimezoneManaged_(false);
+          $('timezone-value-select').disabled = loadTimeData.getBoolean(
+              'resolveTimezoneByGeolocationInitialValue');
         }
       }
 
@@ -2113,7 +2115,6 @@
      */
     setCanSetTime_: function(canSetTime) {
       // If the time has been network-synced, it cannot be set manually.
-      $('time-synced-explanation').hidden = canSetTime;
       $('set-time').hidden = !canSetTime;
     },
 
@@ -2192,6 +2193,7 @@
     'setMetricsReportingSettingVisibility',
     'setProfilesInfo',
     'setSpokenFeedbackCheckboxState',
+    'setSystemTimezoneManaged',
     'setThemesResetButtonEnabled',
     'setVirtualKeyboardCheckboxState',
     'setupPageZoomSelector',
diff --git a/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png b/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png
index 433b026..ddaabb1 100644
--- a/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png
+++ b/chrome/browser/resources/security_warnings/images/1x/brokenssl_red.png
Binary files differ
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2.css b/chrome/browser/resources/security_warnings/interstitial_v2.css
index a847191..920b644 100644
--- a/chrome/browser/resources/security_warnings/interstitial_v2.css
+++ b/chrome/browser/resources/security_warnings/interstitial_v2.css
@@ -31,9 +31,8 @@
   cursor: pointer;
   float: right;
   font-size: .875em;
-  height: 36px;
-  margin: -6px 0 0;
-  padding: 8px 24px;
+  margin: 0;
+  padding: 10px 24px;
   transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1);
 }
 
@@ -51,13 +50,14 @@
 }
 
 #debugging {
+  display: inline;
   overflow: auto;
 }
 
 .debugging-content {
   line-height: 1em;
   margin-bottom: 0;
-  margin-top: 0;
+  margin-top: 1em;
 }
 
 .debugging-title {
@@ -77,8 +77,8 @@
   background: inherit;
   border: 0;
   float: none;
-  margin: -6px 0 0;
-  padding: 0;
+  margin: 0;
+  padding: 10px 0;
   text-decoration: underline;
 }
 
@@ -86,16 +86,17 @@
   box-shadow: inherit;
 }
 
-#error-code {
-  color: black;
-  font-size: .825em;
-  opacity: .35;
+.error-code {
+  color: #777;
+  display: inline;
+  font-size: .86667em;
+  margin-top: 15px;
+  opacity: .5;
   text-transform: uppercase;
 }
 
 #error-debugging-info {
   font-size: 0.8em;
-  overflow: auto;
 }
 
 h1 {
@@ -141,6 +142,10 @@
   width: 100%;
 }
 
+#main-message > p {
+  display: inline;
+}
+
 #malware-opt-in {
   font-size: .875em;
   margin-top: 39px;
@@ -178,18 +183,16 @@
   box-shadow: 0 2px 3px rgba(0, 0, 0, .5);
 }
 
+.safe-browsing .error-code {
+  display: none;
+}
+
 .safe-browsing .icon {
   background-image: -webkit-image-set(
       url(images/1x/stop_sign.png) 1x,
       url(images/2x/stop_sign.png) 2x);
 }
 
-.secondary-button {
-  -webkit-margin-end: 16px;
-  background: #d9d9d9;
-  color: #696969;
-}
-
 .small-link {
   color: #696969;
   font-size: .875em;
@@ -239,7 +242,7 @@
   content: '';
   height: 4px;
   left: 2px;
-  opacity: 0.3;
+  opacity: 0;
   position: absolute;
   top: 3px;
   transform: rotate(-45deg);
@@ -254,9 +257,17 @@
   .interstitial-wrapper {
     padding: 0 10%;
   }
+
+  #error-debugging-info {
+    overflow: auto;
+  }
 }
 
 @media (max-height: 600px) {
+  .error-code {
+    margin-top: 10px;
+  }
+
   .interstitial-wrapper {
     margin-top: 13%;
   }
@@ -358,6 +369,10 @@
     width: 100%;
   }
 
+  .error-code {
+    margin-top: 0;
+  }
+
   #details {
     box-sizing: border-box;
     height: auto;
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2.html b/chrome/browser/resources/security_warnings/interstitial_v2.html
index e285441..b06fe1f 100644
--- a/chrome/browser/resources/security_warnings/interstitial_v2.html
+++ b/chrome/browser/resources/security_warnings/interstitial_v2.html
@@ -20,6 +20,10 @@
       <div id="main-message">
         <h1 i18n-content="heading"></h1>
         <p i18n-values=".innerHTML:primaryParagraph"></p>
+        <div id="debugging">
+          <div id="error-code" class="error-code"></div>
+          <div id="error-debugging-info" class="hidden"></div>
+        </div>
       </div>
       <div id="malware-opt-in" class="hidden">
         <div class="styled-checkbox">
@@ -39,10 +43,6 @@
     <div id="details" class="hidden">
       <p i18n-values=".innerHTML:explanationParagraph"></p>
       <p i18n-values=".innerHTML:finalParagraph" id="final-paragraph"></p>
-      <div id="debugging">
-        <p id="error-code"></p>
-        <div id="error-debugging-info" class="hidden"></div>
-      </div>
     </div>
   </div>
 </body>
diff --git a/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js b/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js
index af0a21d..c482d6f 100644
--- a/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js
+++ b/chrome/browser/resources/security_warnings/interstitial_v2_mobile.js
@@ -15,6 +15,7 @@
       '(orientation: portrait), (max-width: 736px) and ' +
       '(max-height: 420px) and (orientation: landscape)';
   var detailsHidden = helpOuterBox.classList.contains('hidden');
+  var runnerContainer = document.querySelector('.runner-container');
 
   // Check for change in nav status.
   if (mobileNav != window.matchMedia(mediaQuery).matches) {
@@ -24,10 +25,16 @@
     if (mobileNav) {
       mainContent.classList.toggle('hidden', !detailsHidden);
       helpOuterBox.classList.toggle('hidden', detailsHidden);
+      if (runnerContainer) {
+        runnerContainer.classList.toggle('hidden', !detailsHidden);
+      }
     } else if (!detailsHidden) {
       // Non mobile nav with visible details.
       mainContent.classList.remove('hidden');
       helpOuterBox.classList.remove('hidden');
+      if (runnerContainer) {
+        runnerContainer.classList.remove('hidden');
+      }
     }
   }
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 237b239bb..538f50a 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -47,6 +47,7 @@
     "//components/app_modal",
     "//components/auto_login_parser",
     "//components/dom_distiller/webui",
+    "//components/feedback/proto",
     "//components/history/core/browser:proto",
     "//components/invalidation",
     "//components/onc",
@@ -134,7 +135,6 @@
                     "//chrome")
     deps += [
       "//components/copresence",
-      "//components/feedback/proto",
       "//device/bluetooth",
       "//third_party/libusb",
     ]
@@ -228,15 +228,28 @@
     }
     if (is_mac) {
       if (mac_views_browser) {
+        sources += [ "views/apps/chrome_app_window_client_views_mac.mm" ]
         sources -= [
+          "cocoa/apps/chrome_app_window_client_cocoa.mm",
           "cocoa/bookmarks/bookmark_drag_drop_cocoa.mm",
           "cocoa/browser_window_factory_cocoa.mm",
           "cocoa/tab_dialogs_cocoa.mm",
         ]
+        deps += [ "//extensions/components/native_app_window" ]
       } else {
         sources -= [
+          "views/apps/chrome_native_app_window_views.cc",
+          "views/apps/chrome_native_app_window_views.h",
+          "views/apps/desktop_keyboard_capture.cc",
+          "views/apps/desktop_keyboard_capture.h",
+          "views/apps/keyboard_hook_handler.cc",
+          "views/apps/keyboard_hook_handler.h",
           "views/bookmarks/bookmark_drag_drop_views.cc",
+          "views/extensions/extension_keybinding_registry_views.cc",
+          "views/extensions/extension_keybinding_registry_views.h",
           "views/frame/browser_window_factory.cc",
+          "views/frame/taskbar_decorator.cc",
+          "views/frame/taskbar_decorator.h",
           "views/tab_dialogs_views.cc",
         ]
       }
@@ -313,6 +326,7 @@
     ]
     deps -= [
       "//chrome/browser/ui/views",
+      "//components/feedback/proto",
       "//ui/events",
     ]
     sources += rebase_path(gypi_values.chrome_browser_ui_android_sources,
@@ -345,7 +359,10 @@
   if (is_win) {
     sources +=
         rebase_path(gypi_values.chrome_browser_ui_win_sources, ".", "//chrome")
-    sources -= [ "views/frame/taskbar_decorator.cc" ]
+    sources -= [
+      "views/apps/keyboard_hook_handler.cc",
+      "views/frame/taskbar_decorator.cc",
+    ]
     public_deps += [
       "//ui/views",
       "//ui/views/controls/webview",
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
index efaa710..40a960e 100644
--- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
+++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.cc
@@ -88,9 +88,13 @@
   Java_CardUnmaskBridge_disableAndWaitForVerification(env, java_object_.obj());
 }
 
-void CardUnmaskPromptViewAndroid::GotVerificationResult(bool success) {
+void CardUnmaskPromptViewAndroid::GotVerificationResult(
+    const base::string16& error_message,
+    bool allow_retry) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  Java_CardUnmaskBridge_verificationFinished(env, java_object_.obj(), success);
+  // TODO(estade): pass |error_message| and |allow_retry|.
+  Java_CardUnmaskBridge_verificationFinished(env, java_object_.obj(),
+                                             error_message.empty());
 }
 
 // static
diff --git a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
index 21281f8..66d3e2d 100644
--- a/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
+++ b/chrome/browser/ui/android/autofill/card_unmask_prompt_view_android.h
@@ -32,7 +32,8 @@
   // CardUnmaskPromptView implementation.
   void ControllerGone() override;
   void DisableAndWaitForVerification() override;
-  void GotVerificationResult(bool success) override;
+  void GotVerificationResult(const base::string16& error_message,
+                             bool allow_retry) override;
 
   static bool Register(JNIEnv* env);
 
diff --git a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
index f07f122..ac0ae5f 100644
--- a/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_window_launcher_controller.cc
@@ -145,6 +145,11 @@
 }
 
 void AppWindowLauncherController::RegisterApp(AppWindow* app_window) {
+  // Windows created by IME extension should be treated the same way as the
+  // virtual keyboard window, which does not register itself in launcher.
+  if (app_window->is_ime_window())
+    return;
+
   aura::Window* window = app_window->GetNativeWindow();
   // Get the app's shelf identifier and add an entry to the map.
   DCHECK(window_to_app_shelf_id_map_.find(window) ==
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
index 28bed7c..7373454 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos_unittest.cc
@@ -8,10 +8,12 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_session_state_delegate.h"
 #include "ash/test/test_shell_delegate.h"
+#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_notification_blocker_chromeos.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/user_info.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
@@ -23,7 +25,9 @@
   MultiUserNotificationBlockerChromeOSTest()
       : state_changed_count_(0),
         testing_profile_manager_(TestingBrowserProcess::GetGlobal()),
-        window_id_(0) {}
+        window_id_(0),
+        fake_user_manager_(new user_manager::FakeUserManager),
+        user_manager_enabler_(fake_user_manager_) {}
   ~MultiUserNotificationBlockerChromeOSTest() override {}
 
   // ash::test::AshTestBase overrides:
@@ -128,6 +132,10 @@
   TestingProfileManager testing_profile_manager_;
   int window_id_;
 
+  user_manager::FakeUserManager* fake_user_manager_;  // Not owned.
+
+  chromeos::ScopedUserManagerEnabler user_manager_enabler_;
+
   DISALLOW_COPY_AND_ASSIGN(MultiUserNotificationBlockerChromeOSTest);
 };
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index badf4a53..e6834781b 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -18,10 +18,12 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/time/time.h"
+#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 #include "chrome/browser/ui/ash/multi_user/user_switch_animator_chromeos.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/user_manager/fake_user_manager.h"
 #include "components/user_manager/user_info.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -39,7 +41,9 @@
  public:
   MultiUserWindowManagerChromeOSTest()
       : multi_user_window_manager_(NULL),
-        session_state_delegate_(NULL) {}
+        session_state_delegate_(NULL),
+        fake_user_manager_(new user_manager::FakeUserManager),
+        user_manager_enabler_(fake_user_manager_) {}
 
   void SetUp() override;
   void TearDown() override;
@@ -158,6 +162,10 @@
   // The session state delegate.
   ash::test::TestSessionStateDelegate* session_state_delegate_;
 
+  user_manager::FakeUserManager* fake_user_manager_;  // Not owned.
+
+  chromeos::ScopedUserManagerEnabler user_manager_enabler_;
+
   // The maximized window manager (if enabled).
   scoped_ptr<MaximizeModeWindowManager> maximize_mode_window_manager_;
 
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
index 62b044a0..9b5335cc 100644
--- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
+++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.cc
@@ -44,9 +44,39 @@
   card_unmask_view_ = CardUnmaskPromptView::CreateAndShow(this);
 }
 
-void CardUnmaskPromptControllerImpl::OnVerificationResult(bool success) {
-  if (card_unmask_view_)
-    card_unmask_view_->GotVerificationResult(success);
+void CardUnmaskPromptControllerImpl::OnVerificationResult(
+    AutofillClient::GetRealPanResult result) {
+  if (!card_unmask_view_)
+    return;
+
+  base::string16 error_message;
+  bool allow_retry = true;
+  switch (result) {
+    case AutofillClient::SUCCESS:
+      break;
+
+    case AutofillClient::TRY_AGAIN_FAILURE: {
+      error_message = l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_TRY_AGAIN);
+      break;
+    }
+
+    case AutofillClient::PERMANENT_FAILURE: {
+      error_message = l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_PERMANENT);
+      allow_retry = false;
+      break;
+    }
+
+    case AutofillClient::NETWORK_ERROR: {
+      error_message = l10n_util::GetStringUTF16(
+          IDS_AUTOFILL_CARD_UNMASK_PROMPT_ERROR_NETWORK);
+      allow_retry = false;
+      break;
+    }
+  }
+
+  card_unmask_view_->GotVerificationResult(error_message, allow_retry);
 }
 
 void CardUnmaskPromptControllerImpl::OnUnmaskDialogClosed() {
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h
index e2d1b975..a991c7d73 100644
--- a/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h
+++ b/chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller.h"
+#include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/card_unmask_delegate.h"
 #include "components/autofill/core/browser/credit_card.h"
 
@@ -24,7 +25,7 @@
   void ShowPrompt(const CreditCard& card,
                   base::WeakPtr<CardUnmaskDelegate> delegate);
   // The CVC the user entered went through validation.
-  void OnVerificationResult(bool success);
+  void OnVerificationResult(AutofillClient::GetRealPanResult result);
 
   // CardUnmaskPromptController implementation.
   void OnUnmaskDialogClosed() override;
diff --git a/chrome/browser/ui/autofill/card_unmask_prompt_view.h b/chrome/browser/ui/autofill/card_unmask_prompt_view.h
index de3a2ff..6754856f 100644
--- a/chrome/browser/ui/autofill/card_unmask_prompt_view.h
+++ b/chrome/browser/ui/autofill/card_unmask_prompt_view.h
@@ -19,7 +19,8 @@
 
   virtual void ControllerGone() = 0;
   virtual void DisableAndWaitForVerification() = 0;
-  virtual void GotVerificationResult(bool success) = 0;
+  virtual void GotVerificationResult(const base::string16& error_message,
+                                     bool allow_retry) = 0;
 
  protected:
   CardUnmaskPromptView() {}
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 37c8c48..23983d92 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -136,8 +136,8 @@
   unmask_controller_.ShowPrompt(card, delegate);
 }
 
-void ChromeAutofillClient::OnUnmaskVerificationResult(bool success) {
-  unmask_controller_.OnVerificationResult(success);
+void ChromeAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
+  unmask_controller_.OnVerificationResult(result);
 }
 
 void ChromeAutofillClient::ConfirmSaveCreditCard(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index 3bc63aa4..1ce82b7 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -51,7 +51,7 @@
   void ShowAutofillSettings() override;
   void ShowUnmaskPrompt(const CreditCard& card,
                         base::WeakPtr<CardUnmaskDelegate> delegate) override;
-  void OnUnmaskVerificationResult(bool success) override;
+  void OnUnmaskVerificationResult(GetRealPanResult result) override;
   void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 53dfccd..1dc929de 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1339,8 +1339,7 @@
     return;
 
   // GetDownloadShelf creates the download shelf if it was not yet created.
-  DownloadShelf* shelf = window()->GetDownloadShelf();
-  shelf->AddDownload(download);
+  window()->GetDownloadShelf()->AddDownload(download);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
index 02ff9cf..88d1e630 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.h
@@ -27,7 +27,8 @@
   // CardUnmaskPromptView implementation:
   void ControllerGone() override;
   void DisableAndWaitForVerification() override;
-  void GotVerificationResult(bool success) override;
+  void GotVerificationResult(const base::string16& error_message,
+                             bool allow_retry) override;
 
   // ConstrainedWindowMacDelegate implementation:
   void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override;
diff --git a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
index cc8897d4..5d30a79 100644
--- a/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
+++ b/chrome/browser/ui/cocoa/autofill/card_unmask_prompt_view_bridge.mm
@@ -49,7 +49,9 @@
 void CardUnmaskPromptViewBridge::DisableAndWaitForVerification() {
 }
 
-void CardUnmaskPromptViewBridge::GotVerificationResult(bool success) {
+void CardUnmaskPromptViewBridge::GotVerificationResult(
+    const base::string16& error_message,
+    bool allow_retry) {
 }
 
 void CardUnmaskPromptViewBridge::OnConstrainedWindowClosed(
diff --git a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
index 02995b5..e5f6a9a 100644
--- a/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
+++ b/chrome/browser/ui/cocoa/certificate_viewer_mac.mm
@@ -197,6 +197,10 @@
   // NOOP
 }
 
+- (NSWindow*)sheetWindow {
+  return panel_;
+}
+
 - (void)onConstrainedWindowClosed {
   panel_.reset();
   constrainedWindow_.reset();
diff --git a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
index d515508..2b5c1407 100644
--- a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
@@ -72,9 +72,7 @@
   void ReleaseWebContentsOnDialogClose() override {
     return impl_->ReleaseWebContentsOnDialogClose();
   }
-  NativeWebContentsModalDialog GetNativeDialog() override {
-    return constrained_window_->GetNativeDialog();
-  }
+  NativeWebContentsModalDialog GetNativeDialog() override { return window_; }
   WebContents* GetWebContents() override { return impl_->GetWebContents(); }
   gfx::Size GetMinimumSize() const override {
     NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
index 4300036..d6d12c9 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.mm
@@ -73,4 +73,8 @@
   [customWindow_ setFrameOrigin:origin];
 }
 
+- (NSWindow*)sheetWindow {
+  return customWindow_;
+}
+
 @end
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
index 6f3f222..e3d981e 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h
@@ -7,13 +7,11 @@
 
 #import <Cocoa/Cocoa.h>
 
-#include "base/mac/scoped_nsobject.h"
-#include "components/web_modal/native_web_contents_modal_dialog.h"
-
 namespace content {
 class WebContents;
 }
 class ConstrainedWindowMac;
+class SingleWebContentsDialogManagerCocoa;
 @protocol ConstrainedWindowSheet;
 
 // A delegate for a constrained window. The delegate is notified when the
@@ -28,29 +26,25 @@
 // should delete the instance when the window is closed.
 class ConstrainedWindowMac {
  public:
-  ConstrainedWindowMac(
-      ConstrainedWindowMacDelegate* delegate,
-      content::WebContents* web_contents,
-      id<ConstrainedWindowSheet> sheet);
-  virtual ~ConstrainedWindowMac();
+  ConstrainedWindowMac(ConstrainedWindowMacDelegate* delegate,
+                       content::WebContents* web_contents,
+                       id<ConstrainedWindowSheet> sheet);
+  ~ConstrainedWindowMac();
 
-  void ShowWebContentsModalDialog();
-  // Closes the constrained window and deletes this instance.
+  // Closes the constrained window.
   void CloseWebContentsModalDialog();
-  void FocusWebContentsModalDialog();
-  void PulseWebContentsModalDialog();
-  web_modal::NativeWebContentsModalDialog GetNativeDialog();
+
+  SingleWebContentsDialogManagerCocoa* manager() const { return manager_; }
+  void set_manager(SingleWebContentsDialogManagerCocoa* manager) {
+    manager_ = manager;
+  }
+
+  // Called by |manager_| when the dialog is closing.
+  void OnDialogClosing();
 
  private:
   ConstrainedWindowMacDelegate* delegate_;  // weak, owns us.
-
-  // The WebContents that owns and constrains this ConstrainedWindowMac. Weak.
-  content::WebContents* web_contents_;
-
-  base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
-
-  // This is true if the constrained window has been shown.
-  bool shown_;
+  SingleWebContentsDialogManagerCocoa* manager_;  // weak, owned by WCMDM.
 };
 
 #endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_MAC_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
index 3c9dc59..1da08e0 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.mm
@@ -4,89 +4,46 @@
 
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "base/logging.h"
-#include "chrome/browser/ui/browser_finder.h"
-#include "chrome/browser/ui/browser_window.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
-#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
-#include "components/web_modal/popup_manager.h"
+#import "chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h"
 #include "components/web_modal/web_contents_modal_dialog_manager.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
 #include "extensions/browser/guest_view/guest_view_base.h"
 
 using web_modal::WebContentsModalDialogManager;
-using web_modal::NativeWebContentsModalDialog;
 
 ConstrainedWindowMac::ConstrainedWindowMac(
     ConstrainedWindowMacDelegate* delegate,
     content::WebContents* web_contents,
     id<ConstrainedWindowSheet> sheet)
-    : delegate_(delegate),
-      web_contents_(NULL),
-      sheet_([sheet retain]),
-      shown_(false) {
-  DCHECK(web_contents);
+    : delegate_(delegate) {
+  DCHECK(sheet);
   extensions::GuestViewBase* guest_view =
       extensions::GuestViewBase::FromWebContents(web_contents);
   // For embedded WebContents, use the embedder's WebContents for constrained
   // window.
-  web_contents_ = guest_view && guest_view->embedder_web_contents() ?
-                      guest_view->embedder_web_contents() : web_contents;
-  DCHECK(sheet_.get());
-  web_modal::PopupManager* popup_manager =
-      web_modal::PopupManager::FromWebContents(web_contents_);
-  if (popup_manager)
-    popup_manager->ShowModalDialog(this, web_contents_);
+  web_contents = guest_view && guest_view->embedder_web_contents() ?
+                    guest_view->embedder_web_contents() : web_contents;
+
+  auto manager = WebContentsModalDialogManager::FromWebContents(web_contents);
+  scoped_ptr<SingleWebContentsDialogManagerCocoa> native_manager(
+      new SingleWebContentsDialogManagerCocoa(this, sheet, manager));
+  manager->ShowDialogWithManager([sheet sheetWindow], native_manager.Pass());
 }
 
 ConstrainedWindowMac::~ConstrainedWindowMac() {
   CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-}
-
-void ConstrainedWindowMac::ShowWebContentsModalDialog() {
-  if (shown_)
-    return;
-
-  NSWindow* parent_window = web_contents_->GetTopLevelNativeWindow();
-  NSView* parent_view = GetSheetParentViewForWebContents(web_contents_);
-  if (!parent_window || !parent_view)
-    return;
-
-  shown_ = true;
-  ConstrainedWindowSheetController* controller =
-      [ConstrainedWindowSheetController
-          controllerForParentWindow:parent_window];
-  [controller showSheet:sheet_ forParentView:parent_view];
+  DCHECK(!manager_);
 }
 
 void ConstrainedWindowMac::CloseWebContentsModalDialog() {
-  [[ConstrainedWindowSheetController controllerForSheet:sheet_]
-      closeSheet:sheet_];
-  // TODO(gbillock): get this object in config, not from a global.
-  WebContentsModalDialogManager* web_contents_modal_dialog_manager =
-      WebContentsModalDialogManager::FromWebContents(web_contents_);
+  if (manager_)
+    manager_->Close();
+}
 
-  // Will result in the delegate being deleted.
+void ConstrainedWindowMac::OnDialogClosing() {
   if (delegate_)
     delegate_->OnConstrainedWindowClosed(this);
-
-  // Will cause this object to be deleted.
-  web_contents_modal_dialog_manager->WillClose(this);
-}
-
-void ConstrainedWindowMac::FocusWebContentsModalDialog() {
-}
-
-void ConstrainedWindowMac::PulseWebContentsModalDialog() {
-  [[ConstrainedWindowSheetController controllerForSheet:sheet_]
-      pulseSheet:sheet_];
-}
-
-NativeWebContentsModalDialog ConstrainedWindowMac::GetNativeDialog() {
-  // TODO(wittman): Ultimately this should be changed to the
-  // ConstrainedWindowSheet pointer, in conjunction with the corresponding
-  // changes to NativeWebContentsModalDialogManagerCocoa.
-  return this;
 }
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
index 2352af0..4549556 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet.h
@@ -24,6 +24,8 @@
 
 - (void)updateSheetPosition;
 
+@property(readonly, nonatomic) NSWindow* sheetWindow;
+
 @end
 
 #endif  // CHROME_BROWSER_UI_COCOA_CONSTRAINED_WINDOW_CONSTRAINED_WINDOW_SHEET_H_
diff --git a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
index e8939b8e..aeeeb92 100644
--- a/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller_unittest.mm
@@ -56,6 +56,10 @@
 - (void)updateSheetPosition {
 }
 
+- (NSWindow*)sheetWindow {
+  return [alert_ window];
+}
+
 - (void)alertDidEnd:(NSAlert *)alert
          returnCode:(NSInteger)returnCode
             ctxInfo:(void *)contextInfo {
diff --git a/chrome/browser/ui/cocoa/download/download_item_mac.mm b/chrome/browser/ui/cocoa/download/download_item_mac.mm
index bf1ebc9..b39137c 100644
--- a/chrome/browser/ui/cocoa/download/download_item_mac.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_mac.mm
@@ -30,6 +30,11 @@
 void DownloadItemMac::OnDownloadUpdated(content::DownloadItem* download) {
   DCHECK_EQ(download, download_model_.download());
 
+  if (!download_model_.ShouldShowInShelf()) {
+    [item_controller_ remove];  // We're deleted now!
+    return;
+  }
+
   if ([item_controller_ isDangerousMode] && !download_model_.IsDangerous()) {
     // We have been approved.
     [item_controller_ clearDangerousMode];
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
index 12ee052..4c5aac73 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_base_controller.mm
@@ -178,7 +178,7 @@
       NSMaxX([anchor bounds]) - kMenuXOffsetAdjust :
       NSMidX([anchor bounds]);
   NSPoint point = NSMakePoint(anchorX,
-                              NSMaxY([anchor bounds]) - kMenuYOffsetAdjust);
+                              NSMaxY([anchor bounds]) + kMenuYOffsetAdjust);
   point = [anchor convertPoint:point toView:nil];
   point = [[anchor window] convertBaseToScreen:point];
 
diff --git a/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm b/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm
index 588fdea..3d0f39d8 100644
--- a/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.mm
@@ -5,6 +5,7 @@
 #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h"
 
 #include "base/mac/bundle_locations.h"
+#include "base/mac/sdk_forward_declarations.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/avatar_menu.h"
@@ -159,6 +160,8 @@
     NSRect frame = [nameField frame];
     frame.size.width = kMaxItemTextWidth;
     [nameField setFrame:frame];
+    if ([nameField respondsToSelector:@selector(setAllowsExpansionToolTips:)])
+      [nameField setAllowsExpansionToolTips:YES];
   }
   *widthAdjust = std::max(*widthAdjust, delta.width);
 
diff --git a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
index 6844522..27dccbc 100644
--- a/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
+++ b/chrome/browser/ui/cocoa/profiles/profile_chooser_controller.mm
@@ -701,6 +701,13 @@
           IDS_PROFILES_NEW_AVATAR_MENU_EDIT_NAME_ACCESSIBLE_NAME,
           base::SysNSStringToUTF16(profileName))
                                     forAttribute:NSAccessibilityTitleAttribute];
+
+      NSSize textSize = [profileName sizeWithAttributes:@{
+        NSFontAttributeName : [profileNameTextField_ font]
+      }];
+
+      if (textSize.width > frameRect.size.width - [hoverImage size].width * 2)
+        [self setToolTip:profileName];
     }
 
     [[self cell] accessibilitySetOverrideValue:NSAccessibilityButtonRole
@@ -1805,6 +1812,16 @@
   [profileButton setTarget:self];
   [profileButton setAction:@selector(switchToProfile:)];
 
+  NSSize textSize = [[profileButton title] sizeWithAttributes:@{
+    NSFontAttributeName : [profileButton font]
+  }];
+
+  CGFloat availableWidth = rect.size.width - kSmallImageSide -
+                           kImageTitleSpacing - kHorizontalSpacing;
+
+  if (std::ceil(textSize.width) > availableWidth)
+    [profileButton setToolTip:[profileButton title]];
+
   return profileButton.autorelease();
 }
 
diff --git a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h
new file mode 100644
index 0000000..55efe46
--- /dev/null
+++ b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_
+#define CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_
+
+#import "base/mac/scoped_nsobject.h"
+#include "components/web_modal/single_web_contents_dialog_manager.h"
+
+class ConstrainedWindowMac;
+@protocol ConstrainedWindowSheet;
+
+// Cocoa implementation of web_modal::SingleWebContentsDialogManager.
+class SingleWebContentsDialogManagerCocoa
+    : public web_modal::SingleWebContentsDialogManager {
+ public:
+  SingleWebContentsDialogManagerCocoa(
+      ConstrainedWindowMac* client,
+      id<ConstrainedWindowSheet> sheet,
+      web_modal::SingleWebContentsDialogManagerDelegate* delegate);
+  ~SingleWebContentsDialogManagerCocoa() override;
+
+  // SingleWebContentsDialogManager overrides.
+  void Show() override;
+  void Hide() override;
+  void Close() override;
+  void Focus() override;
+  void Pulse() override;
+  void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override;
+  web_modal::NativeWebContentsModalDialog dialog() override;
+
+ private:
+  ConstrainedWindowMac* client_;  // Weak. Can be null.
+  base::scoped_nsprotocol<id<ConstrainedWindowSheet>> sheet_;
+  // Weak. Owns this.
+  web_modal::SingleWebContentsDialogManagerDelegate* delegate_;
+  bool shown_;
+
+  DISALLOW_COPY_AND_ASSIGN(SingleWebContentsDialogManagerCocoa);
+};
+
+#endif  // CHROME_BROWSER_UI_COCOA_SINGLE_WEB_CONTENTS_DIALOG_MANAGER_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
new file mode 100644
index 0000000..3bd76bd
--- /dev/null
+++ b/chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome/browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h"
+
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
+#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
+#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+
+using web_modal::NativeWebContentsModalDialog;
+using web_modal::SingleWebContentsDialogManagerDelegate;
+
+SingleWebContentsDialogManagerCocoa::SingleWebContentsDialogManagerCocoa(
+    ConstrainedWindowMac* client,
+    id<ConstrainedWindowSheet> sheet,
+    web_modal::SingleWebContentsDialogManagerDelegate* delegate)
+    : client_(client),
+      sheet_([sheet retain]),
+      delegate_(delegate),
+      shown_(false) {
+  if (client)
+    client->set_manager(this);
+}
+
+SingleWebContentsDialogManagerCocoa::~SingleWebContentsDialogManagerCocoa() {
+}
+
+void SingleWebContentsDialogManagerCocoa::Show() {
+  if (shown_)
+    return;
+
+  content::WebContents* web_contents = delegate_->GetWebContents();
+  NSWindow* parent_window = web_contents->GetTopLevelNativeWindow();
+  NSView* parent_view = GetSheetParentViewForWebContents(web_contents);
+  if (!parent_window || !parent_view)
+    return;
+
+  shown_ = true;
+  [[ConstrainedWindowSheetController controllerForParentWindow:parent_window]
+      showSheet:sheet_ forParentView:parent_view];
+}
+
+void SingleWebContentsDialogManagerCocoa::Hide() {
+}
+
+void SingleWebContentsDialogManagerCocoa::Close() {
+  [[ConstrainedWindowSheetController controllerForSheet:sheet_]
+      closeSheet:sheet_];
+  if (client_) {
+    client_->set_manager(nullptr);
+    client_->OnDialogClosing();  // |client_| might delete itself here.
+    client_ = nullptr;
+  }
+  delegate_->WillClose(dialog());
+}
+
+void SingleWebContentsDialogManagerCocoa::Focus() {
+}
+
+void SingleWebContentsDialogManagerCocoa::Pulse() {
+  [[ConstrainedWindowSheetController controllerForSheet:sheet_]
+      pulseSheet:sheet_];
+}
+
+void SingleWebContentsDialogManagerCocoa::HostChanged(
+    web_modal::WebContentsModalDialogHost* new_host) {
+}
+
+NativeWebContentsModalDialog SingleWebContentsDialogManagerCocoa::dialog() {
+  return [sheet_ sheetWindow];
+}
+
+namespace web_modal {
+
+SingleWebContentsDialogManager*
+WebContentsModalDialogManager::CreateNativeWebModalManager(
+    NativeWebContentsModalDialog dialog,
+    SingleWebContentsDialogManagerDelegate* delegate) {
+  base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
+      [[CustomConstrainedWindowSheet alloc] initWithCustomWindow:dialog]);
+  return new SingleWebContentsDialogManagerCocoa(nullptr, sheet, delegate);
+}
+
+}  // namespace web_modal
diff --git a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
index 9d471b9..a8d7912 100644
--- a/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
+++ b/chrome/browser/ui/cocoa/ssl_client_certificate_selector_cocoa.mm
@@ -227,6 +227,10 @@
   // NOOP
 }
 
+- (NSWindow*)sheetWindow {
+  return panel_;
+}
+
 - (void)onConstrainedWindowClosed {
   observer_->StopObserving();
   panel_.reset();
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
index 667d952..7273b0d 100644
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ b/chrome/browser/ui/cocoa/status_bubble_mac.mm
@@ -177,16 +177,18 @@
   url_ = url;
   languages_ = languages;
 
-  NSRect frame = [window_ frame];
+  CGFloat bubble_width = NSWidth([window_ frame]);
 
   // Reset frame size when bubble is hidden.
   if (state_ == kBubbleHidden) {
     is_expanded_ = false;
-    frame.size.width = NSWidth(CalculateWindowFrame(/*expand=*/false));
+    NSRect frame = [window_ frame];
+    frame.size = ui::kWindowSizeDeterminedLater.size;
     [window_ setFrame:frame display:NO];
+    bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false));
   }
 
-  int text_width = static_cast<int>(NSWidth(frame) -
+  int text_width = static_cast<int>(bubble_width -
                                     kBubbleViewTextPositionX -
                                     kTextPadding);
 
@@ -260,8 +262,10 @@
     show = false;
 
   if (show) {
-    UpdateSizeAndPosition();
+    // Call StartShowing() first to update the current bubble state before
+    // calculating a new size.
     StartShowing();
+    UpdateSizeAndPosition();
   } else {
     StartHiding();
   }
@@ -284,21 +288,22 @@
     }
   }
 
+  NSRect frame = CalculateWindowFrame(/*expand=*/false);
   if (!fade_out) {
     // No animation is in progress, so the opacity can be set directly.
     [window_ setAlphaValue:0.0];
     SetState(kBubbleHidden);
+    frame.size = ui::kWindowSizeDeterminedLater.size;
   }
 
   // Stop any width animation and reset the bubble size.
   if (!immediate_) {
     [NSAnimationContext beginGrouping];
     [[NSAnimationContext currentContext] setDuration:kMinimumTimeInterval];
-    [[window_ animator] setFrame:CalculateWindowFrame(/*expand=*/false)
-                         display:NO];
+    [[window_ animator] setFrame:frame display:NO];
     [NSAnimationContext endGrouping];
   } else {
-    [window_ setFrame:CalculateWindowFrame(/*expand=*/false) display:NO];
+    [window_ setFrame:frame display:NO];
   }
 
   [status_text_ release];
@@ -717,6 +722,14 @@
   if (!window_)
     return;
 
+  // Hidden bubbles always have size equal to ui::kWindowSizeDeterminedLater.
+  if (state_ == kBubbleHidden) {
+    NSRect frame = [window_ frame];
+    frame.size = ui::kWindowSizeDeterminedLater.size;
+    [window_ setFrame:frame display:YES];
+    return;
+  }
+
   SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false),
                         GetMouseLocation());
 }
diff --git a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
index 48d2f40..19ff9d2a4 100644
--- a/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
+++ b/chrome/browser/ui/cocoa/tab_modal_confirm_dialog_mac.h
@@ -7,6 +7,7 @@
 
 #import <Cocoa/Cocoa.h>
 
+#import "base/mac/scoped_nsobject.h"
 #include "base/memory/scoped_ptr.h"
 #include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
 #include "chrome/browser/ui/tab_modal_confirm_dialog.h"
diff --git a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm b/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm
deleted file mode 100644
index 5d025f6c..0000000
--- a/chrome/browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) 2013 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/web_modal/web_contents_modal_dialog_manager.h"
-
-#include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
-#include "components/web_modal/single_web_contents_dialog_manager.h"
-
-using web_modal::NativeWebContentsModalDialog;
-
-namespace {
-
-class NativeWebContentsModalDialogManagerCocoa
-    : public web_modal::SingleWebContentsDialogManager {
- public:
-  NativeWebContentsModalDialogManagerCocoa(
-      NativeWebContentsModalDialog dialog)
-      : dialog_(dialog) {
-  }
-
-  ~NativeWebContentsModalDialogManagerCocoa() override {}
-
-  // SingleWebContentsDialogManager overrides
-  void Show() override {
-    GetConstrainedWindowMac(dialog())->ShowWebContentsModalDialog();
-  }
-
-  void Hide() override {}
-
-  void Close() override {
-    GetConstrainedWindowMac(dialog())->CloseWebContentsModalDialog();
-  }
-
-  void Focus() override {
-    GetConstrainedWindowMac(dialog())->FocusWebContentsModalDialog();
-  }
-
-  void Pulse() override {
-    GetConstrainedWindowMac(dialog())->PulseWebContentsModalDialog();
-  }
-
-  void HostChanged(web_modal::WebContentsModalDialogHost* new_host) override {}
-
-  NativeWebContentsModalDialog dialog() override { return dialog_; }
-
- private:
-  static ConstrainedWindowMac* GetConstrainedWindowMac(
-      NativeWebContentsModalDialog dialog) {
-    return static_cast<ConstrainedWindowMac*>(dialog);
-  }
-
-  // In mac this is a pointer to a ConstrainedWindowMac.
-  // TODO(gbillock): Replace this casting system with a more typesafe call path.
-  NativeWebContentsModalDialog dialog_;
-
-  DISALLOW_COPY_AND_ASSIGN(NativeWebContentsModalDialogManagerCocoa);
-};
-
-}  // namespace
-
-namespace web_modal {
-
-SingleWebContentsDialogManager*
-    WebContentsModalDialogManager::CreateNativeWebModalManager(
-        NativeWebContentsModalDialog dialog,
-        SingleWebContentsDialogManagerDelegate* native_delegate) {
-  return new NativeWebContentsModalDialogManagerCocoa(dialog);
-}
-
-}  // namespace web_modal
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
index 0df4fa7..23c1275 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model.cc
@@ -1199,6 +1199,7 @@
     return;
   // Reset this embedder's entry to default for each of the requesting
   // origins currently on the page.
+  const GURL& embedder_url = web_contents()->GetURL();
   TabSpecificContentSettings* content_settings =
       TabSpecificContentSettings::FromWebContents(web_contents());
   const ContentSettingsUsagesState::StateMap& state_map =
@@ -1210,7 +1211,7 @@
        state_map.begin(); it != state_map.end(); ++it) {
     settings_map->SetContentSetting(
         ContentSettingsPattern::FromURLNoWildcard(it->first),
-        ContentSettingsPattern::Wildcard(),
+        ContentSettingsPattern::FromURLNoWildcard(embedder_url),
         CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
         std::string(),
         CONTENT_SETTING_DEFAULT);
diff --git a/chrome/browser/ui/views/apps/chrome_apps_client_views.cc b/chrome/browser/ui/views/apps/chrome_app_window_client_views.cc
similarity index 100%
rename from chrome/browser/ui/views/apps/chrome_apps_client_views.cc
rename to chrome/browser/ui/views/apps/chrome_app_window_client_views.cc
diff --git a/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm b/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm
new file mode 100644
index 0000000..c87fc4f
--- /dev/null
+++ b/chrome/browser/ui/views/apps/chrome_app_window_client_views_mac.mm
@@ -0,0 +1,16 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/apps/chrome_app_window_client.h"
+
+#include "chrome/browser/ui/views/apps/chrome_native_app_window_views.h"
+
+// static
+extensions::NativeAppWindow* ChromeAppWindowClient::CreateNativeAppWindowImpl(
+    extensions::AppWindow* app_window,
+    const extensions::AppWindow::CreateParams& params) {
+  ChromeNativeAppWindowViews* window = new ChromeNativeAppWindowViews;
+  window->Init(app_window, params);
+  return window;
+}
diff --git a/chrome/browser/ui/views/apps/chrome_apps_client_views_win.cc b/chrome/browser/ui/views/apps/chrome_app_window_client_views_win.cc
similarity index 100%
rename from chrome/browser/ui/views/apps/chrome_apps_client_views_win.cc
rename to chrome/browser/ui/views/apps/chrome_app_window_client_views_win.cc
diff --git a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
index 83223c6..e5903371 100644
--- a/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
+++ b/chrome/browser/ui/views/autofill/card_unmask_prompt_views.cc
@@ -11,6 +11,9 @@
 #include "chrome/browser/ui/views/autofill/decorated_textfield.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "grit/theme_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -70,29 +73,48 @@
     Layout();
   }
 
-  void GotVerificationResult(bool success) override {
-    if (success) {
+  void GotVerificationResult(const base::string16& error_message,
+                             bool allow_retry) override {
+    if (!error_message.empty()) {
       progress_label_->SetText(base::ASCIIToUTF16("Success!"));
       base::MessageLoop::current()->PostDelayedTask(
           FROM_HERE, base::Bind(&CardUnmaskPromptViews::ClosePrompt,
                                 base::Unretained(this)),
           base::TimeDelta::FromSeconds(1));
     } else {
-      SetInputsEnabled(true);
-      SetInputsInvalid(true);
+      SetInputsEnabled(allow_retry);
+
+      // If there is more than one input showing, don't mark anything as invalid
+      // since we don't know the location of the problem.
+      if (controller_->ShouldRequestExpirationDate())
+        cvc_input_->SetInvalid(true);
+
       // TODO(estade): it's somewhat jarring when the error comes back too
       // quickly.
       progress_overlay_->SetVisible(false);
       // TODO(estade): When do we hide |error_label_|?
-      error_label_->SetText(
-          base::ASCIIToUTF16("Verification error. Please try again."));
+      error_label_->SetMultiLine(true);
+      error_label_->SetText(error_message);
+
+      // Update the dialog's size, which may change depending on
+      // |error_message|.
+      if (GetWidget() && controller_->GetWebContents()) {
+        constrained_window::UpdateWebContentsModalDialogPosition(
+            GetWidget(),
+            web_modal::WebContentsModalDialogManager::FromWebContents(
+                controller_->GetWebContents())
+                ->delegate()
+                ->GetWebContentsModalDialogHost());
+      }
       GetDialogClientView()->UpdateDialogButtons();
     }
+
     Layout();
   }
 
   void SetInputsEnabled(bool enabled) {
     cvc_input_->SetEnabled(enabled);
+    storage_checkbox_->SetEnabled(enabled);
 
     if (month_input_)
       month_input_->SetEnabled(enabled);
@@ -100,15 +122,6 @@
       year_input_->SetEnabled(enabled);
   }
 
-  void SetInputsInvalid(bool invalid) {
-    cvc_input_->SetInvalid(invalid);
-
-    if (month_input_)
-      month_input_->SetInvalid(invalid);
-    if (year_input_)
-      year_input_->SetInvalid(invalid);
-  }
-
   // views::DialogDelegateView
   View* GetContentsView() override {
     InitIfNecessary();
@@ -120,7 +133,7 @@
     // Must hardcode a width so the label knows where to wrap. TODO(estade):
     // This can lead to a weird looking dialog if we end up getting allocated
     // more width than we ask for, e.g. if the title is super long.
-    const int kWidth = 250;
+    const int kWidth = 450;
     return gfx::Size(kWidth, GetHeightForWidth(kWidth));
   }
 
@@ -209,17 +222,13 @@
   // views::TextfieldController
   void ContentsChanged(views::Textfield* sender,
                        const base::string16& new_contents) override {
-    // Sets all inputs back to valid since we don't know which one was
-    // actually invalid to begin with.
-    SetInputsInvalid(false);
+    cvc_input_->SetInvalid(false);
     GetDialogClientView()->UpdateDialogButtons();
   }
 
   // views::ComboboxListener
   void OnPerformAction(views::Combobox* combobox) override {
-    // Sets all inputs back to valid since we don't know which one was
-    // actually invalid to begin with.
-    SetInputsInvalid(false);
+    combobox->SetInvalid(false);
     GetDialogClientView()->UpdateDialogButtons();
   }
 
@@ -268,7 +277,7 @@
 
     input_row->AddChildView(cvc_image);
 
-    // Reserve vertical space.
+    // Reserve vertical space for the error label, assuming it's one line.
     error_label_ = new views::Label(base::ASCIIToUTF16(" "));
     error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
     error_label_->SetEnabledColor(kWarningColor);
diff --git a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
index 37b6391..3b20f0e 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -125,7 +125,7 @@
 
   // ConstrainedWebDialogDelegate:
   web_modal::NativeWebContentsModalDialog GetNativeDialog() override {
-    return view_->GetWidget()->GetNativeView();
+    return view_->GetWidget()->GetNativeWindow();
   }
 
  private:
@@ -246,7 +246,7 @@
         web_modal::PopupManager* popup_manager =
             web_modal::PopupManager::FromWebContents(
                 initiator_observer_.web_contents());
-        popup_manager->ShowModalDialog(GetWidget()->GetNativeView(),
+        popup_manager->ShowModalDialog(GetWidget()->GetNativeWindow(),
                                        initiator_observer_.web_contents());
       }
     }
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 457e4d49f..7a7f269 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -274,6 +274,11 @@
 void DownloadItemView::OnDownloadUpdated(DownloadItem* download_item) {
   DCHECK_EQ(download(), download_item);
 
+  if (!model_.ShouldShowInShelf()) {
+    shelf_->RemoveDownloadView(this);  // This will delete us!
+    return;
+  }
+
   if (IsShowingWarningDialog() && !model_.IsDangerous()) {
     // We have been approved.
     ClearWarningDialog();
diff --git a/chrome/browser/ui/views/download/download_shelf_view.cc b/chrome/browser/ui/views/download/download_shelf_view.cc
index 9f7d42c..4b6552b 100644
--- a/chrome/browser/ui/views/download/download_shelf_view.cc
+++ b/chrome/browser/ui/views/download/download_shelf_view.cc
@@ -127,8 +127,7 @@
 }
 
 void DownloadShelfView::DoAddDownload(DownloadItem* download) {
-  DownloadItemView* view = new DownloadItemView(download, this);
-  AddDownloadView(view);
+  AddDownloadView(new DownloadItemView(download, this));
 }
 
 void DownloadShelfView::MouseMovedOutOfHost() {
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
index fe711579..6bbacf87 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_unittest.cc
@@ -11,84 +11,13 @@
 #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread.h"
-#include "content/public/test/test_renderer_host.h"
-#include "content/public/test/web_contents_tester.h"
+#include "content/public/test/test_web_contents_factory.h"
 #include "ui/accessibility/ax_view_state.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/views/test/views_test_base.h"
 
-#if defined(USE_AURA)
-#include "ui/aura/env.h"
-#endif
-
 namespace {
 
-// A helper class to create test web contents (tabs) for unit tests, without
-// inheriting from RenderViewTestHarness. Can create web contents, and will
-// clean up after itself upon destruction. Owns all created web contents.
-// A few notes:
-// - Works well allocated on the stack, because it should be destroyed before
-//   associated browser context.
-// - Doesn't play nice with web contents created any other way (because of
-//   the implementation of RenderViewHostTestEnabler). But if you are creating
-//   web contents already, what do you need this for? ;)
-// TODO(devlin): Look around and see if this class is needed elsewhere; if so,
-// move it there and expand the API a bit (methods to, e.g., delete/close a
-// web contents, access existing web contents, etc).
-class TestWebContentsFactory {
- public:
-  // |init_aura| initializes the aura environment (and cleans it up at
-  // shutdown, which is necessary for web contents. Since this method should
-  // only be called once, this should only be true if no other part of the test
-  // has initialized the environment.
-  explicit TestWebContentsFactory(bool init_aura);
-  ~TestWebContentsFactory();
-
-  // Creates a new WebContents with the given |context|, and returns it.
-  content::WebContents* CreateWebContents(content::BrowserContext* context);
- private:
-  // The test factory (and friends) for creating test web contents.
-  scoped_ptr<content::RenderViewHostTestEnabler> rvh_enabler_;
-  // The vector of web contents that this class created.
-  ScopedVector<content::WebContents> web_contents_;
-
-  // True if the factory initialized aura (and should thus tear it down).
-  bool init_aura_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWebContentsFactory);
-};
-
-TestWebContentsFactory::TestWebContentsFactory(bool init_aura)
-    : rvh_enabler_(new content::RenderViewHostTestEnabler()),
-      init_aura_(init_aura) {
-#if defined(USE_AURA)
-  if (init_aura)
-    aura::Env::CreateInstance(true);
-#endif
-}
-
-TestWebContentsFactory::~TestWebContentsFactory() {
-  web_contents_.clear();
-  // Let any posted tasks for web contents deletion run.
-  base::RunLoop().RunUntilIdle();
-  rvh_enabler_.reset();
-  // Let any posted tasks for RenderProcess/ViewHost deletion run.
-  base::RunLoop().RunUntilIdle();
-#if defined(USE_AURA)
-  if (init_aura_)
-    aura::Env::DeleteInstance();
-#endif
-}
-
-content::WebContents* TestWebContentsFactory::CreateWebContents(
-    content::BrowserContext* context) {
-  scoped_ptr<content::WebContents> web_contents(
-      content::WebContentsTester::CreateTestWebContents(context, nullptr));
-  DCHECK(web_contents);
-  web_contents_.push_back(web_contents.release());
-  return web_contents_.back();
-}
-
 // A test delegate for a toolbar action view.
 class TestToolbarActionViewDelegate : public ToolbarActionView::Delegate {
  public:
@@ -181,7 +110,7 @@
   TestingProfile profile;
 
   // ViewsTestBase initializees the aura environment, so the factory shouldn't.
-  TestWebContentsFactory web_contents_factory(false);
+  content::TestWebContentsFactory web_contents_factory;
 
   TestToolbarActionViewController controller("fake controller");
   TestToolbarActionViewDelegate action_view_delegate;
diff --git a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
index 1664dfa..f2e6930 100644
--- a/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
+++ b/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc
@@ -220,7 +220,7 @@
 #endif
 
     // Will cause this object to be deleted.
-    native_delegate_->WillClose(widget->GetNativeView());
+    native_delegate_->WillClose(widget->GetNativeWindow());
   }
 
   SingleWebContentsDialogManagerDelegate* native_delegate_;
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index ace8995..b5e8a5c 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -246,10 +246,12 @@
     }
   }
 
-  if (StartupUtils::IsWebviewSigninEnabled()) {
+  if (!command_line->HasSwitch(::switches::kGaiaUrl) &&
+      StartupUtils::IsWebviewSigninEnabled()) {
     // We can't use switch --gaia-url in this case cause we need get
     // auth_code from staging gaia and make all the other auths against prod
     // gaia so user could use all the google services.
+    // TODO(dpolukhin): crbug.com/462204
     const GURL gaia_url = GURL(kStagingGaiaUrl);
     params.SetString("gaiaUrl", gaia_url.spec());
   } else {
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc
index 83c753e..1a1dbc90 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/downloads_dom_handler.cc
@@ -77,35 +77,6 @@
   DOWNLOADS_DOM_EVENT_MAX
 };
 
-static const char kKey[] = "DownloadsDOMHandlerData";
-
-class DownloadsDOMHandlerData : public base::SupportsUserData::Data {
- public:
-  static DownloadsDOMHandlerData* Get(content::DownloadItem* item) {
-    return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey));
-  }
-
-  static const DownloadsDOMHandlerData* Get(const content::DownloadItem* item) {
-    return static_cast<DownloadsDOMHandlerData*>(item->GetUserData(kKey));
-  }
-
-  static void Set(content::DownloadItem* item, DownloadsDOMHandlerData* data) {
-    item->SetUserData(kKey, data);
-  }
-
-  static DownloadsDOMHandlerData* Create(content::DownloadItem* item) {
-    DownloadsDOMHandlerData* data = new DownloadsDOMHandlerData;
-    item->SetUserData(kKey, data);
-    return data;
-  }
-
-  void set_is_removed(bool is_removed) { is_removed_ = is_removed; }
-  bool is_removed() const { return is_removed_; }
-
- private:
-  bool is_removed_;
-};
-
 void CountDownloadsDOMEvents(DownloadsDOMEvent event) {
   UMA_HISTOGRAM_ENUMERATION("Download.DOMEvent",
                             event,
@@ -267,18 +238,14 @@
   return file_value;
 }
 
-bool IsRemoved(const content::DownloadItem& item) {
-  const DownloadsDOMHandlerData* data = DownloadsDOMHandlerData::Get(&item);
-  return data && data->is_removed();
-}
-
 // Filters out extension downloads and downloads that don't have a filename yet.
 bool IsDownloadDisplayable(const content::DownloadItem& item) {
   return !download_crx_util::IsExtensionDownload(item) &&
          !item.IsTemporary() &&
          !item.GetFileNameToReportUser().empty() &&
          !item.GetTargetFilePath().empty() &&
-         !IsRemoved(item);
+         DownloadItemModel(
+             const_cast<content::DownloadItem*>(&item)).ShouldShowInShelf();
 }
 
 }  // namespace
@@ -299,16 +266,7 @@
 }
 
 DownloadsDOMHandler::~DownloadsDOMHandler() {
-  while (!removes_.empty()) {
-    const std::set<uint32> remove = removes_.back();
-    removes_.pop_back();
-
-    for (const auto id : remove) {
-      content::DownloadItem* download = GetDownloadById(id);
-      if (download)
-        download->Remove();
-    }
-  }
+  FinalizeRemovals();
 }
 
 // DownloadsDOMHandler, public: -----------------------------------------------
@@ -398,7 +356,7 @@
 void DownloadsDOMHandler::OnDownloadRemoved(
     content::DownloadManager* manager,
     content::DownloadItem* download_item) {
-  if (IsRemoved(*download_item))
+  if (!DownloadItemModel(download_item).ShouldShowInShelf())
     return;
 
   // This relies on |download_item| being removed from DownloadManager in this
@@ -503,17 +461,17 @@
 
 void DownloadsDOMHandler::HandleUndo(const base::ListValue* args) {
   // TODO(dbeam): handle more than removed downloads someday?
-  if (removes_.empty())
+  if (removals_.empty())
     return;
 
-  const std::set<uint32> last_removed_ids = removes_.back();
-  removes_.pop_back();
+  const std::set<uint32> last_removed_ids = removals_.back();
+  removals_.pop_back();
 
   for (auto id : last_removed_ids) {
     content::DownloadItem* download = GetDownloadById(id);
     if (!download)
       continue;
-    DownloadsDOMHandlerData::Set(download, nullptr);
+    DownloadItemModel(download).SetShouldShowInShelf(true);
     download->UpdateObservers();
   }
 }
@@ -543,16 +501,18 @@
     const std::vector<content::DownloadItem*>& to_remove) {
   std::set<uint32> ids;
   for (auto* download : to_remove) {
-    if (IsRemoved(*download) ||
+    DownloadItemModel item_model(download);
+    if (!item_model.ShouldShowInShelf() ||
         download->GetState() == content::DownloadItem::IN_PROGRESS) {
       continue;
     }
 
-    DownloadsDOMHandlerData::Create(download)->set_is_removed(true);
+    item_model.SetShouldShowInShelf(false);
     ids.insert(download->GetId());
     download->UpdateObservers();
   }
-  removes_.push_back(ids);
+  if (!ids.empty())
+    removals_.push_back(ids);
 }
 
 void DownloadsDOMHandler::HandleOpenDownloadsFolder(
@@ -585,6 +545,19 @@
   return main_notifier_.GetManager();
 }
 
+void DownloadsDOMHandler::FinalizeRemovals() {
+  while (!removals_.empty()) {
+    const std::set<uint32> remove = removals_.back();
+    removals_.pop_back();
+
+    for (const auto id : remove) {
+      content::DownloadItem* download = GetDownloadById(id);
+      if (download)
+        download->Remove();
+    }
+  }
+}
+
 void DownloadsDOMHandler::SendCurrentDownloads() {
   update_scheduled_ = false;
   content::DownloadManager::DownloadVector all_items, filtered_items;
@@ -670,8 +643,8 @@
 
 content::DownloadItem* DownloadsDOMHandler::GetDownloadById(uint32 id) {
   content::DownloadItem* item = NULL;
-  if (main_notifier_.GetManager())
-    item = main_notifier_.GetManager()->GetDownload(id);
+  if (GetMainNotifierManager())
+    item = GetMainNotifierManager()->GetDownload(id);
   if (!item && original_notifier_.get() && original_notifier_->GetManager())
     item = original_notifier_->GetManager()->GetDownload(id);
   return item;
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.h b/chrome/browser/ui/webui/downloads_dom_handler.h
index 06890acd..85fdbd8a 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler.h
+++ b/chrome/browser/ui/webui/downloads_dom_handler.h
@@ -106,6 +106,9 @@
   // Protected for testing.
   virtual content::DownloadManager* GetMainNotifierManager();
 
+  // Actually remove downloads with an ID in |removals_|. This cannot be undone.
+  void FinalizeRemovals();
+
  private:
   // Shorthand for |observing_items_|, which tracks all items that this is
   // observing so that RemoveObserver will be called for all of them.
@@ -150,7 +153,7 @@
   scoped_ptr<AllDownloadItemNotifier> original_notifier_;
 
   // IDs of downloads to remove when this handler gets deleted.
-  std::vector<std::set<uint32>> removes_;
+  std::vector<std::set<uint32>> removals_;
 
   // Whether a call to SendCurrentDownloads() is currently scheduled.
   bool update_scheduled_;
diff --git a/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc b/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc
index 4d8c060..ed0193a 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/downloads_dom_handler_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/json/json_reader.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
+#include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/webui/downloads_dom_handler.h"
@@ -85,6 +86,8 @@
 
   void set_manager(content::DownloadManager* manager) { manager_ = manager; }
 
+  using DownloadsDOMHandler::FinalizeRemovals;
+
  protected:
   content::WebContents* GetWebUIWebContents() override { return NULL; }
 
@@ -247,6 +250,7 @@
       testing::SetArgPointee<0>(items));
 
   mock_handler_->HandleClearAll(NULL);
+  EXPECT_TRUE(DownloadItemModel(&item).ShouldShowInShelf());
 }
 
 // Tests that DownloadsDOMHandler detects new downloads and relays them to the
@@ -270,6 +274,34 @@
   EXPECT_EQ(0, static_cast<int>(mock_handler_->downloads_list()->GetSize()));
 }
 
+// Tests that DownloadsDOMHandler actually calls DownloadItem::Remove() when
+// it's closed (and removals can no longer be undone).
+IN_PROC_BROWSER_TEST_F(DownloadsDOMHandlerTest, RemoveCalledOnPageClose) {
+  content::MockDownloadManager manager;
+  mock_handler_->set_manager(&manager);
+
+  content::MockDownloadItem item;
+  EXPECT_CALL(item, GetId()).WillRepeatedly(testing::Return(1));
+  EXPECT_CALL(item, GetState()).WillRepeatedly(
+      testing::Return(content::DownloadItem::COMPLETE));
+
+  DownloadItemModel model(&item);
+  EXPECT_TRUE(model.ShouldShowInShelf());
+
+  EXPECT_CALL(manager, GetDownload(1)).WillRepeatedly(testing::Return(&item));
+
+  base::ListValue remove;
+  remove.AppendString("1");
+  EXPECT_CALL(item, UpdateObservers()).Times(1);
+  mock_handler_->HandleRemove(&remove);
+  EXPECT_FALSE(model.ShouldShowInShelf());
+
+  EXPECT_CALL(item, Remove()).Times(1);
+  // Call |mock_handler_->FinalizeRemovals()| instead of |mock_handler_.reset()|
+  // because the vtable is affected during destruction and the fake manager
+  // rigging doesn't work.
+  mock_handler_->FinalizeRemovals();
+}
 
 // TODO(benjhayden): Test the extension downloads filter for both
 // mock_handler_.downloads_list() and mock_handler_.download_updated().
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index b7ea12f..c21555f 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -636,6 +636,30 @@
   // uber extensions.
   source->AddString("extensionUninstall",
       l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL));
+
+  // Pack Extension Overlay:
+  source->AddString("packExtensionOverlay",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
+  source->AddString("packExtensionHeading",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
+  source->AddString("packExtensionCommit",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON));
+  source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
+  source->AddString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
+  source->AddString("packExtensionRootDir",
+      l10n_util::GetStringUTF16(
+          IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
+  source->AddString("packExtensionPrivateKey",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
+  source->AddString("packExtensionBrowseButton",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
+  source->AddString("packExtensionProceedAnyway",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PROCEED_ANYWAY));
+  source->AddString("packExtensionWarningTitle",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_WARNING_TITLE));
+  source->AddString("packExtensionErrorTitle",
+      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_ERROR_TITLE));
+
 }
 
 void ExtensionSettingsHandler::RenderViewDeleted(
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index d99e809..88252e0 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/webui/extensions/extension_loader_handler.h"
 #include "chrome/browser/ui/webui/extensions/extension_settings_handler.h"
 #include "chrome/browser/ui/webui/extensions/install_extension_handler.h"
-#include "chrome/browser/ui/webui/extensions/pack_extension_handler.h"
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_ui.h"
@@ -51,10 +50,6 @@
   handler->GetLocalizedValues(source);
   web_ui->AddMessageHandler(handler);
 
-  PackExtensionHandler* pack_handler = new PackExtensionHandler();
-  pack_handler->GetLocalizedValues(source);
-  web_ui->AddMessageHandler(pack_handler);
-
   CommandHandler* commands_handler = new CommandHandler(profile);
   commands_handler->GetLocalizedValues(source);
   web_ui->AddMessageHandler(commands_handler);
diff --git a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc b/chrome/browser/ui/webui/extensions/pack_extension_handler.cc
deleted file mode 100644
index 12a4c07..0000000
--- a/chrome/browser/ui/webui/extensions/pack_extension_handler.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/extensions/pack_extension_handler.h"
-
-#include "base/bind.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/extension_creator.h"
-#include "chrome/browser/ui/chrome_select_file_policy.h"
-#include "chrome/grit/generated_resources.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-#include "content/public/browser/web_ui_data_source.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace extensions {
-
-PackExtensionHandler::PackExtensionHandler() {
-}
-
-PackExtensionHandler::~PackExtensionHandler() {
-  // There may be pending file dialogs, we need to tell them that we've gone
-  // away so they don't try and call back to us.
-  if (load_extension_dialog_.get())
-    load_extension_dialog_->ListenerDestroyed();
-
-  if (pack_job_.get())
-    pack_job_->ClearClient();
-}
-
-void PackExtensionHandler::GetLocalizedValues(
-    content::WebUIDataSource* source) {
-  source->AddString("packExtensionOverlay",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_TITLE));
-  source->AddString("packExtensionHeading",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_HEADING));
-  source->AddString("packExtensionCommit",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_BUTTON));
-  source->AddString("ok", l10n_util::GetStringUTF16(IDS_OK));
-  source->AddString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
-  source->AddString("packExtensionRootDir",
-      l10n_util::GetStringUTF16(
-          IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL));
-  source->AddString("packExtensionPrivateKey",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL));
-  source->AddString("packExtensionBrowseButton",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_DIALOG_BROWSE));
-  source->AddString("packExtensionProceedAnyway",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PROCEED_ANYWAY));
-  source->AddString("packExtensionWarningTitle",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_WARNING_TITLE));
-  source->AddString("packExtensionErrorTitle",
-      l10n_util::GetStringUTF16(IDS_EXTENSION_PACK_ERROR_TITLE));
-}
-
-void PackExtensionHandler::RegisterMessages() {
-  web_ui()->RegisterMessageCallback(
-      "pack",
-      base::Bind(&PackExtensionHandler::HandlePackMessage,
-                 base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "packExtensionSelectFilePath",
-      base::Bind(&PackExtensionHandler::HandleSelectFilePathMessage,
-                 base::Unretained(this)));
-}
-
-void PackExtensionHandler::OnPackSuccess(const base::FilePath& crx_file,
-                                         const base::FilePath& pem_file) {
-  base::ListValue arguments;
-  arguments.Append(new base::StringValue(base::UTF16ToUTF8(
-      PackExtensionJob::StandardSuccessMessage(crx_file, pem_file))));
-  web_ui()->CallJavascriptFunction(
-      "extensions.PackExtensionOverlay.showSuccessMessage", arguments);
-}
-
-void PackExtensionHandler::OnPackFailure(const std::string& error,
-                                         ExtensionCreator::ErrorType type) {
-  if (type == ExtensionCreator::kCRXExists) {
-    base::StringValue error_str(error);
-    base::StringValue extension_path_str(extension_path_.value());
-    base::StringValue key_path_str(private_key_path_.value());
-    base::FundamentalValue overwrite_flag(ExtensionCreator::kOverwriteCRX);
-
-    web_ui()->CallJavascriptFunction(
-        "extensions.ExtensionSettings.askToOverrideWarning",
-        error_str, extension_path_str, key_path_str, overwrite_flag);
-  } else {
-    ShowAlert(error);
-  }
-}
-
-void PackExtensionHandler::FileSelected(const base::FilePath& path, int index,
-                                        void* params) {
-  base::ListValue results;
-  results.Append(new base::StringValue(path.value()));
-  web_ui()->CallJavascriptFunction("window.handleFilePathSelected", results);
-}
-
-void PackExtensionHandler::MultiFilesSelected(
-    const std::vector<base::FilePath>& files, void* params) {
-  NOTREACHED();
-}
-
-void PackExtensionHandler::HandlePackMessage(const base::ListValue* args) {
-  DCHECK_EQ(3U, args->GetSize());
-
-  double flags_double = 0.0;
-  base::FilePath::StringType extension_path_str;
-  base::FilePath::StringType private_key_path_str;
-  if (!args->GetString(0, &extension_path_str) ||
-      !args->GetString(1, &private_key_path_str) ||
-      !args->GetDouble(2, &flags_double)) {
-    NOTREACHED();
-    return;
-  }
-
-  extension_path_ = base::FilePath(extension_path_str);
-  private_key_path_ = base::FilePath(private_key_path_str);
-
-  int run_flags = static_cast<int>(flags_double);
-
-  base::FilePath root_directory = extension_path_;
-  base::FilePath key_file = private_key_path_;
-  last_used_path_ = extension_path_;
-
-  if (root_directory.empty()) {
-    if (extension_path_.empty()) {
-      ShowAlert(l10n_util::GetStringUTF8(
-          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED));
-    } else {
-      ShowAlert(l10n_util::GetStringUTF8(
-          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID));
-    }
-
-    return;
-  }
-
-  if (!private_key_path_.empty() && key_file.empty()) {
-    ShowAlert(l10n_util::GetStringUTF8(
-        IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID));
-    return;
-  }
-
-  pack_job_ = new PackExtensionJob(this, root_directory, key_file, run_flags);
-  pack_job_->Start();
-}
-
-void PackExtensionHandler::HandleSelectFilePathMessage(
-    const base::ListValue* args) {
-  DCHECK_EQ(2U, args->GetSize());
-
-  std::string select_type;
-  if (!args->GetString(0, &select_type))
-    NOTREACHED();
-
-  std::string operation;
-  if (!args->GetString(1, &operation))
-    NOTREACHED();
-
-  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
-  ui::SelectFileDialog::FileTypeInfo info;
-  int file_type_index = 0;
-  base::FilePath path_to_use = last_used_path_;
-  if (select_type == "file") {
-    type = ui::SelectFileDialog::SELECT_OPEN_FILE;
-    path_to_use = base::FilePath();
-  }
-
-  base::string16 select_title;
-  if (operation == "load") {
-    select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
-  } else if (operation == "pem") {
-    select_title = l10n_util::GetStringUTF16(
-        IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
-    info.extensions.push_back(std::vector<base::FilePath::StringType>());
-        info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
-        info.extension_description_overrides.push_back(
-            l10n_util::GetStringUTF16(
-                IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
-        info.include_all_files = true;
-    file_type_index = 1;
-  } else {
-    NOTREACHED();
-  }
-
-  load_extension_dialog_ = ui::SelectFileDialog::Create(
-      this, new ChromeSelectFilePolicy(web_ui()->GetWebContents()));
-  load_extension_dialog_->SelectFile(
-      type,
-      select_title,
-      path_to_use,
-      &info,
-      file_type_index,
-      base::FilePath::StringType(),
-      web_ui()->GetWebContents()->GetTopLevelNativeWindow(),
-      NULL);
-}
-
-void PackExtensionHandler::ShowAlert(const std::string& message) {
-  base::ListValue arguments;
-  arguments.Append(new base::StringValue(message));
-  web_ui()->CallJavascriptFunction(
-      "extensions.PackExtensionOverlay.showError", arguments);
-}
-
-}  // namespace extensions
diff --git a/chrome/browser/ui/webui/extensions/pack_extension_handler.h b/chrome/browser/ui/webui/extensions/pack_extension_handler.h
deleted file mode 100644
index 36a27b3..0000000
--- a/chrome/browser/ui/webui/extensions/pack_extension_handler.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "chrome/browser/browsing_data/browsing_data_remover.h"
-#include "chrome/browser/extensions/pack_extension_job.h"
-#include "chrome/browser/plugins/plugin_data_remover_helper.h"
-#include "content/public/browser/web_ui_message_handler.h"
-#include "ui/shell_dialogs/select_file_dialog.h"
-
-namespace content {
-class WebUIDataSource;
-}
-
-namespace extensions {
-
-// Clear browser data handler page UI handler.
-class PackExtensionHandler : public content::WebUIMessageHandler,
-                             public ui::SelectFileDialog::Listener,
-                             public PackExtensionJob::Client {
- public:
-  PackExtensionHandler();
-  ~PackExtensionHandler() override;
-
-  void GetLocalizedValues(content::WebUIDataSource* source);
-
-  // WebUIMessageHandler implementation.
-  void RegisterMessages() override;
-
-  // ExtensionPackJob::Client implementation.
-  void OnPackSuccess(const base::FilePath& crx_file,
-                     const base::FilePath& key_file) override;
-
-  void OnPackFailure(const std::string& error,
-                     ExtensionCreator::ErrorType) override;
-
- private:
-  // SelectFileDialog::Listener implementation.
-  void FileSelected(const base::FilePath& path,
-                    int index,
-                    void* params) override;
-  void MultiFilesSelected(const std::vector<base::FilePath>& files,
-                          void* params) override;
-  void FileSelectionCanceled(void* params) override {}
-
-  // JavaScript callback to start packing an extension.
-  void HandlePackMessage(const base::ListValue* args);
-
-  // JavaScript callback to show a file browse dialog.
-  // |args[0]| must be a string that specifies the file dialog type: file or
-  // folder.
-  // |args[1]| must be a string that specifies the operation to perform: load
-  // or pem.
-  void HandleSelectFilePathMessage(const base::ListValue* args);
-
-  // A function to ask the page to show an alert.
-  void ShowAlert(const std::string& message);
-
-  // Used to package the extension.
-  scoped_refptr<PackExtensionJob> pack_job_;
-
-  // Returned by the SelectFileDialog machinery. Used to initiate the selection
-  // dialog.
-  scoped_refptr<ui::SelectFileDialog> load_extension_dialog_;
-
-  // Path to root directory of extension.
-  base::FilePath extension_path_;
-
-  // Path to private key file, or null if none specified.
-  base::FilePath private_key_path_;
-
-  // Path to the last used folder to load an extension.
-  base::FilePath last_used_path_;
-
-  DISALLOW_COPY_AND_ASSIGN(PackExtensionHandler);
-};
-
-}  // namespace extensions
-
-#endif  // CHROME_BROWSER_UI_WEBUI_EXTENSIONS_PACK_EXTENSION_HANDLER_H_
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index e3d05b1..a40eb9ef 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -681,6 +681,9 @@
   values->SetBoolean("enableTimeZoneTrackingOption",
                      !have_disable_time_zone_tracking_option_switch &&
                          !chromeos::system::HasSystemTimezonePolicy());
+  values->SetBoolean("resolveTimezoneByGeolocationInitialValue",
+                     Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
+                         prefs::kResolveTimezoneByGeolocation));
 #endif
 }
 
diff --git a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js b/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
index 937af8b..4033599 100644
--- a/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
+++ b/chrome/browser/ui/webui/options/chromeos/date_time_options_browsertest.js
@@ -26,14 +26,12 @@
 TEST_F('DateTimeOptionsWebUITest', 'testShowSetTimeButton', function() {
   assertEquals(this.browsePreload, document.location.href);
 
-  // Hide label and show button.
+  // Show button.
   BrowserOptions.setCanSetTime(true);
-  expectTrue($('time-synced-explanation').hidden);
   expectFalse($('set-time').hidden);
 
-  // Show label and hide button.
+  // Hide button.
   BrowserOptions.setCanSetTime(false);
-  expectFalse($('time-synced-explanation').hidden);
   expectTrue($('set-time').hidden);
 });
 
diff --git a/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc
index ef55e5f..bbb4b0c 100644
--- a/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/date_time_options_handler.cc
@@ -33,9 +33,6 @@
   localized_strings->SetString(
       "setTimeButton",
       l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_SET_TIME_BUTTON));
-  localized_strings->SetString(
-      "timeSyncedExplanation",
-      l10n_util::GetStringUTF16(IDS_OPTIONS_SETTINGS_TIME_SYNCED_EXPLANATION));
 }
 
 void DateTimeOptionsHandler::InitializeHandler() {
diff --git a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
index df7f7d1..d51fd41 100644
--- a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
+++ b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc
@@ -118,11 +118,17 @@
         browser->tab_strip_model()->GetActiveWebContents();
 
     for (size_t i = 0; i < sizeof(kPrefTests) / sizeof(kPrefTests[0]); i++) {
-      CheckPreference(contents,
-                      kPrefTests[i].pref_name,
-                      !is_owner && kPrefTests[i].owner_only,
-                      !is_owner && kPrefTests[i].indicator ? "owner" :
-                                                             std::string());
+      bool disabled = !is_owner && kPrefTests[i].owner_only;
+      if (strcmp(kPrefTests[i].pref_name, kSystemTimezone) == 0) {
+        disabled = ProfileHelper::Get()
+                       ->GetProfileByUserUnsafe(user)
+                       ->GetPrefs()
+                       ->GetBoolean(prefs::kResolveTimezoneByGeolocation);
+      }
+
+      CheckPreference(
+          contents, kPrefTests[i].pref_name, disabled,
+          !is_owner && kPrefTests[i].indicator ? "owner" : std::string());
     }
     CheckBanner(contents, is_primary);
     CheckSharedSections(contents, is_primary);
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 501a602..5a552b6 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -101,6 +101,12 @@
       'browser/android/logo_service.h',
       'browser/android/manifest_icon_selector.cc',
       'browser/android/manifest_icon_selector.h',
+      'browser/android/metrics/uma_bridge.cc',
+      'browser/android/metrics/uma_bridge.h',
+      'browser/android/metrics/uma_session_stats.cc',
+      'browser/android/metrics/uma_session_stats.h',
+      'browser/android/metrics/uma_utils.cc',
+      'browser/android/metrics/uma_utils.h',
       'browser/android/most_visited_sites.cc',
       'browser/android/most_visited_sites.h',
       'browser/android/new_tab_page_prefs.cc',
@@ -154,10 +160,6 @@
       'browser/android/thumbnail/thumbnail.h',
       'browser/android/thumbnail/thumbnail_store.cc',
       'browser/android/thumbnail/thumbnail_store.h',
-      'browser/android/uma_bridge.cc',
-      'browser/android/uma_bridge.h',
-      'browser/android/uma_utils.cc',
-      'browser/android/uma_utils.h',
       'browser/android/url_utilities.cc',
       'browser/android/url_utilities.h',
       'browser/android/voice_search_tab_helper.cc',
@@ -1599,6 +1601,9 @@
       'android/java/src/org/chromium/chrome/browser/NewTabPagePrefs.java',
       'android/java/src/org/chromium/chrome/browser/IntentHelper.java',
       'android/java/src/org/chromium/chrome/browser/JavascriptAppModalDialog.java',
+      'android/java/src/org/chromium/chrome/browser/metrics/UmaBridge.java',
+      'android/java/src/org/chromium/chrome/browser/metrics/UmaSessionStats.java',
+      'android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java',
       'android/java/src/org/chromium/chrome/browser/NavigationPopup.java',
       'android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java',
       'android/java/src/org/chromium/chrome/browser/notifications/NotificationUIManager.java',
@@ -1631,8 +1636,6 @@
       'android/java/src/org/chromium/chrome/browser/Tab.java',
       'android/java/src/org/chromium/chrome/browser/TabState.java',
       'android/java/src/org/chromium/chrome/browser/TtsPlatformImpl.java',
-      'android/java/src/org/chromium/chrome/browser/UmaBridge.java',
-      'android/java/src/org/chromium/chrome/browser/UmaUtils.java',
       'android/java/src/org/chromium/chrome/browser/UrlUtilities.java',
       'android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java',
       'android/java/src/org/chromium/chrome/browser/VoiceSearchTabHelper.java',
@@ -2241,6 +2244,7 @@
       'browser/profiles/profile_metrics.cc',
       'browser/profiles/profile_metrics.h',
       'browser/profiles/profile_metrics_list.h',
+      'browser/profiles/profile_metrics_mac.mm',
       'browser/profiles/profile_shortcut_manager_win.cc',
       'browser/profiles/profile_shortcut_manager_win.h',
       'browser/profiles/profiles_state.cc',
@@ -2896,6 +2900,7 @@
         '../components/components.gyp:enhanced_bookmarks',
         '../components/components.gyp:favicon_base',
         '../components/components.gyp:favicon_core',
+        '../components/components.gyp:feedback_component',
         '../components/components.gyp:gcm_driver',
         '../components/components.gyp:google_core_browser',
         '../components/components.gyp:handoff',
@@ -3366,7 +3371,6 @@
         }, {  # OS!="android" and OS!="ios"
           'sources': [ '<@(chrome_browser_non_mobile_sources)' ],
           'dependencies': [
-            '../components/components.gyp:feedback_component',
             '../device/core/core.gyp:device_core',
             '../device/usb/usb.gyp:device_usb',
           ]
@@ -3383,6 +3387,7 @@
             'chrome_browser_jni_headers',
           ],
           'dependencies!': [
+            '../components/components.gyp:feedback_component',
             '../components/components.gyp:storage_monitor',
             '../components/components.gyp:web_modal',
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 11d50ac..0714c13 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -421,8 +421,6 @@
         'browser/chromeos/login/auth/chrome_login_performer.h',
         'browser/chromeos/login/chrome_restart_request.cc',
         'browser/chromeos/login/chrome_restart_request.h',
-        'browser/chromeos/login/default_pinned_apps_field_trial.cc',
-        'browser/chromeos/login/default_pinned_apps_field_trial.h',
         'browser/chromeos/login/demo_mode/demo_app_launcher.cc',
         'browser/chromeos/login/demo_mode/demo_app_launcher.h',
         'browser/chromeos/login/easy_unlock/easy_unlock_create_keys_operation.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index 28e210e4..5bb7f3a3 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -651,6 +651,8 @@
       'browser/ui/cocoa/screen_capture_notification_ui_cocoa.h',
       'browser/ui/cocoa/screen_capture_notification_ui_cocoa.mm',
       'browser/ui/cocoa/simple_message_box_mac.mm',
+      'browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.h',
+      'browser/ui/cocoa/single_web_contents_dialog_manager_cocoa.mm',
       'browser/ui/cocoa/sprite_view.h',
       'browser/ui/cocoa/sprite_view.mm',
       'browser/ui/cocoa/ssl_client_certificate_selector_cocoa.h',
@@ -731,7 +733,6 @@
       'browser/ui/cocoa/view_id_util.h',
       'browser/ui/cocoa/view_id_util.mm',
       'browser/ui/cocoa/view_resizer.h',
-      'browser/ui/cocoa/web_contents_modal_dialog_manager_cocoa.mm',
       'browser/ui/cocoa/web_dialog_window_controller.h',
       'browser/ui/cocoa/web_dialog_window_controller.mm',
       'browser/ui/cocoa/website_settings/permission_bubble_cocoa.h',
@@ -1344,8 +1345,7 @@
     # Counts desktop Linux and ChromeOS.
     'chrome_browser_ui_linux_sources': [
       'browser/ui/startup/autolaunch_prompt.cc',
-      'browser/ui/views/apps/chrome_apps_client_views.cc',
-      'browser/ui/views/apps/keyboard_hook_handler.cc',
+      'browser/ui/views/apps/chrome_app_window_client_views.cc',
       'browser/ui/webui/certificate_viewer_ui.cc',
       'browser/ui/webui/certificate_viewer_ui.h',
       'browser/ui/webui/certificate_viewer_webui.cc',
@@ -1841,6 +1841,12 @@
       'browser/ui/app_list/app_list_service_views.h',
       'browser/ui/app_list/app_list_shower_views.cc',
       'browser/ui/app_list/app_list_shower_views.h',
+      'browser/ui/views/apps/chrome_native_app_window_views.cc',
+      'browser/ui/views/apps/chrome_native_app_window_views.h',
+      'browser/ui/views/apps/desktop_keyboard_capture.cc',
+      'browser/ui/views/apps/desktop_keyboard_capture.h',
+      'browser/ui/views/apps/keyboard_hook_handler.cc',
+      'browser/ui/views/apps/keyboard_hook_handler.h',
       'browser/ui/views/chrome_browser_main_extra_parts_views.cc',
       'browser/ui/views/chrome_browser_main_extra_parts_views.h',
       'browser/ui/views/chrome_constrained_window_views_client.cc',
@@ -1851,10 +1857,14 @@
       'browser/ui/views/collected_cookies_views.h',
       'browser/ui/views/cookie_info_view.cc',
       'browser/ui/views/cookie_info_view.h',
+      'browser/ui/views/extensions/extension_keybinding_registry_views.cc',
+      'browser/ui/views/extensions/extension_keybinding_registry_views.h',
       'browser/ui/views/find_bar_host.cc',
       'browser/ui/views/find_bar_host.h',
       'browser/ui/views/find_bar_view.cc',
       'browser/ui/views/find_bar_view.h',
+      'browser/ui/views/frame/taskbar_decorator.cc',
+      'browser/ui/views/frame/taskbar_decorator.h',
       'browser/ui/views/hung_renderer_view.cc',
       'browser/ui/views/hung_renderer_view.h',
       'browser/ui/views/infobars/confirm_infobar.cc',
@@ -1953,18 +1963,13 @@
       'browser/ui/views/apps/app_window_desktop_native_widget_aura_win.h',
       'browser/ui/views/apps/app_window_desktop_window_tree_host_win.cc',
       'browser/ui/views/apps/app_window_desktop_window_tree_host_win.h',
-      'browser/ui/views/apps/chrome_apps_client_views_win.cc',
-      'browser/ui/views/apps/chrome_native_app_window_views.cc',
-      'browser/ui/views/apps/chrome_native_app_window_views.h',
+      'browser/ui/views/apps/chrome_app_window_client_views_win.cc',
       'browser/ui/views/apps/chrome_native_app_window_views_aura.cc',
       'browser/ui/views/apps/chrome_native_app_window_views_aura.h',
       'browser/ui/views/apps/chrome_native_app_window_views_win.cc',
       'browser/ui/views/apps/chrome_native_app_window_views_win.h',
-      'browser/ui/views/apps/desktop_keyboard_capture.cc',
-      'browser/ui/views/apps/desktop_keyboard_capture.h',
       'browser/ui/views/apps/glass_app_window_frame_view_win.cc',
       'browser/ui/views/apps/glass_app_window_frame_view_win.h',
-      'browser/ui/views/apps/keyboard_hook_handler.h',
       'browser/ui/views/apps/keyboard_hook_handler_win.cc',
       'browser/ui/views/apps/shaped_app_window_targeter.cc',
       'browser/ui/views/apps/shaped_app_window_targeter.h',
@@ -2078,8 +2083,6 @@
       'browser/ui/views/extensions/extension_install_dialog_view.cc',
       'browser/ui/views/extensions/extension_installed_bubble_view.cc',
       'browser/ui/views/extensions/extension_installed_bubble_view.h',
-      'browser/ui/views/extensions/extension_keybinding_registry_views.cc',
-      'browser/ui/views/extensions/extension_keybinding_registry_views.h',
       'browser/ui/views/extensions/extension_message_bubble_view.cc',
       'browser/ui/views/extensions/extension_message_bubble_view.h',
       'browser/ui/views/extensions/extension_popup.cc',
@@ -2147,8 +2150,6 @@
       'browser/ui/views/frame/system_menu_model_builder.h',
       'browser/ui/views/frame/system_menu_model_delegate.cc',
       'browser/ui/views/frame/system_menu_model_delegate.h',
-      'browser/ui/views/frame/taskbar_decorator.cc',
-      'browser/ui/views/frame/taskbar_decorator.h',
       'browser/ui/views/frame/taskbar_decorator_win.cc',
       'browser/ui/views/frame/top_container_view.cc',
       'browser/ui/views/frame/top_container_view.h',
@@ -2504,8 +2505,6 @@
       'browser/ui/webui/extensions/extension_error_ui_util.h',
       'browser/ui/webui/extensions/extension_icon_source.cc',
       'browser/ui/webui/extensions/extension_icon_source.h',
-      'browser/ui/webui/extensions/pack_extension_handler.cc',
-      'browser/ui/webui/extensions/pack_extension_handler.h',
       'browser/ui/webui/voice_search_ui.cc',
       'browser/ui/webui/voice_search_ui.h',
     ],
@@ -2668,6 +2667,7 @@
         '../components/components.gyp:device_event_log_component',
         '../components/components.gyp:dom_distiller_core',
         '../components/components.gyp:dom_distiller_webui',
+        '../components/components.gyp:feedback_proto',
         '../components/components.gyp:history_core_browser_proto',
         '../components/components.gyp:invalidation',
         '../components/components.gyp:onc_component',
@@ -2852,16 +2852,33 @@
             ['OS=="mac"', {
               'conditions': [
                 ['mac_views_browser==1', {
+                  'sources': [
+                    'browser/ui/views/apps/chrome_app_window_client_views_mac.mm',
+                  ],
                   'sources!': [
+                    'browser/ui/cocoa/apps/chrome_app_window_client_cocoa.mm',
                     'browser/ui/cocoa/bookmarks/bookmark_drag_drop_cocoa.mm',
                     'browser/ui/cocoa/browser_window_factory_cocoa.mm',
                     'browser/ui/cocoa/infobars/confirm_infobar_controller.mm',
                     'browser/ui/cocoa/tab_dialogs_cocoa.mm',
                   ],
+                  'dependencies': [
+                    '<(DEPTH)/extensions/components/extensions_components.gyp:native_app_window',
+                  ],
                 }, {
                   'sources!': [
+                    'browser/ui/views/apps/chrome_native_app_window_views.cc',
+                    'browser/ui/views/apps/chrome_native_app_window_views.h',
+                    'browser/ui/views/apps/desktop_keyboard_capture.cc',
+                    'browser/ui/views/apps/desktop_keyboard_capture.h',
+                    'browser/ui/views/apps/keyboard_hook_handler.cc',
+                    'browser/ui/views/apps/keyboard_hook_handler.h',
                     'browser/ui/views/bookmarks/bookmark_drag_drop_views.cc',
+                    'browser/ui/views/extensions/extension_keybinding_registry_views.cc',
+                    'browser/ui/views/extensions/extension_keybinding_registry_views.h',
                     'browser/ui/views/frame/browser_window_factory.cc',
+                    'browser/ui/views/frame/taskbar_decorator.cc',
+                    'browser/ui/views/frame/taskbar_decorator.h',
                     'browser/ui/views/infobar/confirm_infobar.cc'
                     'browser/ui/views/tab_dialogs_views.cc',
                   ],
@@ -2928,6 +2945,7 @@
             'chrome_browser_jni_headers',
           ],
           'dependencies!': [
+             '../components/components.gyp:feedback_proto',
              '../ui/events/events.gyp:events',
              'chrome_browser_ui_views.gyp:browser_ui_views',
           ],
@@ -3001,6 +3019,7 @@
           ],
           'sources': [ '<@(chrome_browser_ui_win_sources)' ],
           'sources!': [
+            'browser/ui/views/apps/keyboard_hook_handler.cc',
             'browser/ui/views/frame/taskbar_decorator.cc'
           ],
           'conditions': [
@@ -3124,7 +3143,6 @@
         }],
         ['OS!="android" and OS!="ios"', {
           'dependencies': [
-            '../components/components.gyp:feedback_proto',
             '../device/bluetooth/bluetooth.gyp:device_bluetooth',
             '../third_party/libusb/libusb.gyp:libusb',
           ],
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 0ecfd4f4..6a80c5b 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -51,6 +51,8 @@
       'common/custom_handlers/protocol_handler.cc',
       'common/custom_handlers/protocol_handler.h',
       'common/descriptors_android.h',
+      'common/favicon/fallback_icon_url_parser.cc',
+      'common/favicon/fallback_icon_url_parser.h',
       'common/favicon/favicon_url_parser.cc',
       'common/favicon/favicon_url_parser.h',
       'common/icon_with_badge_image_source.cc',
@@ -317,6 +319,7 @@
         '<(DEPTH)/crypto/crypto.gyp:crypto',
         '<(DEPTH)/net/net.gyp:net',
         '<(DEPTH)/skia/skia.gyp:skia',
+        '<(DEPTH)/skia/skia.gyp:skia_library',
         '<(DEPTH)/third_party/icu/icu.gyp:icui18n',
         '<(DEPTH)/third_party/icu/icu.gyp:icuuc',
         '<(DEPTH)/third_party/libxml/libxml.gyp:libxml',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 015a219a..593f2e6f70 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -657,6 +657,7 @@
       'browser/chromeos/login/enrollment/mock_enrollment_screen.cc',
       'browser/chromeos/login/enrollment/mock_enrollment_screen.h',
       'browser/chromeos/login/existing_user_controller_browsertest.cc',
+      'browser/chromeos/login/hid_detection_browsertest.cc',
       'browser/chromeos/login/kiosk_browsertest.cc',
       'browser/chromeos/login/lock/screen_locker_tester.cc',
       'browser/chromeos/login/lock/screen_locker_tester.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index e49743e..21b25630 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -541,6 +541,7 @@
       'common/chrome_paths_unittest.cc',
       'common/cloud_print/cloud_print_helpers_unittest.cc',
       'common/crash_keys_unittest.cc',
+      'common/favicon/fallback_icon_url_parser_unittest.cc',
       'common/favicon/favicon_url_parser_unittest.cc',
       'common/ini_parser_unittest.cc',
       'common/instant_types_unittest.cc',
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index c08ea657..902b803 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -989,8 +989,7 @@
     "extension_types": ["extension", "legacy_packaged_app", "hosted_app"],
     "whitelist": [
       "B44D08FD98F1523ED5837D78D0A606EA9D6206E5",  // Web Store
-      "2653F6F6C39BC6EEBD36A09AFB92A19782FF7EB4",  // Enterprise Web Store
-      "2779FA8B45841D61A37207CCFAC9CB393964FE5B"   // Login Proxy (prototype)
+      "2653F6F6C39BC6EEBD36A09AFB92A19782FF7EB4"   // Enterprise Web Store
     ]
   }
 }
diff --git a/chrome/common/favicon/fallback_icon_url_parser.cc b/chrome/common/favicon/fallback_icon_url_parser.cc
new file mode 100644
index 0000000..418617f
--- /dev/null
+++ b/chrome/common/favicon/fallback_icon_url_parser.cc
@@ -0,0 +1,84 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/favicon/fallback_icon_url_parser.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "third_party/skia/include/utils/SkParse.h"
+#include "ui/gfx/favicon_size.h"
+
+namespace chrome {
+
+ParsedFallbackIconPath::ParsedFallbackIconPath()
+    : size_in_pixels_(gfx::kFaviconSize) {
+}
+
+ParsedFallbackIconPath::~ParsedFallbackIconPath() {
+}
+
+bool ParsedFallbackIconPath::Parse(const std::string& path) {
+  if (path.empty())
+    return false;
+
+  size_t slash = path.find("/", 0);
+  if (slash == std::string::npos)
+    return false;
+  std::string spec_str = path.substr(0, slash);
+  if (!ParseSpecs(spec_str, &size_in_pixels_, &style_))
+    return false;  // Parse failed.
+
+  // Extract URL, which may be empty (if first slash appears at the end).
+  std::string url_str = path.substr(slash + 1);
+  url_ = GURL(url_str);
+  return url_str.empty() || url_.is_valid();  // Allow empty URL.
+}
+
+// static
+bool ParsedFallbackIconPath::ParseSpecs(
+    const std::string& specs_str,
+    int *size,
+    favicon_base::FallbackIconStyle* style) {
+  DCHECK(size);
+  DCHECK(style);
+
+  std::vector<std::string> tokens;
+  base::SplitStringDontTrim(specs_str, ',', &tokens);
+  if (tokens.size() != 5)  // Force "," for empty fields.
+    return false;
+
+  *size = gfx::kFaviconSize;
+  if (!tokens[0].empty() && !base::StringToInt(tokens[0], size))
+    return false;
+  if (*size <= 0)
+    return false;
+
+  if (!tokens[1].empty() && !ParseColor(tokens[1], &style->background_color))
+    return false;
+
+  if (tokens[2].empty())
+    favicon_base::MatchFallbackIconTextColorAgainstBackgroundColor(style);
+  else if (!ParseColor(tokens[2], &style->text_color))
+    return false;
+
+  if (!tokens[3].empty() &&
+      !base::StringToDouble(tokens[3], &style->font_size_ratio))
+    return false;
+
+  if (!tokens[4].empty() && !base::StringToDouble(tokens[4], &style->roundness))
+    return false;
+
+  return favicon_base::ValidateFallbackIconStyle(*style);
+}
+
+// static
+bool ParsedFallbackIconPath::ParseColor(const std::string& color_str,
+                                        SkColor* color) {
+  const char* end = SkParse::FindColor(color_str.c_str(), color);
+  // Return true if FindColor() succeeds and |color_str| is entirely consumed.
+  return end && !*end;
+}
+
+}  // namespace chrome
diff --git a/chrome/common/favicon/fallback_icon_url_parser.h b/chrome/common/favicon/fallback_icon_url_parser.h
new file mode 100644
index 0000000..12a068f4
--- /dev/null
+++ b/chrome/common/favicon/fallback_icon_url_parser.h
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
+#define CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "components/favicon_base/fallback_icon_style.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "url/gurl.h"
+
+namespace chrome {
+
+class ParsedFallbackIconPath {
+ public:
+  ParsedFallbackIconPath();
+  ~ParsedFallbackIconPath();
+
+  const GURL& url() const { return url_; }
+
+  int size_in_pixels() const { return size_in_pixels_; }
+
+  const favicon_base::FallbackIconStyle& style() const { return style_; }
+
+  // Parses |path|, which should be in the format described at the top of the
+  // file "chrome/browser/ui/webui/fallback_icon_source.h".
+  bool Parse(const std::string& path);
+
+ private:
+  // Parses |specs_str|, which should be the comma-separated value portion
+  // in the format described at the top of the file
+  // "chrome/browser/ui/webui/fallback_icon_source.h".
+  static bool ParseSpecs(const std::string& specs_str,
+                         int *size,
+                         favicon_base::FallbackIconStyle* style);
+
+  // Helper to parse color string (e.g., "red", "#f00", "#fF0000"). Returns true
+  // on success.
+  static bool ParseColor(const std::string& color_str, SkColor* color);
+
+  friend class FallbackIconUrlParserTest;
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorSuccess);
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseColorFailure);
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsEmpty);
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsPartial);
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFull);
+  FRIEND_TEST_ALL_PREFIXES(FallbackIconUrlParserTest, ParseSpecsFailure);
+
+  // The page URL the fallback icon is requested for.
+  GURL url_;
+
+  // The size of the requested fallback icon in pixels.
+  int size_in_pixels_;
+
+  // Styling specifications of fallback icon.
+  favicon_base::FallbackIconStyle style_;
+
+  DISALLOW_COPY_AND_ASSIGN(ParsedFallbackIconPath);
+};
+
+}  // namespace chrome
+
+#endif  // CHROME_COMMON_FAVICON_FALLBACK_ICON_URL_PARSER_H_
diff --git a/chrome/common/favicon/fallback_icon_url_parser_unittest.cc b/chrome/common/favicon/fallback_icon_url_parser_unittest.cc
new file mode 100644
index 0000000..76a761c0
--- /dev/null
+++ b/chrome/common/favicon/fallback_icon_url_parser_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/favicon/fallback_icon_url_parser.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "components/favicon_base/fallback_icon_style.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/favicon_size.h"
+#include "url/gurl.h"
+
+using chrome::ParsedFallbackIconPath;
+using favicon_base::FallbackIconStyle;
+
+namespace chrome {
+
+namespace {
+
+// Default values for FallbackIconStyle, from
+// /components/favicon_base/fallback_icon_style.h
+SkColor kDefaultBackgroundColor = SkColorSetRGB(0x80, 0x80, 0x80);
+SkColor kDefaultTextColorDark = SK_ColorBLACK;
+SkColor kDefaultTextColorLight = SK_ColorWHITE;
+double kDefaultFontSizeRatio = 0.8;
+double kDefaultRoundness = 0.125;  // 1 / 8.
+
+const char kTestUrlStr[] = "https://www.google.ca/imghp?hl=en&tab=wi";
+
+}  // namespace
+
+class FallbackIconUrlParserTest : public testing::Test {
+ public:
+  FallbackIconUrlParserTest() {
+  }
+
+  bool ParseSpecs(const std::string& specs_str,
+                  int *size,
+                  favicon_base::FallbackIconStyle* style) {
+    return ParsedFallbackIconPath::ParseSpecs(specs_str, size, style);
+  }
+
+  bool ParseColor(const std::string& color_str, SkColor* color) {
+    int size_dummy;
+    favicon_base::FallbackIconStyle style;
+    std::string spec_str = "16," + color_str + ",,,";
+    if (!ParseSpecs(spec_str, &size_dummy, &style))
+      return false;
+    *color = style.background_color;
+    return true;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FallbackIconUrlParserTest);
+};
+
+TEST_F(FallbackIconUrlParserTest, ParseColorSuccess) {
+  SkColor c;
+  EXPECT_TRUE(ParseColor("#01aBf0f4", &c));
+  EXPECT_EQ(SkColorSetARGB(0x01, 0xAB, 0xF0, 0xF4), c);
+  EXPECT_TRUE(ParseColor("#01aBf0", &c));
+  EXPECT_EQ(SkColorSetRGB(0x01, 0xAB, 0xF0), c);
+  EXPECT_TRUE(ParseColor("#01a", &c));
+  EXPECT_EQ(SkColorSetRGB(0x00, 0x11, 0xAA), c);
+  EXPECT_TRUE(ParseColor("#000000", &c));
+  EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0x00), c);
+  EXPECT_TRUE(ParseColor("red", &c));
+  EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), c);
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseColorFailure) {
+  const char* test_cases[] = {
+    "#00000",
+    "#000000000",
+    " #000000",
+    "#ABCDEFG",
+    "000000",
+    "#000000 ",
+  };
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    SkColor c;
+    EXPECT_FALSE(ParseColor(test_cases[i], &c))
+         << "test_cases[" << i << "]";
+  }
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseSpecsEmpty) {
+  int size;
+  FallbackIconStyle style;
+  EXPECT_TRUE(ParseSpecs(",,,,", &size, &style));
+  EXPECT_EQ(16, size);
+  EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+  EXPECT_EQ(kDefaultTextColorLight, style.text_color);
+  EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
+  EXPECT_EQ(kDefaultRoundness, style.roundness);
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseSpecsPartial) {
+  int size;
+  FallbackIconStyle style;
+  EXPECT_TRUE(ParseSpecs(",,#aCE,,0.1", &size, &style));
+  EXPECT_EQ(16, size);
+  EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+  EXPECT_EQ(SkColorSetRGB(0xAA, 0xCC, 0xEE), style.text_color);
+  EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
+  EXPECT_EQ(0.1, style.roundness);
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseSpecsFull) {
+  int size;
+
+  {
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs("16,#000,#f01,0.75,0.25", &size, &style));
+    EXPECT_EQ(16, size);
+    EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+    EXPECT_EQ(SkColorSetRGB(0xff, 0x00, 0x11), style.text_color);
+    EXPECT_EQ(0.75, style.font_size_ratio);
+    EXPECT_EQ(0.25, style.roundness);
+  }
+
+  {
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs("48,black,#123456,0.5,0.3", &size, &style));
+    EXPECT_EQ(48, size);
+    EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+    EXPECT_EQ(SkColorSetRGB(0x12, 0x34, 0x56), style.text_color);
+    EXPECT_EQ(0.5, style.font_size_ratio);
+    EXPECT_EQ(0.3, style.roundness);
+  }
+
+  {
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs("1,#000,red,0,0", &size, &style));
+    EXPECT_EQ(1, size);
+    EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+    EXPECT_EQ(SkColorSetRGB(0xFF, 0x00, 0x00), style.text_color);
+    EXPECT_EQ(0, style.font_size_ratio);
+    EXPECT_EQ(0, style.roundness);
+  }
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseSpecsDefaultTextColor) {
+  int size;
+
+  {
+    // Dark background -> Light text.
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs(",#000,,,", &size, &style));
+    EXPECT_EQ(kDefaultTextColorLight, style.text_color);
+  }
+
+  {
+    // Light background -> Dark text.
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs(",#fff,,,", &size, &style));
+    EXPECT_EQ(kDefaultTextColorDark, style.text_color);
+  }
+
+  {
+    // Light background -> Dark text, more params don't matter.
+    FallbackIconStyle style;
+    EXPECT_TRUE(ParseSpecs("107,#fff,,0.3,0.5", &size, &style));
+    EXPECT_EQ(kDefaultTextColorDark, style.text_color);
+  }
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseSpecsFailure) {
+  const char* test_cases[] = {
+    // Need exactly 5 params.
+    "",
+    "16",
+    "16,black",
+    "16,black,#fff",
+    "16,black,#fff,0.75",
+    ",,,"
+    ",,,,,",
+    "16,black,#fff,0.75,0.25,junk",
+    // Don't allow any space.
+    "16,black,#fff, 0.75,0.25",
+    "16,black ,#fff,0.75,0.25",
+    "16,black,#fff,0.75,0.25 ",
+    // Adding junk text.
+    "16,black,#fff,0.75,0.25junk",
+    "junk,black,#fff,0.75,0.25",
+    "16,#junk,#fff,0.75,0.25",
+    "16,black,#junk,0.75,0.25",
+    "16,black,#fff,junk,0.25",
+    "16,black,#fff,0.75,junk",
+    // Out of bound.
+    "0,black,#fff,0.75,0.25",  // size.
+    "4294967296,black,#fff,0.75,0.25",  // size.
+    "-1,black,#fff,0.75,0.25",  // size.
+    "16,black,#fff,-0.1,0.25",  // font_size_ratio.
+    "16,black,#fff,1.1,0.25",  // font_size_ratio.
+    "16,black,#fff,0.75,-0.1",  // roundness.
+    "16,black,#fff,0.75,1.1",  // roundness.
+  };
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    int size;
+    FallbackIconStyle style;
+    EXPECT_FALSE(ParseSpecs(test_cases[i], &size, &style))
+        << "test_cases[" << i << "]";
+
+  }
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathSuccess) {
+  const std::string specs = "31,black,#fff,0.75,0.25";
+
+  // Everything populated.
+  {
+    chrome::ParsedFallbackIconPath parsed;
+    EXPECT_TRUE(parsed.Parse(specs + "/" + kTestUrlStr));
+    EXPECT_EQ(GURL(kTestUrlStr), parsed.url());
+    EXPECT_EQ(31, parsed.size_in_pixels());
+    const favicon_base::FallbackIconStyle& style = parsed.style();
+    EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+    EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
+    EXPECT_EQ(0.75, style.font_size_ratio);
+    EXPECT_EQ(0.25, style.roundness);
+  }
+
+  // Empty URL.
+  {
+    chrome::ParsedFallbackIconPath parsed;
+    EXPECT_TRUE(parsed.Parse(specs + "/"));
+    EXPECT_EQ(GURL(), parsed.url());
+    EXPECT_EQ(31, parsed.size_in_pixels());
+    const favicon_base::FallbackIconStyle& style = parsed.style();
+    EXPECT_EQ(SkColorSetRGB(0x00, 0x00, 0x00), style.background_color);
+    EXPECT_EQ(SkColorSetRGB(0xFF, 0xFF, 0xFF), style.text_color);
+    EXPECT_EQ(0.75, style.font_size_ratio);
+    EXPECT_EQ(0.25, style.roundness);
+  }
+
+  // Size and style are default.
+  {
+    chrome::ParsedFallbackIconPath parsed;
+    EXPECT_TRUE(parsed.Parse(std::string(",,,,/") + kTestUrlStr));
+    EXPECT_EQ(GURL(kTestUrlStr), parsed.url());
+    EXPECT_EQ(gfx::kFaviconSize, parsed.size_in_pixels());
+    const favicon_base::FallbackIconStyle& style = parsed.style();
+    EXPECT_EQ(kDefaultBackgroundColor, style.background_color);
+    EXPECT_EQ(kDefaultTextColorLight, style.text_color);
+    EXPECT_EQ(kDefaultFontSizeRatio, style.font_size_ratio);
+    EXPECT_EQ(kDefaultRoundness, style.roundness);
+  }
+}
+
+TEST_F(FallbackIconUrlParserTest, ParseFallbackIconPathFailure) {
+  const char* test_cases[] = {
+    // Bad size.
+    "-1,#000,#fff,0.75,0.25/http://www.google.com/",
+    // Bad specs.
+    "32,#junk,#fff,0.75,0.25/http://www.google.com/",
+    // Bad URL.
+    "32,#000,#fff,0.75,0.25/NOT A VALID URL",
+  };
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    chrome::ParsedFallbackIconPath parsed;
+    EXPECT_FALSE(parsed.Parse(test_cases[i])) << "test_cases[" << i << "]";
+  }
+}
+
+}  // namespace chrome
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 518c0ae3..46cc10ae 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -361,14 +361,6 @@
 // window when the user is attempting to quit. Mac only.
 const char kConfirmToQuitEnabled[] = "browser.confirm_to_quit";
 
-// OBSOLETE.  Enum that specifies whether to enforce a third-party cookie
-// blocking policy.  This has been superseded by kDefaultContentSettings +
-// kBlockThirdPartyCookies.
-// 0 - allow all cookies.
-// 1 - block third-party cookies
-// 2 - block all cookies
-const char kCookieBehavior[] = "security.cookie_behavior";
-
 // Boolean which specifies whether we should ask the user if we should download
 // a file (true) or just download it automatically.
 const char kPromptForDownload[] = "download.prompt_for_download";
@@ -376,18 +368,10 @@
 // A boolean pref set to true if we're using Link Doctor error pages.
 const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled";
 
-// OBSOLETE: new pref now stored with user prefs instead of profile, as
-// kDnsPrefetchingStartupList.
-const char kDnsStartupPrefetchList[] = "StartupDNSPrefetchList";
-
 // An adaptively identified list of domain names to be pre-fetched during the
 // next startup, based on what was actually needed during this startup.
 const char kDnsPrefetchingStartupList[] = "dns_prefetching.startup_list";
 
-// OBSOLETE: new pref now stored with user prefs instead of profile, as
-// kDnsPrefetchingHostReferralList.
-const char kDnsHostReferralList[] = "HostReferralList";
-
 // A list of host names used to fetch web pages, and their commonly used
 // sub-resource hostnames (and expected latency benefits from pre-resolving, or
 // preconnecting to, such sub-resource hostnames).
@@ -421,16 +405,6 @@
 const char kInstantUIZeroSuggestUrlPrefix[] =
     "instant_ui.zero_suggest_url_prefix";
 
-// Used to migrate preferences from local state to user preferences to
-// enable multiple profiles.
-// BITMASK with possible values (see browser_prefs.cc for enum):
-// 0: No preferences migrated.
-// 1: DNS preferences migrated: kDnsPrefetchingStartupList and HostReferralList
-// 2: Browser window preferences migrated: kDevToolsSplitLocation and
-//    kBrowserWindowPlacement
-const char kMultipleProfilePrefMigration[] =
-    "local_state.multiple_profile_prefs_version";
-
 // A boolean pref set to true if prediction of network actions is allowed.
 // Actions include DNS prefetching, TCP and SSL preconnection, prerendering
 // of web pages, and resource prefetching.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 29875f2..379cfbd 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -149,12 +149,9 @@
 extern const char kContextualSearchEnabled[];
 #endif
 extern const char kConfirmToQuitEnabled[];
-extern const char kCookieBehavior[];  // OBSOLETE
 extern const char kPromptForDownload[];
 extern const char kAlternateErrorPagesEnabled[];
-extern const char kDnsStartupPrefetchList[];  // OBSOLETE
 extern const char kDnsPrefetchingStartupList[];
-extern const char kDnsHostReferralList[];  // OBSOLETE
 extern const char kDnsPrefetchingHostReferralList[];
 extern const char kDisableSpdy[];
 extern const char kHttpServerProperties[];
@@ -165,7 +162,6 @@
 extern const char kLastPolicyCheckTime[];
 #endif
 extern const char kInstantUIZeroSuggestUrlPrefix[];
-extern const char kMultipleProfilePrefMigration[];
 extern const char kNetworkPredictionEnabled[];
 extern const char kNetworkPredictionOptions[];
 extern const char kDefaultAppsInstallState[];
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index 7b2fbc3..b3467bc2 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -5,6 +5,7 @@
 #include "chrome/installer/util/google_update_settings.h"
 
 #include <algorithm>
+#include <limits>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -70,7 +71,7 @@
 bool WriteGoogleUpdateAggregateNumKeyInternal(
     const AppRegistrationData& app_reg_data,
     const wchar_t* const name,
-    int value,
+    size_t value,
     const wchar_t* const aggregate) {
   DCHECK(aggregate);
   DCHECK(GoogleUpdateSettings::IsSystemInstall());
@@ -90,7 +91,11 @@
   reg_path.append(name);
   RegKey key(HKEY_LOCAL_MACHINE, reg_path.c_str(), kAccess);
   key.WriteValue(google_update::kRegAggregateMethod, aggregate);
-  return (key.WriteValue(uniquename.c_str(), value) == ERROR_SUCCESS);
+
+  DWORD dword_value = (value > std::numeric_limits<DWORD>::max() ?
+      std::numeric_limits<DWORD>::max() :
+      static_cast<DWORD>(value));
+  return (key.WriteValue(uniquename.c_str(), dword_value) == ERROR_SUCCESS);
 }
 
 // Updates a registry key |name| to be |value| for the given |app_reg_data|.
@@ -546,8 +551,8 @@
   return modified;
 }
 
-void GoogleUpdateSettings::UpdateProfileCounts(int profiles_active,
-                                               int profiles_signedin) {
+void GoogleUpdateSettings::UpdateProfileCounts(size_t profiles_active,
+                                               size_t profiles_signedin) {
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
   // System-level installs must write into the ClientStateMedium key shared by
   // all users. Special treatment is used to aggregate across those users.
@@ -569,10 +574,10 @@
     // user-level installs.
     WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
                                     google_update::kRegProfilesActive,
-                                    base::IntToString16(profiles_active));
+                                    base::SizeTToString16(profiles_active));
     WriteGoogleUpdateStrKeyInternal(dist->GetAppRegistrationData(),
                                     google_update::kRegProfilesSignedIn,
-                                    base::IntToString16(profiles_signedin));
+                                    base::SizeTToString16(profiles_signedin));
   }
 }
 
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index ea5a7d58..e3a0168 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -218,7 +218,8 @@
 
   // This method updates the values that report how many profiles are in use
   // and how many of those are signed-in.
-  static void UpdateProfileCounts(int profiles_active, int profiles_signedin);
+  static void UpdateProfileCounts(size_t profiles_active,
+                                  size_t profiles_signedin);
 
   // For system-level installs, we need to be able to communicate the results
   // of the Toast Experiments back to Google Update. The problem is just that
diff --git a/chrome/renderer/autofill/autofill_renderer_browsertest.cc b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
index 26840bb..49a83665 100644
--- a/chrome/renderer/autofill/autofill_renderer_browsertest.cc
+++ b/chrome/renderer/autofill/autofill_renderer_browsertest.cc
@@ -250,7 +250,7 @@
   // Shouldn't crash.
 }
 
-TEST_F(AutofillRendererTest, DISABLED_DynamicallyAddedUnownedFormElements) {
+TEST_F(AutofillRendererTest, DynamicallyAddedUnownedFormElements) {
   std::string html_data;
   base::FilePath test_path = ui_test_utils::GetTestFilePath(
       base::FilePath(FILE_PATH_LITERAL("autofill")),
diff --git a/chrome/renderer/autofill/form_autofill_browsertest.cc b/chrome/renderer/autofill/form_autofill_browsertest.cc
index a447229..24b5f05c 100644
--- a/chrome/renderer/autofill/form_autofill_browsertest.cc
+++ b/chrome/renderer/autofill/form_autofill_browsertest.cc
@@ -2393,7 +2393,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FindFormForInputElementForUnownedForm) {
+TEST_F(FormAutofillTest, FindFormForInputElementForUnownedForm) {
     TestFindFormForInputElement(
         "<INPUT type='text' id='firstname' value='John'/>"
         "<INPUT type='text' id='lastname' value='Smith'/>"
@@ -2420,7 +2420,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FindFormForTextAreaElementForUnownedForm) {
+TEST_F(FormAutofillTest, FindFormForTextAreaElementForUnownedForm) {
   TestFindFormForTextAreaElement(
       "<INPUT type='text' id='firstname' value='John'/>"
       "<INPUT type='text' id='lastname' value='Smith'/>"
@@ -2439,7 +2439,7 @@
   TestFillForm(kFormHtml, false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormForUnownedForm) {
   TestFillForm(kUnownedFormHtml, true);
 }
 
@@ -2531,7 +2531,7 @@
   TestPreviewForm(kFormHtml, false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_PreviewFormForUnownedForm) {
+TEST_F(FormAutofillTest, PreviewFormForUnownedForm) {
   TestPreviewForm(kUnownedFormHtml, true);
 }
 
@@ -3406,7 +3406,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormMaxLengthForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormMaxLengthForUnownedForm) {
   TestFillFormMaxLength(
       "<INPUT type='text' id='firstname' maxlength='5'/>"
       "<INPUT type='text' id='lastname' maxlength='7'/>"
@@ -3429,7 +3429,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormNegativeMaxLengthForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormNegativeMaxLengthForUnownedForm) {
   TestFillFormNegativeMaxLength(
       "<INPUT type='text' id='firstname' maxlength='-1'/>"
       "<INPUT type='text' id='lastname' maxlength='-10'/>"
@@ -3449,7 +3449,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormEmptyNameForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormEmptyNameForUnownedForm) {
   TestFillFormEmptyName(
       "<INPUT type='text' id='firstname'/>"
       "<INPUT type='text' id='lastname'/>"
@@ -3475,7 +3475,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormEmptyFormNamesForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormEmptyFormNamesForUnownedForm) {
   TestFillFormEmptyFormNames(
       "<INPUT type='text' id='firstname'/>"
       "<INPUT type='text' id='middlename'/>"
@@ -3631,7 +3631,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_FillFormNonEmptyFieldForUnownedForm) {
+TEST_F(FormAutofillTest, FillFormNonEmptyFieldForUnownedForm) {
   TestFillFormNonEmptyField("<INPUT type='text' id='firstname'/>"
                             "<INPUT type='text' id='lastname'/>"
                             "<INPUT type='text' id='email'/>"
@@ -3659,7 +3659,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest, DISABLED_ClearFormWithNodeForUnownedForm) {
+TEST_F(FormAutofillTest, ClearFormWithNodeForUnownedForm) {
   TestClearFormWithNode(
       "  <!-- Indented on purpose //-->"
       "  <INPUT type='text' id='firstname' value='Wyatt'/>"
@@ -3694,8 +3694,7 @@
       false);
 }
 
-TEST_F(FormAutofillTest,
-       DISABLED_ClearFormWithNodeContainingSelectOneForUnownedForm) {
+TEST_F(FormAutofillTest, ClearFormWithNodeContainingSelectOneForUnownedForm) {
   TestClearFormWithNodeContainingSelectOne(
       "<INPUT type='text' id='firstname' value='Wyatt'/>"
       "<INPUT type='text' id='lastname' value='Earp'/>"
@@ -3721,7 +3720,7 @@
       "</FORM>");
 }
 
-TEST_F(FormAutofillTest, DISABLED_ClearPreviewedFormWithElementForUnownedForm) {
+TEST_F(FormAutofillTest, ClearPreviewedFormWithElementForUnownedForm) {
   TestClearPreviewedFormWithElement(
       "<INPUT type='text' id='firstname' value='Wyatt'/>"
       "<INPUT type='text' id='lastname'/>"
@@ -3744,7 +3743,7 @@
 }
 
 TEST_F(FormAutofillTest,
-       DISABLED_ClearPreviewedFormWithNonEmptyInitiatingNodeForUnownedForm) {
+       ClearPreviewedFormWithNonEmptyInitiatingNodeForUnownedForm) {
   TestClearPreviewedFormWithNonEmptyInitiatingNode(
       "<INPUT type='text' id='firstname' value='W'/>"
       "<INPUT type='text' id='lastname'/>"
@@ -3767,7 +3766,7 @@
 }
 
 TEST_F(FormAutofillTest,
-       DISABLED_ClearPreviewedFormWithAutofilledInitiatingNodeForUnownedForm) {
+       ClearPreviewedFormWithAutofilledInitiatingNodeForUnownedForm) {
   TestClearPreviewedFormWithAutofilledInitiatingNode(
       "<INPUT type='text' id='firstname' value='W'/>"
       "<INPUT type='text' id='lastname'/>"
@@ -3789,7 +3788,7 @@
       "</FORM>");
 }
 
-TEST_F(FormAutofillTest, DISABLED_ClearOnlyAutofilledFieldsForUnownedForm) {
+TEST_F(FormAutofillTest, ClearOnlyAutofilledFieldsForUnownedForm) {
   TestClearOnlyAutofilledFields(
       "<INPUT type='text' id='firstname' value='Wyatt'/>"
       "<INPUT type='text' id='lastname' value='Earp'/>"
@@ -3948,7 +3947,7 @@
 }
 
 TEST_F(FormAutofillTest,
-       DISABLED_UnownedFormElementsAndFieldSetsToFormDataFieldsets) {
+       UnownedFormElementsAndFieldSetsToFormDataFieldsets) {
   std::vector<WebElement> fieldsets;
   std::vector<WebFormControlElement> control_elements;
 
@@ -4010,7 +4009,7 @@
 }
 
 TEST_F(FormAutofillTest,
-       DISABLED_UnownedFormElementsAndFieldSetsToFormDataControlOutsideOfFieldset) {
+       UnownedFormElementsAndFieldSetsToFormDataControlOutsideOfFieldset) {
   std::vector<WebElement> fieldsets;
   std::vector<WebFormControlElement> control_elements;
 
@@ -4069,8 +4068,7 @@
   EXPECT_FORM_FIELD_DATA_EQUALS(expected, fields[2]);
 }
 
-TEST_F(FormAutofillTest,
-       DISABLED_UnownedFormElementsAndFieldSetsToFormDataWithForm) {
+TEST_F(FormAutofillTest, UnownedFormElementsAndFieldSetsToFormDataWithForm) {
   std::vector<WebElement> fieldsets;
   std::vector<WebFormControlElement> control_elements;
 
diff --git a/chrome/renderer/resources/neterror.css b/chrome/renderer/resources/neterror.css
index e93543c..a630a5a1 100644
--- a/chrome/renderer/resources/neterror.css
+++ b/chrome/renderer/resources/neterror.css
@@ -58,6 +58,10 @@
   position: relative;
 }
 
+.error-code {
+  display: block;
+}
+
 #content-top {
   margin: 20px;
 }
@@ -130,6 +134,12 @@
   margin: auto;
 }
 
+.secondary-button {
+  -webkit-margin-end: 16px;
+  background: #d9d9d9;
+  color: #696969;
+}
+
 .hidden {
   display: none;
 }
@@ -147,12 +157,6 @@
   color: #777;
 }
 
-.error-code {
-  color: #A0A0A0;
-  font-size: .825em;
-  margin-top: 15px;
-}
-
 /* Increase line height at higher resolutions. */
 @media (min-width: 641px) and (min-height: 641px) {
   #help-box-inner {
@@ -240,26 +244,28 @@
 
 /* details-button is special; it's a <button> element that looks like a link. */
 #details-button {
-  background-color: inherit;
-  background-image: none;
-  border: none;
   box-shadow: none;
   min-width: 0;
-  padding: 0;
-  text-decoration: underline;
 }
 
 /* Styles for platform dependent separation of controls and details button. */
 .suggested-left > #control-buttons,
-.suggested-right > #details-button  {
+.suggested-left #stale-load-button,
+.suggested-right > #details-button {
   float: left;
 }
 
 .suggested-right > #control-buttons,
-.suggested-left > #details-button  {
+.suggested-right #stale-load-button,
+.suggested-left > #details-button {
   float: right;
 }
 
+.suggested-left .secondary-button {
+  -webkit-margin-end: 0px;
+  -webkit-margin-start: 16px;
+}
+
 #details-button.singular {
   float: none;
 }
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html
index d397f4a4..bf1f1b47 100644
--- a/chrome/renderer/resources/neterror.html
+++ b/chrome/renderer/resources/neterror.html
@@ -19,6 +19,7 @@
       <div id="main-message">
         <h1 i18n-content="heading"></h1>
         <p hidden></p>
+        <div class="error-code" jscontent="errorCode"></div>
       </div>
     </div>
     <div id="buttons" class="nav-wrapper">
@@ -66,7 +67,6 @@
           </button>
         </div>
       </form>
-      <div class="error-code" jscontent="errorCode"></div>
     </div>
   </div>
   <div id="sub-frame-error">
diff --git a/chrome/renderer/resources/neterror.js b/chrome/renderer/resources/neterror.js
index 5929643..cee640f 100644
--- a/chrome/renderer/resources/neterror.js
+++ b/chrome/renderer/resources/neterror.js
@@ -12,8 +12,13 @@
     detailsButton.innerText = detailsButton.hideDetailsText;
 
   // Details appears over the main content on small screens.
-  if (mobileNav)
+  if (mobileNav) {
     document.getElementById('main-content').classList.toggle('hidden');
+    var runnerContainer = document.querySelector('.runner-container');
+    if (runnerContainer) {
+      runnerContainer.classList.toggle('hidden');
+    }
+  }
 }
 
 function diagnoseErrors() {
@@ -142,7 +147,6 @@
   if (loadTimeData.valueExists('summary') &&
           !loadTimeData.getValue('summary').msg) {
     detailsButton.style.display = 'none';
-    document.getElementById('details').style.display = 'block';
   }
 </if>
 
diff --git a/chrome/renderer/resources/offline.js b/chrome/renderer/resources/offline.js
index fbf46d9..75404cc 100644
--- a/chrome/renderer/resources/offline.js
+++ b/chrome/renderer/resources/offline.js
@@ -793,6 +793,11 @@
     // our canvas element.
     context.scale(ratio, ratio);
     return true;
+  } else if (devicePixelRatio == 1) {
+    // Reset the canvas width / height. Fixes scaling bug when the page is
+    // zoomed and the devicePixelRatio changes accordingly.
+    canvas.style.width = canvas.width + 'px';
+    canvas.style.height = canvas.height + 'px';
   }
   return false;
 };
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7082051..8341315 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -215,7 +215,7 @@
   ]
 }
 
-if (!is_android && (!is_win || link_chrome_on_windows)) {
+if (!is_android) {
   import("//chrome/chrome_tests.gni")
 
   test("interactive_ui_tests") {
diff --git a/chrome/test/data/extensions/api_test/bindings/api_enums/background.js b/chrome/test/data/extensions/api_test/bindings/api_enums/background.js
new file mode 100644
index 0000000..c795e4e
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/api_enums/background.js
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+chrome.test.runTests([
+  function() {
+    // Test management (backed by a json file) api enums.
+
+    // The enum should be declared on the API object.
+    chrome.test.assertTrue(
+        'LaunchType' in chrome.management,
+        '"LaunchType" is not present on chrome.management.');
+    // The object should have entries for each enum entry. Note that we don't
+    // test all entries here because we don't want to update this test if the
+    // management api changes.
+    chrome.test.assertTrue(
+        'OPEN_AS_REGULAR_TAB' in chrome.management.LaunchType,
+        '"OPEN_AS_REGULAR_TAB" is not present on management.LaunchType');
+    // The value of the enum should be its string value.
+    chrome.test.assertEq(chrome.management.LaunchType.OPEN_AS_REGULAR_TAB,
+                         'OPEN_AS_REGULAR_TAB');
+    // There should be more than one value for the enum.
+    chrome.test.assertTrue(
+        Object.keys(chrome.management.LaunchType).length > 1);
+
+    // Perform an analogous test for the notifications api (backed by an idl).
+    chrome.test.assertTrue(
+        'PermissionLevel' in chrome.notifications,
+        '"PermissionLevel" is not present on chrome.notifications.');
+    chrome.test.assertTrue(
+        'granted' in chrome.notifications.PermissionLevel,
+        '"granted" is not present on notifications.PermissionLevel');
+    chrome.test.assertEq(chrome.notifications.PermissionLevel.granted,
+                         'granted');
+    chrome.test.assertTrue(
+        Object.keys(chrome.notifications.PermissionLevel).length > 1);
+
+    chrome.test.succeed();
+  }
+]);
diff --git a/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json b/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json
new file mode 100644
index 0000000..49c3850
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/bindings/api_enums/manifest.json
@@ -0,0 +1,9 @@
+{
+  "name": "bindings/api_enums",
+  "manifest_version": 2,
+  "version": "1",
+  "background": {
+    "scripts": ["background.js"]
+  },
+  "permissions": ["management", "notifications"]
+}
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html
index 8060cb2..f7d49cd 100644
--- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html
+++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.html
@@ -6,6 +6,7 @@
 
 <html>
 <body>
+<input id="textfield" type="text">
 <script src="main.js"></script>
 </body>
 </html>
diff --git a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
index bd16ca6..ce4fdc07 100644
--- a/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
+++ b/chrome/test/data/extensions/platform_apps/custom_launcher_page/main.js
@@ -31,4 +31,15 @@
   });
 }
 
-chrome.test.sendMessage('Launched');
+document.addEventListener('DOMContentLoaded', function() {
+  chrome.test.sendMessage('Launched');
+});
+
+var textfield = document.getElementById('textfield');
+textfield.onfocus = function() {
+  chrome.test.sendMessage('textfieldFocused');
+};
+
+textfield.onblur = function() {
+  chrome.test.sendMessage('textfieldBlurred');
+};
diff --git a/chrome/test/data/notifications/android_test_worker.js b/chrome/test/data/notifications/android_test_worker.js
index 421494a..f2a2de5 100644
--- a/chrome/test/data/notifications/android_test_worker.js
+++ b/chrome/test/data/notifications/android_test_worker.js
@@ -8,3 +8,7 @@
   messagePort = event.data;
   messagePort.postMessage('ready');
 });
+
+addEventListener('notificationclick', function(event) {
+  event.notification.close();
+});
diff --git a/chromecast/media/cma/filters/cma_renderer.cc b/chromecast/media/cma/filters/cma_renderer.cc
index 799dd61..a8a46f5 100644
--- a/chromecast/media/cma/filters/cma_renderer.cc
+++ b/chromecast/media/cma/filters/cma_renderer.cc
@@ -75,7 +75,8 @@
     const ::media::BufferingStateCB& buffering_state_cb,
     const PaintCB& paint_cb,
     const base::Closure& ended_cb,
-    const ::media::PipelineStatusCB& error_cb) {
+    const ::media::PipelineStatusCB& error_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   CMALOG(kLogControl) << __FUNCTION__;
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK_EQ(state_, kUninitialized) << state_;
@@ -84,6 +85,7 @@
   DCHECK(!ended_cb.is_null());
   DCHECK(!error_cb.is_null());
   DCHECK(!buffering_state_cb.is_null());
+  DCHECK(!waiting_for_decryption_key_cb.is_null());
   DCHECK(demuxer_stream_provider->GetStream(::media::DemuxerStream::AUDIO) ||
          demuxer_stream_provider->GetStream(::media::DemuxerStream::VIDEO));
 
@@ -95,6 +97,8 @@
   paint_cb_ = paint_cb;
   ended_cb_ = ended_cb;
   error_cb_ = error_cb;
+  // TODO(erickung): wire up waiting_for_decryption_key_cb.
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
   MediaPipelineClient media_pipeline_client;
   media_pipeline_client.error_cb = error_cb_;
diff --git a/chromecast/media/cma/filters/cma_renderer.h b/chromecast/media/cma/filters/cma_renderer.h
index 33fc2b1..62efd7c 100644
--- a/chromecast/media/cma/filters/cma_renderer.h
+++ b/chromecast/media/cma/filters/cma_renderer.h
@@ -45,7 +45,8 @@
       const ::media::BufferingStateCB& buffering_state_cb,
       const PaintCB& paint_cb,
       const base::Closure& ended_cb,
-      const ::media::PipelineStatusCB& error_cb) override;
+      const ::media::PipelineStatusCB& error_cb,
+      const base::Closure& waiting_for_decryption_key_cb) override;
   void Flush(const base::Closure& flush_cb) override;
   void StartPlayingFrom(base::TimeDelta time) override;
   void SetPlaybackRate(float playback_rate) override;
@@ -108,6 +109,7 @@
   ::media::PipelineStatusCB error_cb_;
   ::media::BufferingStateCB buffering_state_cb_;
   base::Closure flush_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // Renderer state.
   // Used mostly for checking that transitions are correct.
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 6297834..c5ff1e2 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-6835.0.0
\ No newline at end of file
+6836.0.0
\ No newline at end of file
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 9549971..3c945b1 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -261,6 +261,7 @@
 // Overrides network stub behavior. By default, ethernet, wifi and vpn are
 // enabled, and transitions occur instantaneously. Multiple options can be
 // comma separated (no spaces). Note: all options are in the format 'foo=x'.
+// Values are case sensitive and based on Shill names in service_constants.h.
 // See FakeShillManagerClient::SetInitialNetworkState for implementation.
 // Examples:
 //  'clear=1' - Clears all default configurations
@@ -270,6 +271,7 @@
 //  'wifi=none' - Wifi is unavailable
 //  'wifi=portal' - Wifi connection will be in Portal state
 //  'cellular=1' - Cellular is initially connected
+//  'cellular=LTE' - Cellular is initially connected, technology is LTE
 //  'interactive=3' - Interactive mode, connect/scan/etc requests take 3 secs
 const char kShillStub[] = "shill-stub";
 
diff --git a/chromeos/dbus/fake_shill_manager_client.cc b/chromeos/dbus/fake_shill_manager_client.cc
index 72dedef..2702ad9 100644
--- a/chromeos/dbus/fake_shill_manager_client.cc
+++ b/chromeos/dbus/fake_shill_manager_client.cc
@@ -105,6 +105,19 @@
                            base::StringValue(shill::kStatePortal));
 }
 
+bool IsCellularTechnology(const std::string& type) {
+  return (type == shill::kNetworkTechnology1Xrtt ||
+          type == shill::kNetworkTechnologyEvdo ||
+          type == shill::kNetworkTechnologyGsm ||
+          type == shill::kNetworkTechnologyGprs ||
+          type == shill::kNetworkTechnologyEdge ||
+          type == shill::kNetworkTechnologyUmts ||
+          type == shill::kNetworkTechnologyHspa ||
+          type == shill::kNetworkTechnologyHspaPlus ||
+          type == shill::kNetworkTechnologyLte ||
+          type == shill::kNetworkTechnologyLteAdvanced);
+}
+
 const char* kTechnologyUnavailable = "unavailable";
 const char* kNetworkActivated = "activated";
 const char* kNetworkDisabled = "disabled";
@@ -118,6 +131,7 @@
 
 FakeShillManagerClient::FakeShillManagerClient()
     : interactive_delay_(0),
+      cellular_technology_(shill::kNetworkTechnologyGsm),
       weak_ptr_factory_(this) {
   ParseCommandLineSwitch();
 }
@@ -776,7 +790,7 @@
                          shill::kTypeCellular,
                          state,
                          add_to_visible);
-    base::StringValue technology_value(shill::kNetworkTechnologyGsm);
+    base::StringValue technology_value(cellular_technology_);
     devices->SetDeviceProperty("/device/cellular1",
                                shill::kTechnologyFamilyProperty,
                                technology_value);
@@ -1066,7 +1080,6 @@
 bool FakeShillManagerClient::SetInitialNetworkState(std::string type_arg,
                                                     std::string state_arg) {
   std::string state;
-  state_arg = base::StringToLowerASCII(state_arg);
   if (state_arg.empty() || state_arg == "1" || state_arg == "on" ||
       state_arg == "enabled" || state_arg == "connected" ||
       state_arg == "online") {
@@ -1088,12 +1101,20 @@
   } else if (state_arg == "active" || state_arg == "activated") {
     // Technology is enabled, a service is connected and Activated.
     state = kNetworkActivated;
+  } else if (type_arg == shill::kTypeCellular &&
+             IsCellularTechnology(state_arg)) {
+    state = shill::kStateOnline;
+    cellular_technology_ = state_arg;
+  } else if (type_arg == shill::kTypeCellular && state_arg == "LTEAdvanced") {
+    // Special case, Shill name contains a ' '.
+    state = shill::kStateOnline;
+    cellular_technology_ = shill::kNetworkTechnologyLteAdvanced;
   } else {
-    LOG(ERROR) << "Unrecognized initial state: " << state_arg;
+    LOG(ERROR) << "Unrecognized initial state: " << type_arg << "="
+               << state_arg;
     return false;
   }
 
-  type_arg = base::StringToLowerASCII(type_arg);
   // Special cases
   if (type_arg == "wireless") {
     shill_initial_state_map_[shill::kTypeWifi] = state;
diff --git a/chromeos/dbus/fake_shill_manager_client.h b/chromeos/dbus/fake_shill_manager_client.h
index b21b2a1..61d1809 100644
--- a/chromeos/dbus/fake_shill_manager_client.h
+++ b/chromeos/dbus/fake_shill_manager_client.h
@@ -142,6 +142,9 @@
   // Initial state for fake services.
   std::map<std::string, std::string> shill_initial_state_map_;
 
+  // Technology type for fake cellular service.
+  std::string cellular_technology_;
+
   // Roaming state for fake cellular service.
   std::string roaming_state_;
 
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 95b02c9..39548d7a 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -40,6 +40,7 @@
     "//components/enhanced_bookmarks",
     "//components/favicon/core",
     "//components/favicon_base",
+    "//components/feedback",
     "//components/gcm_driver",
     "//components/google/core/browser",
     "//components/history/content/browser",
@@ -161,6 +162,7 @@
       "//components/domain_reliability",  # Blocked on content.
       "//components/favicon_base",  # Should work, needs checking.
       "//components/favicon/core",  # Blocked on keyed service.
+      "//components/feedback",  # Blocked on content.
       "//components/gcm_driver",  # Should work, needs checking.
       "//components/google/core/browser",  # Should work, needs checking.
       "//components/history/core/browser",  # Should work, needs checking.
@@ -202,7 +204,6 @@
   if (!is_ios && !is_android) {
     deps += [
       "//components/copresence",
-      "//components/feedback",
       "//components/storage_monitor",
     ]
   }
@@ -220,89 +221,87 @@
 # component (it's important to use a source_set instead of a static library or
 # no tests will run) and add a reference here. You can add more than one unit
 # test target if convenient.
-if (!is_win || link_chrome_on_windows) {
-  test("components_unittests") {
-    sources = [
-      "test/run_all_unittests.cc",
-    ]
+test("components_unittests") {
+  sources = [
+    "test/run_all_unittests.cc",
+  ]
 
-    # Add only ":unit_tests" dependencies here. If your tests have dependencies
-    # (this would at least include the component itself), they should be on the
-    # test source set and not here.
-    deps = [
-      "//components/auto_login_parser:unit_tests",
-      "//components/autofill/content/browser:unit_tests",
-      "//components/autofill/core/browser:unit_tests",
-      "//components/autofill/core/common:unit_tests",
-      "//components/bookmarks/browser:unit_tests",
-      "//components/captive_portal:unit_tests",
-      "//components/cloud_devices/common:unit_tests",
-      "//components/content_settings/core/browser:unit_tests",
-      "//components/content_settings/core/common:unit_tests",
-      "//components/crx_file:unit_tests",
-      "//components/data_reduction_proxy/core/browser:unit_tests",
-      "//components/data_reduction_proxy/core/common:unit_tests",
-      "//components/device_event_log:unit_tests",
-      "//components/dom_distiller/core:unit_tests",
-      "//components/domain_reliability:unit_tests",
-      "//components/favicon_base:unit_tests",
-      "//components/google/core/browser:unit_tests",
-      "//components/invalidation:unittests",
-      "//components/login:unit_tests",
-      "//components/metrics:unit_tests",
-      "//components/omnibox:unit_tests",
-      "//components/ownership:unit_tests",
-      "//components/packed_ct_ev_whitelist:unit_tests",
-      "//components/proximity_auth:unit_tests",
-      "//components/update_client:unit_tests",
-      "//components/variations:unit_tests",
-      "//components/web_resource:unit_tests",
-      "//components/webdata/common:unit_tests",
+  # Add only ":unit_tests" dependencies here. If your tests have dependencies
+  # (this would at least include the component itself), they should be on the
+  # test source set and not here.
+  deps = [
+    "//components/auto_login_parser:unit_tests",
+    "//components/autofill/content/browser:unit_tests",
+    "//components/autofill/core/browser:unit_tests",
+    "//components/autofill/core/common:unit_tests",
+    "//components/bookmarks/browser:unit_tests",
+    "//components/captive_portal:unit_tests",
+    "//components/cloud_devices/common:unit_tests",
+    "//components/content_settings/core/browser:unit_tests",
+    "//components/content_settings/core/common:unit_tests",
+    "//components/crx_file:unit_tests",
+    "//components/data_reduction_proxy/core/browser:unit_tests",
+    "//components/data_reduction_proxy/core/common:unit_tests",
+    "//components/device_event_log:unit_tests",
+    "//components/dom_distiller/core:unit_tests",
+    "//components/domain_reliability:unit_tests",
+    "//components/favicon_base:unit_tests",
+    "//components/google/core/browser:unit_tests",
+    "//components/invalidation:unittests",
+    "//components/login:unit_tests",
+    "//components/metrics:unit_tests",
+    "//components/omnibox:unit_tests",
+    "//components/ownership:unit_tests",
+    "//components/packed_ct_ev_whitelist:unit_tests",
+    "//components/proximity_auth:unit_tests",
+    "//components/update_client:unit_tests",
+    "//components/variations:unit_tests",
+    "//components/web_resource:unit_tests",
+    "//components/webdata/common:unit_tests",
 
-      # These are the deps required by the code in this target.
-      "//base",
-      "//base/test:test_support",
-      "//content/test:test_support",
-      "//ui/base",
-    ]
-    data_deps = [ ":components_tests_pak" ]
+    # These are the deps required by the code in this target.
+    "//base",
+    "//base/test:test_support",
+    "//content/test:test_support",
+    "//ui/base",
+  ]
+  data_deps = [ ":components_tests_pak" ]
 
-    if (is_android) {
-      deps += [ "//components/data_reduction_proxy/content/browser:unit_tests" ]
-    }
-
-    # TODO(GYP) need this target.
-    #'breakpad/app/crash_keys_win_unittest.cc',
-
-    # Precache tests need these defines.
-    #configs += [ "//components/precache/core:precache_config" ]
-
-    if (toolkit_views) {
-      # TODO(GYP) enable this as above.
-      #deps += [ "//components/constrained_window:unit_tests" ]
-    }
-    if (is_win) {
-      deps += [ "//components/browser_watcher:unit_tests" ]
-    }
+  if (is_android) {
+    deps += [ "//components/data_reduction_proxy/content/browser:unit_tests" ]
   }
 
-  repack("components_tests_pak") {
-    sources = [
-      "$root_gen_dir/components/components_resources.pak",
-      "$root_gen_dir/components/strings/components_strings_en-US.pak",
-      "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
-      "$root_gen_dir/ui/resources/webui_resources.pak",
-      "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
-      "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
-    ]
+  # TODO(GYP) need this target.
+  #'breakpad/app/crash_keys_win_unittest.cc',
 
-    output = "$root_out_dir/components_tests_resources.pak"
+  # Precache tests need these defines.
+  #configs += [ "//components/precache/core:precache_config" ]
 
-    deps = [
-      "//components/resources",
-      "//components/strings",
-      "//ui/resources",
-      "//ui/strings",
-    ]
+  if (toolkit_views) {
+    # TODO(GYP) enable this as above.
+    #deps += [ "//components/constrained_window:unit_tests" ]
   }
+  if (is_win) {
+    deps += [ "//components/browser_watcher:unit_tests" ]
+  }
+}
+
+repack("components_tests_pak") {
+  sources = [
+    "$root_gen_dir/components/components_resources.pak",
+    "$root_gen_dir/components/strings/components_strings_en-US.pak",
+    "$root_gen_dir/ui/resources/ui_resources_100_percent.pak",
+    "$root_gen_dir/ui/resources/webui_resources.pak",
+    "$root_gen_dir/ui/strings/app_locale_settings_en-US.pak",
+    "$root_gen_dir/ui/strings/ui_strings_en-US.pak",
+  ]
+
+  output = "$root_out_dir/components_tests_resources.pak"
+
+  deps = [
+    "//components/resources",
+    "//components/strings",
+    "//ui/resources",
+    "//ui/strings",
+  ]
 }
diff --git a/components/autofill.gypi b/components/autofill.gypi
index 21d98fd..e8c6d153 100644
--- a/components/autofill.gypi
+++ b/components/autofill.gypi
@@ -459,5 +459,26 @@
         },
       ],
     }],
+    ['OS == "ios"', {
+      'targets': [
+        {
+          'target_name': 'autofill_ios_browser',
+          'type': 'static_library',
+          'include_dirs': [
+            '..',
+          ],
+          'dependencies': [
+            'autofill_core_browser',
+            '../ios/provider/ios_provider_web.gyp:ios_provider_web',
+            '../ios/web/ios_web.gyp:ios_web',
+          ],
+          'sources': [
+            'autofill/ios/browser/autofill_driver_ios.h',
+            'autofill/ios/browser/autofill_driver_ios.mm',
+            'autofill/ios/browser/autofill_driver_ios_bridge.h',
+          ],
+        },
+      ],
+    }],
   ],
 }
diff --git a/components/autofill/content/renderer/form_cache.cc b/components/autofill/content/renderer/form_cache.cc
index 3f27c39..9bc97e2f 100644
--- a/components/autofill/content/renderer/form_cache.cc
+++ b/components/autofill/content/renderer/form_cache.cc
@@ -119,10 +119,41 @@
       parsed_forms_.insert(form);
     }
   }
+
+  // Look for more parseable fields outside of forms.
+  std::vector<WebElement> fieldsets;
+  std::vector<WebFormControlElement> control_elements =
+      GetUnownedAutofillableFormFieldElements(document.all(), &fieldsets);
+
+  size_t num_editable_elements =
+      ScanFormControlElements(control_elements, log_deprecation_messages);
+
+  if (ShouldIgnoreForm(num_editable_elements, control_elements.size()))
+    return forms;
+
+  FormData synthetic_form;
+  if (!UnownedFormElementsAndFieldSetsToFormData(fieldsets, control_elements,
+                                                 nullptr, document.url(),
+                                                 REQUIRE_NONE, extract_mask,
+                                                 &synthetic_form, nullptr)) {
+    return forms;
+  }
+
+  num_fields_seen += synthetic_form.fields.size();
+  if (num_fields_seen > kMaxParseableFields)
+    return forms;
+
+  if (synthetic_form.fields.size() >= kRequiredAutofillFields &&
+      !parsed_forms_.count(synthetic_form)) {
+    forms.push_back(synthetic_form);
+    parsed_forms_.insert(synthetic_form);
+    synthetic_form_ = synthetic_form;
+  }
   return forms;
 }
 
 void FormCache::Reset() {
+  synthetic_form_ = FormData();
   parsed_forms_.clear();
   initial_select_values_.clear();
   initial_checked_state_.clear();
@@ -191,7 +222,15 @@
 
   std::vector<WebFormControlElement> control_elements;
 
+  // First check the synthetic form.
   bool found_synthetic_form = false;
+  if (form.data.SameFormAs(synthetic_form_)) {
+    found_synthetic_form = true;
+    WebDocument document = frame_.document();
+    control_elements =
+        GetUnownedAutofillableFormFieldElements(document.all(), nullptr);
+  }
+
   if (!found_synthetic_form) {
     // Find the real form by searching through the WebDocuments.
     bool found_form = false;
diff --git a/components/autofill/content/renderer/form_cache.h b/components/autofill/content/renderer/form_cache.h
index f37a981..d0c29cd 100644
--- a/components/autofill/content/renderer/form_cache.h
+++ b/components/autofill/content/renderer/form_cache.h
@@ -64,6 +64,10 @@
   // The cached forms. Used to prevent re-extraction of forms.
   std::set<FormData> parsed_forms_;
 
+  // The synthetic FormData is for all the fieldsets in the document without a
+  // form owner.
+  FormData synthetic_form_;
+
   // The cached initial values for <select> elements.
   std::map<const blink::WebSelectElement, base::string16>
       initial_select_values_;
diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h
index 534aa68..ef3039b 100644
--- a/components/autofill/core/browser/autofill_client.h
+++ b/components/autofill/core/browser/autofill_client.h
@@ -55,6 +55,21 @@
     AutocompleteResultErrorInvalid,
   };
 
+  enum GetRealPanResult {
+    // Request succeeded.
+    SUCCESS,
+
+    // Request failed; try again.
+    TRY_AGAIN_FAILURE,
+
+    // Request failed; don't try again.
+    PERMANENT_FAILURE,
+
+    // Unable to connect to Wallet servers. Prompt user to check internet
+    // connection.
+    NETWORK_ERROR,
+  };
+
   typedef base::Callback<void(RequestAutocompleteResult,
                               const base::string16&,
                               const FormStructure*)> ResultCallback;
@@ -87,7 +102,7 @@
   // information to proceed.
   virtual void ShowUnmaskPrompt(const CreditCard& card,
                                 base::WeakPtr<CardUnmaskDelegate> delegate) = 0;
-  virtual void OnUnmaskVerificationResult(bool success) = 0;
+  virtual void OnUnmaskVerificationResult(GetRealPanResult result) = 0;
 
   // Run |save_card_callback| if the credit card should be imported as personal
   // data. |metric_logger| can be used to log user actions.
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index ca6399a..20121fc 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -778,8 +778,10 @@
   return client()->GetIdentityProvider();
 }
 
-void AutofillManager::OnDidGetRealPan(const std::string& real_pan) {
+void AutofillManager::OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+                                      const std::string& real_pan) {
   if (!real_pan.empty()) {
+    DCHECK_EQ(AutofillClient::SUCCESS, result);
     credit_card_form_event_logger_->OnDidFillSuggestion(unmasking_card_);
     unmasking_card_.set_record_type(CreditCard::FULL_SERVER_CARD);
     unmasking_card_.SetNumber(base::UTF8ToUTF16(real_pan));
@@ -790,7 +792,7 @@
                        unmasking_card_);
   }
 
-  client()->OnUnmaskVerificationResult(!real_pan.empty());
+  client()->OnUnmaskVerificationResult(result);
 }
 
 void AutofillManager::OnDidEndTextFieldEditing() {
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index e9bbb44..5f8b67b 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -237,7 +237,8 @@
 
   // wallet::RealPanWalletClient::Delegate:
   IdentityProvider* GetIdentityProvider() override;
-  void OnDidGetRealPan(const std::string& real_pan) override;
+  void OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+                       const std::string& real_pan) override;
 
   // Returns false if Autofill is disabled or if no Autofill data is available.
   bool RefreshDataModels();
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index f249d08..04ff306 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -1186,7 +1186,8 @@
         AutofillDriver::FORM_DATA_ACTION_FILL,
         0, form, form.fields.front(),
         autofill_manager_->MakeFrontendID(guid, SuggestionBackendID()));
-    autofill_manager_->OnDidGetRealPan("6011000990139424");
+    autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
+                                       "6011000990139424");
     histogram_tester.ExpectBucketCount(
         "Autofill.FormEvents.CreditCard",
         AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -1348,7 +1349,8 @@
         AutofillDriver::FORM_DATA_ACTION_FILL,
         0, form, form.fields.front(),
         autofill_manager_->MakeFrontendID(guid, SuggestionBackendID()));
-    autofill_manager_->OnDidGetRealPan("6011000990139424");
+    autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
+                                       "6011000990139424");
     histogram_tester.ExpectBucketCount(
         "Autofill.FormEvents.CreditCard",
         AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc
index abcfb53..eef879d 100644
--- a/components/autofill/core/browser/test_autofill_client.cc
+++ b/components/autofill/core/browser/test_autofill_client.cc
@@ -42,7 +42,7 @@
     base::WeakPtr<CardUnmaskDelegate> delegate) {
 }
 
-void TestAutofillClient::OnUnmaskVerificationResult(bool success) {
+void TestAutofillClient::OnUnmaskVerificationResult(GetRealPanResult result) {
 }
 
 void TestAutofillClient::ConfirmSaveCreditCard(
diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h
index 1d5ab7ae..fcafd98 100644
--- a/components/autofill/core/browser/test_autofill_client.h
+++ b/components/autofill/core/browser/test_autofill_client.h
@@ -30,7 +30,7 @@
   void ShowAutofillSettings() override;
   void ShowUnmaskPrompt(const CreditCard& card,
                         base::WeakPtr<CardUnmaskDelegate> delegate) override;
-  void OnUnmaskVerificationResult(bool success) override;
+  void OnUnmaskVerificationResult(GetRealPanResult result) override;
   void ConfirmSaveCreditCard(const base::Closure& save_card_callback) override;
   bool HasCreditCardScanFeature() override;
   void ScanCreditCard(const CreditCardScanCallback& callback) override;
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
index 37083c8..3934685 100644
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
+++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.cc
@@ -129,8 +129,8 @@
   std::string data;
   source->GetResponseAsString(&data);
 
-  // TODO(estade): OAuth2 may fail due to an expired access token, in which case
-  // we should invalidate the token and try again. How is that failure reported?
+  std::string real_pan;
+  AutofillClient::GetRealPanResult result = AutofillClient::SUCCESS;
 
   switch (response_code) {
     // Valid response.
@@ -140,24 +140,19 @@
           message_value->IsType(base::Value::TYPE_DICTIONARY)) {
         response_dict.reset(
             static_cast<base::DictionaryValue*>(message_value.release()));
+        response_dict->GetString("pan", &real_pan);
+        if (real_pan.empty())
+          result = AutofillClient::TRY_AGAIN_FAILURE;
+        // TODO(estade): check response for allow_retry.
       }
       break;
     }
 
-    // HTTP_BAD_REQUEST means the arguments are invalid. No point retrying.
-    case net::HTTP_BAD_REQUEST: {
-      break;
-    }
-
-    // Response contains an error to show the user.
-    case net::HTTP_FORBIDDEN:
-    case net::HTTP_INTERNAL_SERVER_ERROR: {
-      break;
-    }
-
     case net::HTTP_UNAUTHORIZED: {
-      if (has_retried_authorization_)
+      if (has_retried_authorization_) {
+        result = AutofillClient::PERMANENT_FAILURE;
         break;
+      }
       has_retried_authorization_ = true;
 
       CreateRequest();
@@ -165,21 +160,27 @@
       return;
     }
 
-    // Handle anything else as a generic error.
-    default:
+    // TODO(estade): is this actually how network connectivity issues are
+    // reported?
+    case net::HTTP_REQUEST_TIMEOUT: {
+      result = AutofillClient::NETWORK_ERROR;
       break;
-  }
+    }
 
-  std::string real_pan;
-  if (response_dict)
-    response_dict->GetString("pan", &real_pan);
+    // Handle anything else as a generic (permanent) failure.
+    default: {
+      result = AutofillClient::PERMANENT_FAILURE;
+      break;
+    }
+  }
 
   if (real_pan.empty()) {
-    NOTIMPLEMENTED() << "Unhandled error: " << response_code
-                     << " with data: " << data;
+    LOG(ERROR) << "Wallet returned error: " << response_code
+               << " with data: " << data;
   }
 
-  delegate_->OnDidGetRealPan(real_pan);
+  DCHECK_EQ(result != AutofillClient::SUCCESS, real_pan.empty());
+  delegate_->OnDidGetRealPan(result, real_pan);
 }
 
 void RealPanWalletClient::OnGetTokenSuccess(
@@ -198,13 +199,12 @@
     const OAuth2TokenService::Request* request,
     const GoogleServiceAuthError& error) {
   DCHECK_EQ(request, access_token_request_.get());
+  LOG(ERROR) << "Unhandled OAuth2 error: " << error.ToString();
   if (request_) {
     request_.reset();
-    delegate_->OnDidGetRealPan(std::string());
+    delegate_->OnDidGetRealPan(AutofillClient::PERMANENT_FAILURE,
+                               std::string());
   }
-  // TODO(estade): what do we do in the failure case?
-  NOTIMPLEMENTED() << "Unhandled OAuth2 error: " << error.ToString();
-
   access_token_request_.reset();
 }
 
@@ -257,7 +257,7 @@
 
 void RealPanWalletClient::SetOAuth2TokenAndStartRequest() {
   request_->AddExtraRequestHeader(net::HttpRequestHeaders::kAuthorization +
-      std::string(": Bearer ") + access_token_);
+                                  std::string(": Bearer ") + access_token_);
 
   request_->Start();
 }
diff --git a/components/autofill/core/browser/wallet/real_pan_wallet_client.h b/components/autofill/core/browser/wallet/real_pan_wallet_client.h
index 82dc0b72d..6dd7a2d7 100644
--- a/components/autofill/core/browser/wallet/real_pan_wallet_client.h
+++ b/components/autofill/core/browser/wallet/real_pan_wallet_client.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill/core/browser/autofill_client.h"
 #include "components/autofill/core/browser/card_unmask_delegate.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -36,7 +37,8 @@
 
     // Returns the real PAN retrieved from Wallet. |real_pan| will be empty
     // on failure.
-    virtual void OnDidGetRealPan(const std::string& real_pan) = 0;
+    virtual void OnDidGetRealPan(AutofillClient::GetRealPanResult result,
+                                 const std::string& real_pan) = 0;
   };
 
   // |context_getter| is reference counted so it has no lifetime or ownership
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 14fd62e..ea047585 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -189,37 +189,6 @@
   return credit_card.Pass();
 }
 
-// Obsolete version of AddAutofillProfileNamesToProfile, but still needed
-// for MigrateToVersion37MergeAndCullOlderProfiles().
-bool AddAutofillProfileNamesToProfileForVersion37(sql::Connection* db,
-                                                  AutofillProfile* profile) {
-  sql::Statement s(db->GetUniqueStatement(
-      "SELECT guid, first_name, middle_name, last_name "
-      "FROM autofill_profile_names "
-      "WHERE guid=?"));
-  s.BindString(0, profile->guid());
-
-  if (!s.is_valid())
-    return false;
-
-  std::vector<base::string16> first_names;
-  std::vector<base::string16> middle_names;
-  std::vector<base::string16> last_names;
-  while (s.Step()) {
-    DCHECK_EQ(profile->guid(), s.ColumnString(0));
-    first_names.push_back(s.ColumnString16(1));
-    middle_names.push_back(s.ColumnString16(2));
-    last_names.push_back(s.ColumnString16(3));
-  }
-  if (!s.Succeeded())
-    return false;
-
-  profile->SetRawMultiInfo(NAME_FIRST, first_names);
-  profile->SetRawMultiInfo(NAME_MIDDLE, middle_names);
-  profile->SetRawMultiInfo(NAME_LAST, last_names);
-  return true;
-}
-
 bool AddAutofillProfileNamesToProfile(sql::Connection* db,
                                       AutofillProfile* profile) {
   sql::Statement s(db->GetUniqueStatement(
@@ -298,38 +267,6 @@
   return true;
 }
 
-// Obsolete version of AddAutofillProfileNames needed for
-// MigrateToVersion33ProfilesBasedOnFirstName() and
-// MigrateToVersion37MergeAndCullOlderProfiles().
-bool AddAutofillProfileNamesForVersion3x(
-    const AutofillProfile& profile,
-    sql::Connection* db) {
-  std::vector<base::string16> first_names;
-  profile.GetRawMultiInfo(NAME_FIRST, &first_names);
-  std::vector<base::string16> middle_names;
-  profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names);
-  std::vector<base::string16> last_names;
-  profile.GetRawMultiInfo(NAME_LAST, &last_names);
-  DCHECK_EQ(first_names.size(), middle_names.size());
-  DCHECK_EQ(first_names.size(), last_names.size());
-
-  for (size_t i = 0; i < first_names.size(); ++i) {
-    // Add the new name.
-    sql::Statement s(db->GetUniqueStatement(
-        "INSERT INTO autofill_profile_names"
-        " (guid, first_name, middle_name, last_name) "
-        "VALUES (?,?,?,?)"));
-    s.BindString(0, profile.guid());
-    s.BindString16(1, first_names[i]);
-    s.BindString16(2, middle_names[i]);
-    s.BindString16(3, last_names[i]);
-
-    if (!s.Run())
-      return false;
-  }
-  return true;
-}
-
 bool AddAutofillProfileNames(const AutofillProfile& profile,
                              sql::Connection* db) {
   std::vector<base::string16> first_names;
@@ -511,48 +448,6 @@
                                      bool* update_compatible_version) {
   // Migrate if necessary.
   switch (version) {
-    case 22:
-      return MigrateToVersion22ClearAutofillEmptyValueElements();
-    case 23:
-      return MigrateToVersion23AddCardNumberEncryptedColumn();
-    case 24:
-      return MigrateToVersion24CleanupOversizedStringFields();
-    case 27:
-      *update_compatible_version = true;
-      return MigrateToVersion27UpdateLegacyCreditCards();
-    case 30:
-      *update_compatible_version = true;
-      return MigrateToVersion30AddDateModifed();
-    case 31:
-      *update_compatible_version = true;
-      return MigrateToVersion31AddGUIDToCreditCardsAndProfiles();
-    case 32:
-      *update_compatible_version = true;
-      return MigrateToVersion32UpdateProfilesAndCreditCards();
-    case 33:
-      *update_compatible_version = true;
-      return MigrateToVersion33ProfilesBasedOnFirstName();
-    case 34:
-      *update_compatible_version = true;
-      return MigrateToVersion34ProfilesBasedOnCountryCode();
-    case 35:
-      *update_compatible_version = true;
-      return MigrateToVersion35GreatBritainCountryCodes();
-    // Combine migrations 36 and 37.  This is due to enhancements to the merge
-    // step when migrating profiles.  The original migration from 35 to 36 did
-    // not merge profiles with identical addresses, but the migration from 36 to
-    // 37 does.  The step from 35 to 36 should only happen on the Chrome 12 dev
-    // channel.  Chrome 12 beta and release users will jump from 35 to 37
-    // directly getting the full benefits of the multi-valued merge as well as
-    // the culling of bad data.
-    case 37:
-      *update_compatible_version = true;
-      return MigrateToVersion37MergeAndCullOlderProfiles();
-    case 51:
-      // Combine migrations 50 and 51.  The migration code from version 49 to 50
-      // worked correctly for users with existing 'origin' columns, but failed
-      // to create these columns for new users.
-      return MigrateToVersion51AddOriginColumn();
     case 54:
       *update_compatible_version = true;
       return MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
@@ -574,6 +469,9 @@
     case 62:
       *update_compatible_version = false;
       return MigrateToVersion62AddUsageStatsForUnmaskedCards();
+    case 63:
+      *update_compatible_version = false;
+      return MigrateToVersion63AddServerRecipientName();
   }
   return true;
 }
@@ -1004,6 +902,7 @@
   sql::Statement s(db_->GetUniqueStatement(
       "SELECT "
         "id,"
+        "recipient_name,"
         "company_name,"
         "street_address,"
         "address_1,"  // ADDRESS_HOME_STATE
@@ -1021,6 +920,7 @@
     scoped_ptr<AutofillProfile> profile(new AutofillProfile(
         AutofillProfile::SERVER_PROFILE, s.ColumnString(index++)));
 
+    profile->SetRawInfo(NAME_FULL, s.ColumnString16(index++));
     profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
     profile->SetRawInfo(ADDRESS_HOME_STREET_ADDRESS, s.ColumnString16(index++));
     profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
@@ -1049,6 +949,7 @@
   sql::Statement insert(db_->GetUniqueStatement(
       "INSERT INTO server_addresses("
         "id,"
+        "recipient_name,"
         "company_name,"
         "street_address,"
         "address_1,"  // ADDRESS_HOME_STATE
@@ -1059,12 +960,13 @@
         "sorting_code,"  // ADDRESS_HOME_SORTING_CODE
         "country_code,"  // ADDRESS_HOME_COUNTRY
         "language_code) "
-      "VALUES (?,?,?,?,?,?,?,?,?,?,?)"));
+      "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"));
   for (const auto& profile : profiles) {
     DCHECK(profile.record_type() == AutofillProfile::SERVER_PROFILE);
 
     int index = 0;
     insert.BindString(index++, profile.server_id());
+    insert.BindString16(index++, profile.GetRawInfo(NAME_FULL));
     insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME));
     insert.BindString16(index++,
                         profile.GetRawInfo(ADDRESS_HOME_STREET_ADDRESS));
@@ -1776,6 +1678,8 @@
 
 bool AutofillTable::InitServerAddressesTable() {
   if (!db_->DoesTableExist("server_addresses")) {
+    // The space after language_code is necessary to match what sqlite does
+    // when it appends the column in migration.
     if (!db_->Execute("CREATE TABLE server_addresses ("
                       "id VARCHAR,"
                       "company_name VARCHAR,"
@@ -1787,7 +1691,8 @@
                       "postal_code VARCHAR,"
                       "sorting_code VARCHAR,"
                       "country_code VARCHAR,"
-                      "language_code VARCHAR)")) {
+                      "language_code VARCHAR, "  // Space required.
+                      "recipient_name VARCHAR)")) {
       NOTREACHED();
       return false;
     }
@@ -1795,778 +1700,6 @@
   return true;
 }
 
-bool AutofillTable::MigrateToVersion22ClearAutofillEmptyValueElements() {
-  if (!db_->DoesTableExist("autofill") &&
-      (!db_->Execute("CREATE TABLE autofill ("
-                     "  name VARCHAR,"
-                     "  value VARCHAR,"
-                     "  value_lower VARCHAR,"
-                     "  pair_id INTEGER PRIMARY KEY,"
-                     "  count INTEGER DEFAULT 1)") ||
-       !db_->Execute("CREATE INDEX autofill_name ON autofill (name)") ||
-       !db_->Execute("CREATE INDEX autofill_name_value_lower ON"
-                     "  autofill (name, value_lower)") ||
-       !db_->Execute("CREATE TABLE autofill_dates ("
-                     "  pair_id INTEGER DEFAULT 0,"
-                     "  date_created INTEGER DEFAULT 0)") ||
-       !db_->Execute("CREATE INDEX autofill_dates_pair_id ON"
-                     "  autofill (pair_id)")))
-    return false;
-
-
-  sql::Statement s(db_->GetUniqueStatement(
-      "SELECT pair_id FROM autofill WHERE TRIM(value) = \"\""));
-  if (!s.is_valid())
-    return false;
-
-  std::set<int64> ids;
-  while (s.Step())
-    ids.insert(s.ColumnInt64(0));
-  if (!s.Succeeded())
-    return false;
-
-  if (!db_->Execute("DELETE FROM autofill WHERE TRIM(value) = \"\""))
-    return false;
-
-  for (std::set<int64>::const_iterator it = ids.begin(); it != ids.end();
-       ++it) {
-    sql::Statement s(db_->GetUniqueStatement(
-        "DELETE FROM autofill_dates WHERE pair_id = ?"));
-    s.BindInt64(0, *it);
-    if (!s.Run())
-      return false;
-  }
-
-  return true;
-}
-
-// Add the card_number_encrypted column if credit card table was not
-// created in this build (otherwise the column already exists).
-// WARNING: Do not change the order of the execution of the SQL
-// statements in this case!  Profile corruption and data migration
-// issues WILL OCCUR. See http://crbug.com/10913
-//
-// The problem is that if a user has a profile which was created before
-// r37036, when the credit_cards table was added, and then failed to
-// update this profile between the credit card addition and the addition
-// of the "encrypted" columns (44963), the next data migration will put
-// the user's profile in an incoherent state: The user will update from
-// a data profile set to be earlier than 22, and therefore pass through
-// this update case.  But because the user did not have a credit_cards
-// table before starting Chrome, it will have just been initialized
-// above, and so already have these columns -- and thus this data
-// update step will have failed.
-//
-// The false assumption in this case is that at this step in the
-// migration, the user has a credit card table, and that this
-// table does not include encrypted columns!
-// Because this case does not roll back the complete set of SQL
-// transactions properly in case of failure (that is, it does not
-// roll back the table initialization done above), the incoherent
-// profile will now see itself as being at version 22 -- but include a
-// fully initialized credit_cards table.  Every time Chrome runs, it
-// will try to update the web database and fail at this step, unless
-// we allow for the faulty assumption described above by checking for
-// the existence of the columns only AFTER we've executed the commands
-// to add them.
-bool AutofillTable::MigrateToVersion23AddCardNumberEncryptedColumn() {
-  if (!db_->DoesTableExist("autofill_profiles") &&
-      (!db_->Execute("CREATE TABLE autofill_profiles ( "
-                     "label VARCHAR, "
-                     "unique_id INTEGER PRIMARY KEY, "
-                     "first_name VARCHAR, "
-                     "middle_name VARCHAR, "
-                     "last_name VARCHAR, "
-                     "email VARCHAR, "
-                     "company_name VARCHAR, "
-                     "address_line_1 VARCHAR, "
-                     "address_line_2 VARCHAR, "
-                     "city VARCHAR, "
-                     "state VARCHAR, "
-                     "zipcode VARCHAR, "
-                     "country VARCHAR, "
-                     "phone VARCHAR, "
-                     "fax VARCHAR)") ||
-       !db_->Execute("CREATE INDEX autofill_profiles_label_index"
-                     "  ON autofill_profiles (label)")))
-    return false;
-
-  if (!db_->DoesTableExist("credit_cards") &&
-      (!db_->Execute("CREATE TABLE credit_cards ( "
-                     "label VARCHAR, "
-                     "unique_id INTEGER PRIMARY KEY, "
-                     "name_on_card VARCHAR, "
-                     "type VARCHAR, "
-                     "card_number VARCHAR, "
-                     "expiration_month INTEGER, "
-                     "expiration_year INTEGER, "
-                     "verification_code VARCHAR, "
-                     "billing_address VARCHAR, "
-                     "shipping_address VARCHAR)") ||
-       !db_->Execute("CREATE INDEX credit_cards_label_index"
-                     "  ON credit_cards (label)")))
-    return false;
-
-  if (!db_->DoesColumnExist("credit_cards", "card_number_encrypted")) {
-    if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
-                      "card_number_encrypted BLOB DEFAULT NULL")) {
-      return false;
-    }
-  }
-
-  if (!db_->DoesColumnExist("credit_cards", "verification_code_encrypted")) {
-    if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
-                      "verification_code_encrypted BLOB DEFAULT NULL")) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-// One-time cleanup for http://crbug.com/38364 - In the presence of
-// multi-byte UTF-8 characters, that bug could cause Autofill strings
-// to grow larger and more corrupt with each save.  The cleanup removes
-// any row with a string field larger than a reasonable size.  The string
-// fields examined here are precisely the ones that were subject to
-// corruption by the original bug.
-bool AutofillTable::MigrateToVersion24CleanupOversizedStringFields() {
-  const std::string autofill_is_too_big =
-      "max(length(name), length(value)) > 500";
-
-  const std::string credit_cards_is_too_big =
-      "max(length(label), length(name_on_card), length(type), "
-      "    length(expiration_month), length(expiration_year), "
-      "    length(billing_address), length(shipping_address) "
-      ") > 500";
-
-  const std::string autofill_profiles_is_too_big =
-      "max(length(label), length(first_name), "
-      "    length(middle_name), length(last_name), length(email), "
-      "    length(company_name), length(address_line_1), "
-      "    length(address_line_2), length(city), length(state), "
-      "    length(zipcode), length(country), length(phone)) > 500";
-
-  std::string query = "DELETE FROM autofill_dates WHERE pair_id IN ("
-      "SELECT pair_id FROM autofill WHERE " + autofill_is_too_big + ")";
-
-  if (!db_->Execute(query.c_str()))
-    return false;
-
-  query = "DELETE FROM autofill WHERE " + autofill_is_too_big;
-
-  if (!db_->Execute(query.c_str()))
-    return false;
-
-  // Only delete from legacy credit card tables where specific columns exist.
-  if (db_->DoesColumnExist("credit_cards", "label") &&
-      db_->DoesColumnExist("credit_cards", "name_on_card") &&
-      db_->DoesColumnExist("credit_cards", "type") &&
-      db_->DoesColumnExist("credit_cards", "expiration_month") &&
-      db_->DoesColumnExist("credit_cards", "expiration_year") &&
-      db_->DoesColumnExist("credit_cards", "billing_address") &&
-      db_->DoesColumnExist("credit_cards", "shipping_address") &&
-      db_->DoesColumnExist("autofill_profiles", "label")) {
-    query = "DELETE FROM credit_cards WHERE (" + credit_cards_is_too_big +
-        ") OR label IN (SELECT label FROM autofill_profiles WHERE " +
-        autofill_profiles_is_too_big + ")";
-
-    if (!db_->Execute(query.c_str()))
-      return false;
-  }
-
-  if (db_->DoesColumnExist("autofill_profiles", "label")) {
-    query = "DELETE FROM autofill_profiles WHERE " +
-        autofill_profiles_is_too_big;
-
-    if (!db_->Execute(query.c_str()))
-      return false;
-  }
-
-  return true;
-}
-
-// Change the credit_cards.billing_address column from a string to an
-// int.  The stored string is the label of an address, so we have to
-// select the unique ID of this address using the label as a foreign
-// key into the |autofill_profiles| table.
-bool AutofillTable::MigrateToVersion27UpdateLegacyCreditCards() {
-  // Only migrate from legacy credit card tables where specific columns
-  // exist.
-  if (!(db_->DoesColumnExist("credit_cards", "unique_id") &&
-        db_->DoesColumnExist("credit_cards", "billing_address") &&
-        db_->DoesColumnExist("autofill_profiles", "unique_id"))) {
-    return true;
-  }
-
-  std::string stmt =
-      "SELECT credit_cards.unique_id, autofill_profiles.unique_id "
-      "FROM autofill_profiles, credit_cards "
-      "WHERE credit_cards.billing_address = autofill_profiles.label";
-  sql::Statement s(db_->GetUniqueStatement(stmt.c_str()));
-
-  std::map<int, int> cc_billing_map;
-  while (s.Step())
-    cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1);
-  if (!s.Succeeded())
-    return false;
-
-  // Windows already stores the IDs as strings in |billing_address|. Try
-  // to convert those.
-  if (cc_billing_map.empty()) {
-    std::string stmt = "SELECT unique_id,billing_address FROM credit_cards";
-    sql::Statement s(db_->GetUniqueStatement(stmt.c_str()));
-
-    while (s.Step()) {
-      int id = 0;
-      if (base::StringToInt(s.ColumnString(1), &id))
-        cc_billing_map[s.ColumnInt(0)] = id;
-    }
-    if (!s.Succeeded())
-      return false;
-  }
-
-  if (!db_->Execute("CREATE TABLE credit_cards_temp ( "
-                    "label VARCHAR, "
-                    "unique_id INTEGER PRIMARY KEY, "
-                    "name_on_card VARCHAR, "
-                    "type VARCHAR, "
-                    "card_number VARCHAR, "
-                    "expiration_month INTEGER, "
-                    "expiration_year INTEGER, "
-                    "verification_code VARCHAR, "
-                    "billing_address INTEGER, "
-                    "shipping_address VARCHAR, "
-                    "card_number_encrypted BLOB, "
-                    "verification_code_encrypted BLOB)")) {
-    return false;
-  }
-
-  if (!db_->Execute(
-      "INSERT INTO credit_cards_temp "
-      "SELECT label,unique_id,name_on_card,type,card_number,"
-      "expiration_month,expiration_year,verification_code,0,"
-      "shipping_address,card_number_encrypted,"
-      "verification_code_encrypted FROM credit_cards")) {
-    return false;
-  }
-
-  if (!db_->Execute("DROP TABLE credit_cards"))
-    return false;
-
-  if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards"))
-    return false;
-
-  for (std::map<int, int>::const_iterator iter = cc_billing_map.begin();
-       iter != cc_billing_map.end(); ++iter) {
-    sql::Statement s(db_->GetCachedStatement(
-        SQL_FROM_HERE,
-        "UPDATE credit_cards SET billing_address=? WHERE unique_id=?"));
-    s.BindInt(0, (*iter).second);
-    s.BindInt(1, (*iter).first);
-
-    if (!s.Run())
-      return false;
-  }
-
-  return true;
-}
-
-bool AutofillTable::MigrateToVersion30AddDateModifed() {
-  // Add date_modified to autofill_profiles.
-  if (!db_->DoesColumnExist("autofill_profiles", "date_modified")) {
-    if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN "
-                      "date_modified INTEGER NON NULL DEFAULT 0")) {
-      return false;
-    }
-
-    sql::Statement s(db_->GetUniqueStatement(
-        "UPDATE autofill_profiles SET date_modified=?"));
-    s.BindInt64(0, Time::Now().ToTimeT());
-
-    if (!s.Run())
-      return false;
-  }
-
-  // Add date_modified to credit_cards.
-  if (!db_->DoesColumnExist("credit_cards", "date_modified")) {
-    if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
-                      "date_modified INTEGER NON NULL DEFAULT 0")) {
-      return false;
-    }
-
-    sql::Statement s(db_->GetUniqueStatement(
-        "UPDATE credit_cards SET date_modified=?"));
-    s.BindInt64(0, Time::Now().ToTimeT());
-
-    if (!s.Run())
-      return false;
-  }
-
-  return true;
-}
-
-bool AutofillTable::MigrateToVersion31AddGUIDToCreditCardsAndProfiles() {
-  // Note that we need to check for the guid column's existence due to the
-  // fact that for a version 22 database the |autofill_profiles| table
-  // gets created fresh with |InitAutofillProfilesTable|.
-  if (!db_->DoesColumnExist("autofill_profiles", "guid")) {
-    if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN "
-                      "guid VARCHAR NOT NULL DEFAULT \"\"")) {
-      return false;
-    }
-
-    // Set all the |guid| fields to valid values.
-
-    sql::Statement s(db_->GetUniqueStatement("SELECT unique_id "
-                                             "FROM autofill_profiles"));
-
-    while (s.Step()) {
-      sql::Statement update_s(
-          db_->GetUniqueStatement("UPDATE autofill_profiles "
-                                  "SET guid=? WHERE unique_id=?"));
-      update_s.BindString(0, base::GenerateGUID());
-      update_s.BindInt(1, s.ColumnInt(0));
-
-      if (!update_s.Run())
-        return false;
-    }
-    if (!s.Succeeded())
-      return false;
-  }
-
-  // Note that we need to check for the guid column's existence due to the
-  // fact that for a version 22 database the |autofill_profiles| table
-  // gets created fresh with |InitAutofillProfilesTable|.
-  if (!db_->DoesColumnExist("credit_cards", "guid")) {
-    if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN "
-                      "guid VARCHAR NOT NULL DEFAULT \"\"")) {
-      return false;
-    }
-
-    // Set all the |guid| fields to valid values.
-
-    sql::Statement s(db_->GetUniqueStatement("SELECT unique_id "
-                                             "FROM credit_cards"));
-
-    while (s.Step()) {
-      sql::Statement update_s(
-          db_->GetUniqueStatement("UPDATE credit_cards "
-                                  "set guid=? WHERE unique_id=?"));
-      update_s.BindString(0, base::GenerateGUID());
-      update_s.BindInt(1, s.ColumnInt(0));
-
-      if (!update_s.Run())
-        return false;
-    }
-    if (!s.Succeeded())
-      return false;
-  }
-
-  return true;
-}
-
-bool AutofillTable::MigrateToVersion32UpdateProfilesAndCreditCards() {
-  if (db_->DoesColumnExist("autofill_profiles", "unique_id")) {
-    if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( "
-                      "guid VARCHAR PRIMARY KEY, "
-                      "label VARCHAR, "
-                      "first_name VARCHAR, "
-                      "middle_name VARCHAR, "
-                      "last_name VARCHAR, "
-                      "email VARCHAR, "
-                      "company_name VARCHAR, "
-                      "address_line_1 VARCHAR, "
-                      "address_line_2 VARCHAR, "
-                      "city VARCHAR, "
-                      "state VARCHAR, "
-                      "zipcode VARCHAR, "
-                      "country VARCHAR, "
-                      "phone VARCHAR, "
-                      "date_modified INTEGER NOT NULL DEFAULT 0)")) {
-      return false;
-    }
-
-    if (!db_->Execute(
-        "INSERT INTO autofill_profiles_temp "
-        "SELECT guid, label, first_name, middle_name, last_name, email, "
-        "company_name, address_line_1, address_line_2, city, state, "
-        "zipcode, country, phone, date_modified "
-        "FROM autofill_profiles")) {
-      return false;
-    }
-
-    if (!db_->Execute("DROP TABLE autofill_profiles"))
-      return false;
-
-    if (!db_->Execute(
-        "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) {
-      return false;
-    }
-  }
-
-  if (db_->DoesColumnExist("credit_cards", "unique_id")) {
-    if (!db_->Execute("CREATE TABLE credit_cards_temp ( "
-                      "guid VARCHAR PRIMARY KEY, "
-                      "label VARCHAR, "
-                      "name_on_card VARCHAR, "
-                      "expiration_month INTEGER, "
-                      "expiration_year INTEGER, "
-                      "card_number_encrypted BLOB, "
-                      "date_modified INTEGER NOT NULL DEFAULT 0)")) {
-      return false;
-    }
-
-    if (!db_->Execute(
-        "INSERT INTO credit_cards_temp "
-        "SELECT guid, label, name_on_card, expiration_month, "
-        "expiration_year, card_number_encrypted, date_modified "
-        "FROM credit_cards")) {
-      return false;
-    }
-
-    if (!db_->Execute("DROP TABLE credit_cards"))
-      return false;
-
-    if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards"))
-      return false;
-  }
-
-  return true;
-}
-
-// Test the existence of the |first_name| column as an indication that
-// we need a migration.  It is possible that the new |autofill_profiles|
-// schema is in place because the table was newly created when migrating
-// from a pre-version-22 database.
-bool AutofillTable::MigrateToVersion33ProfilesBasedOnFirstName() {
-  if (!db_->DoesTableExist("autofill_profile_names") &&
-      !db_->Execute("CREATE TABLE autofill_profile_names ( "
-                    "guid VARCHAR, "
-                    "first_name VARCHAR, "
-                    "middle_name VARCHAR, "
-                    "last_name VARCHAR)"))
-    return false;
-
-  if (!db_->DoesTableExist("autofill_profile_emails") &&
-      !db_->Execute("CREATE TABLE autofill_profile_emails ( "
-                    "guid VARCHAR, "
-                    "email VARCHAR)"))
-    return false;
-
-  if (!db_->DoesTableExist("autofill_profile_phones") &&
-      !db_->Execute("CREATE TABLE autofill_profile_phones ( "
-                    "guid VARCHAR, "
-                    "type INTEGER DEFAULT 0, "
-                    "number VARCHAR)"))
-    return false;
-
-  if (db_->DoesColumnExist("autofill_profiles", "first_name")) {
-    // Create autofill_profiles_temp table that will receive the data.
-    if (!db_->DoesTableExist("autofill_profiles_temp")) {
-      if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( "
-                        "guid VARCHAR PRIMARY KEY, "
-                        "company_name VARCHAR, "
-                        "address_line_1 VARCHAR, "
-                        "address_line_2 VARCHAR, "
-                        "city VARCHAR, "
-                        "state VARCHAR, "
-                        "zipcode VARCHAR, "
-                        "country VARCHAR, "
-                        "date_modified INTEGER NOT NULL DEFAULT 0)")) {
-        return false;
-      }
-    }
-
-    sql::Statement s(db_->GetUniqueStatement(
-        "SELECT guid, first_name, middle_name, last_name, email, "
-        "company_name, address_line_1, address_line_2, city, state, "
-        "zipcode, country, phone, date_modified "
-        "FROM autofill_profiles"));
-
-    while (s.Step()) {
-      AutofillProfile profile;
-      int index = 0;
-      profile.set_guid(s.ColumnString(index++));
-      DCHECK(base::IsValidGUID(profile.guid()));
-
-      profile.SetRawInfo(NAME_FIRST, s.ColumnString16(index++));
-      profile.SetRawInfo(NAME_MIDDLE, s.ColumnString16(index++));
-      profile.SetRawInfo(NAME_LAST, s.ColumnString16(index++));
-      profile.SetRawInfo(EMAIL_ADDRESS, s.ColumnString16(index++));
-      profile.SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
-      profile.SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(index++));
-      profile.SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(index++));
-      profile.SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++));
-      profile.SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
-      profile.SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++));
-      profile.SetInfo(AutofillType(ADDRESS_HOME_COUNTRY),
-                      s.ColumnString16(index++), app_locale_);
-      profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(index++));
-      int64 date_modified = s.ColumnInt64(index++);
-
-      sql::Statement s_insert(db_->GetUniqueStatement(
-          "INSERT INTO autofill_profiles_temp"
-          "(guid, company_name, address_line_1, address_line_2, city,"
-          " state, zipcode, country, date_modified)"
-          "VALUES (?,?,?,?,?,?,?,?,?)"));
-      index = 0;
-      s_insert.BindString(index++, profile.guid());
-      s_insert.BindString16(index++, profile.GetRawInfo(COMPANY_NAME));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_LINE1));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_LINE2));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_CITY));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_STATE));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_ZIP));
-      s_insert.BindString16(index++, profile.GetRawInfo(ADDRESS_HOME_COUNTRY));
-      s_insert.BindInt64(index++, date_modified);
-
-      if (!s_insert.Run())
-        return false;
-
-      // Add the other bits: names, emails, and phone numbers.
-      if (!AddAutofillProfileNamesForVersion3x(profile, db_) ||
-          !AddAutofillProfileEmails(profile, db_) ||
-          !AddAutofillProfilePhones(profile, db_)) {
-        return false;
-      }
-    }  // endwhile
-    if (!s.Succeeded())
-      return false;
-
-    if (!db_->Execute("DROP TABLE autofill_profiles"))
-      return false;
-
-    if (!db_->Execute(
-        "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) {
-      return false;
-    }
-  }
-
-  // Remove the labels column from the credit_cards table.
-  if (db_->DoesColumnExist("credit_cards", "label")) {
-    if (!db_->Execute("CREATE TABLE credit_cards_temp ( "
-                      "guid VARCHAR PRIMARY KEY, "
-                      "name_on_card VARCHAR, "
-                      "expiration_month INTEGER, "
-                      "expiration_year INTEGER, "
-                      "card_number_encrypted BLOB, "
-                      "date_modified INTEGER NOT NULL DEFAULT 0)")) {
-      return false;
-    }
-
-    if (!db_->Execute(
-        "INSERT INTO credit_cards_temp "
-        "SELECT guid, name_on_card, expiration_month, "
-        "expiration_year, card_number_encrypted, date_modified "
-        "FROM credit_cards")) {
-      return false;
-    }
-
-    if (!db_->Execute("DROP TABLE credit_cards"))
-      return false;
-
-    if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards"))
-      return false;
-  }
-
-  return true;
-}
-
-// Test the existence of the |country_code| column as an indication that
-// we need a migration.  It is possible that the new |autofill_profiles|
-// schema is in place because the table was newly created when migrating
-// from a pre-version-22 database.
-bool AutofillTable::MigrateToVersion34ProfilesBasedOnCountryCode() {
-  if (!db_->DoesColumnExist("autofill_profiles", "country_code")) {
-    if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN "
-                      "country_code VARCHAR")) {
-      return false;
-    }
-
-    // Set all the |country_code| fields to match existing |country| values.
-    sql::Statement s(db_->GetUniqueStatement("SELECT guid, country "
-                                             "FROM autofill_profiles"));
-
-    while (s.Step()) {
-      sql::Statement update_s(
-          db_->GetUniqueStatement("UPDATE autofill_profiles "
-                                  "SET country_code=? WHERE guid=?"));
-
-      base::string16 country = s.ColumnString16(1);
-      update_s.BindString(0, AutofillCountry::GetCountryCode(country,
-                                                             app_locale_));
-      update_s.BindString(1, s.ColumnString(0));
-
-      if (!update_s.Run())
-        return false;
-    }
-    if (!s.Succeeded())
-      return false;
-  }
-
-  return true;
-}
-
-// Correct all country codes with value "UK" to be "GB".  This data
-// was mistakenly introduced in build 686.0.  This migration is to clean
-// it up.  See http://crbug.com/74511 for details.
-bool AutofillTable::MigrateToVersion35GreatBritainCountryCodes() {
-  sql::Statement s(db_->GetUniqueStatement(
-      "UPDATE autofill_profiles SET country_code=\"GB\" "
-      "WHERE country_code=\"UK\""));
-
-  return s.Run();
-}
-
-// Merge and cull older profiles where possible.
-bool AutofillTable::MigrateToVersion37MergeAndCullOlderProfiles() {
-  if (!db_->DoesTableExist("autofill_profiles_trash") &&
-      !db_->Execute("CREATE TABLE autofill_profiles_trash (guid VARCHAR)"))
-    return false;
-
-  sql::Statement s(db_->GetUniqueStatement(
-      "SELECT guid, date_modified FROM autofill_profiles"));
-
-  // Accumulate the good profiles.
-  std::vector<AutofillProfile> accumulated_profiles;
-  std::vector<AutofillProfile*> accumulated_profiles_p;
-  std::map<std::string, int64> modification_map;
-  while (s.Step()) {
-    std::string guid = s.ColumnString(0);
-    int64 date_modified = s.ColumnInt64(1);
-    modification_map.insert(
-        std::pair<std::string, int64>(guid, date_modified));
-
-    sql::Statement s(db_->GetUniqueStatement(
-        "SELECT guid, company_name, address_line_1, address_line_2, city, "
-        " state, zipcode, country, country_code, date_modified "
-        "FROM autofill_profiles "
-        "WHERE guid=?"));
-    s.BindString(0, guid);
-
-    if (!s.Step())
-      return false;
-
-    scoped_ptr<AutofillProfile> profile(new AutofillProfile);
-    int index = 0;
-    profile->set_guid(s.ColumnString(index++));
-    DCHECK(base::IsValidGUID(profile->guid()));
-
-    profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(index++));
-    profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(index++));
-    profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(index++));
-    profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(index++));
-    profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(index++));
-    profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(index++));
-    // Intentionally skip column 7, which stores the localized country name.
-    index++;
-    profile->SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(index++));
-    profile->set_modification_date(
-        base::Time::FromTimeT(s.ColumnInt64(index++)));
-    profile->set_origin(s.ColumnString(index++));
-
-    // Get associated name info.
-    AddAutofillProfileNamesToProfileForVersion37(db_, profile.get());
-
-    // Get associated email info.
-    AddAutofillProfileEmailsToProfile(db_, profile.get());
-
-    // Get associated phone info.
-    AddAutofillProfilePhonesToProfile(db_, profile.get());
-
-    if (PersonalDataManager::IsValidLearnableProfile(*profile, app_locale_)) {
-      std::vector<AutofillProfile> merged_profiles;
-      std::string merged_guid = PersonalDataManager::MergeProfile(
-          *profile, accumulated_profiles_p, app_locale_, &merged_profiles);
-
-      std::swap(accumulated_profiles, merged_profiles);
-
-      accumulated_profiles_p.clear();
-      accumulated_profiles_p.resize(accumulated_profiles.size());
-      std::transform(accumulated_profiles.begin(),
-                     accumulated_profiles.end(),
-                     accumulated_profiles_p.begin(),
-                     address_of<AutofillProfile>);
-
-      // If the profile got merged trash the original.
-      if (merged_guid != profile->guid())
-        AddAutofillGUIDToTrash(profile->guid());
-    } else {
-      // An invalid profile, so trash it.
-      AddAutofillGUIDToTrash(profile->guid());
-    }
-  }  // endwhile
-  if (!s.Succeeded())
-    return false;
-
-  // Drop the current profiles.
-  if (!ClearAutofillProfiles())
-    return false;
-
-  // Add the newly merged profiles back in.
-  for (std::vector<AutofillProfile>::const_iterator
-          iter = accumulated_profiles.begin();
-       iter != accumulated_profiles.end();
-       ++iter) {
-    // Save the profile with its original modification date.
-    std::map<std::string, int64>::const_iterator date_item =
-        modification_map.find(iter->guid());
-    if (date_item == modification_map.end())
-      return false;
-
-    sql::Statement s(db_->GetUniqueStatement(
-        "INSERT INTO autofill_profiles"
-        "(guid, company_name, address_line_1, address_line_2, city, state,"
-        " zipcode, country, country_code, date_modified)"
-        "VALUES (?,?,?,?,?,?,?,?,?,?)"));
-    int index = 0;
-    s.BindString(index++, iter->guid());
-    s.BindString16(index++, GetInfo(*iter, COMPANY_NAME));
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_LINE1));
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_LINE2));
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_CITY));
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_STATE));
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_ZIP));
-    s.BindString16(index++, base::string16());  // This column is deprecated.
-    s.BindString16(index++, GetInfo(*iter, ADDRESS_HOME_COUNTRY));
-    s.BindInt64(index++, date_item->second);
-
-    if (!s.Run())
-      return false;
-
-    if (!AddAutofillProfileNamesForVersion3x(*iter, db_) ||
-        !AddAutofillProfileEmails(*iter, db_) ||
-        !AddAutofillProfilePhones(*iter, db_)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool AutofillTable::MigrateToVersion51AddOriginColumn() {
-  sql::Transaction transaction(db_);
-  if (!transaction.Begin())
-    return false;
-
-  // Add origin to autofill_profiles.
-  if (!db_->DoesColumnExist("autofill_profiles", "origin") &&
-      !db_->Execute("ALTER TABLE autofill_profiles "
-                    "ADD COLUMN origin VARCHAR DEFAULT ''")) {
-    return false;
-  }
-
-  // Add origin to credit_cards.
-  if (!db_->DoesColumnExist("credit_cards", "origin") &&
-      !db_->Execute("ALTER TABLE credit_cards "
-                    "ADD COLUMN origin VARCHAR DEFAULT ''")) {
-      return false;
-  }
-
-  return transaction.Commit();
-}
-
 bool AutofillTable::MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields() {
   sql::Transaction transaction(db_);
   if (!transaction.Begin())
@@ -2843,4 +1976,13 @@
   return transaction.Commit();
 }
 
+bool AutofillTable::MigrateToVersion63AddServerRecipientName() {
+  if (!db_->DoesColumnExist("server_addresses", "recipient_name") &&
+      !db_->Execute("ALTER TABLE server_addresses ADD COLUMN "
+                    "recipient_name VARCHAR")) {
+    return false;
+  }
+  return true;
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index a25006a7..221cbe8 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -174,6 +174,7 @@
 //
 //   id                 String assigned by the server to identify this address.
 //                      This is opaque to the client.
+//   recipient_name     Added in v63.
 //   company_name
 //   street_address     The combined lines of the street address.
 //   address_1          Also known as "administrative area". This is normally
@@ -358,20 +359,6 @@
   bool ClearAutofillProfiles();
 
   // Table migration functions.
-  // Removes empty values for autofill that were incorrectly stored in the DB
-  // See bug http://crbug.com/6111
-  bool MigrateToVersion22ClearAutofillEmptyValueElements();
-  bool MigrateToVersion23AddCardNumberEncryptedColumn();
-  bool MigrateToVersion24CleanupOversizedStringFields();
-  bool MigrateToVersion27UpdateLegacyCreditCards();
-  bool MigrateToVersion30AddDateModifed();
-  bool MigrateToVersion31AddGUIDToCreditCardsAndProfiles();
-  bool MigrateToVersion32UpdateProfilesAndCreditCards();
-  bool MigrateToVersion33ProfilesBasedOnFirstName();
-  bool MigrateToVersion34ProfilesBasedOnCountryCode();
-  bool MigrateToVersion35GreatBritainCountryCodes();
-  bool MigrateToVersion37MergeAndCullOlderProfiles();
-  bool MigrateToVersion51AddOriginColumn();
   bool MigrateToVersion54AddI18nFieldsAndRemoveDeprecatedFields();
   bool MigrateToVersion55MergeAutofillDatesTable();
   bool MigrateToVersion56AddProfileLanguageCodeForFormatting();
@@ -379,6 +366,7 @@
   bool MigrateToVersion60AddServerCards();
   bool MigrateToVersion61AddUsageStats();
   bool MigrateToVersion62AddUsageStatsForUnmaskedCards();
+  bool MigrateToVersion63AddServerRecipientName();
 
   // Max data length saved in the table;
   static const size_t kMaxDataLength;
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index a99b3751..7be33a9 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -84,6 +84,7 @@
   profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                      base::UTF8ToUTF16(JoinString(street_address, '\n')));
 
+  profile.SetRawInfo(NAME_FULL, base::UTF8ToUTF16(address.recipient_name()));
   profile.SetRawInfo(COMPANY_NAME, base::UTF8ToUTF16(address.company_name()));
   profile.SetRawInfo(ADDRESS_HOME_STATE,
                      base::UTF8ToUTF16(address.address_1()));
diff --git a/components/autofill/ios/DEPS b/components/autofill/ios/DEPS
new file mode 100644
index 0000000..450c6e9
--- /dev/null
+++ b/components/autofill/ios/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+ios/public/provider/web",
+  "+ios/web/public",
+]
diff --git a/components/autofill/ios/OWNERS b/components/autofill/ios/OWNERS
new file mode 100644
index 0000000..ca512d20e
--- /dev/null
+++ b/components/autofill/ios/OWNERS
@@ -0,0 +1 @@
+jdonnelly@chromium.org
diff --git a/components/autofill/ios/browser/autofill_driver_ios.h b/components/autofill/ios/browser/autofill_driver_ios.h
new file mode 100644
index 0000000..1b670f7
--- /dev/null
+++ b/components/autofill/ios/browser/autofill_driver_ios.h
@@ -0,0 +1,87 @@
+// Copyright 2013 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_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_
+#define COMPONENTS_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_
+
+#include <string>
+
+#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/autofill_driver.h"
+#include "components/autofill/core/browser/autofill_external_delegate.h"
+#include "components/autofill/core/browser/autofill_manager.h"
+#include "ios/web/public/web_state/web_state_user_data.h"
+
+namespace web {
+class WebState;
+}
+
+@protocol AutofillDriverIOSBridge;
+
+namespace autofill {
+
+class AutofillManagerDelegate;
+
+// Class that drives autofill flow on iOS. There is one instance per
+// WebContents.
+class AutofillDriverIOS : public AutofillDriver,
+                          public web::WebStateUserData<AutofillDriverIOS> {
+ public:
+  static void CreateForWebStateAndDelegate(
+      web::WebState* web_state,
+      AutofillClient* client,
+      id<AutofillDriverIOSBridge> bridge,
+      const std::string& app_locale,
+      AutofillManager::AutofillDownloadManagerState enable_download_manager);
+
+  // AutofillDriver:
+  bool IsOffTheRecord() const override;
+  net::URLRequestContextGetter* GetURLRequestContext() override;
+  bool RendererIsAvailable() override;
+  void SendFormDataToRenderer(int query_id,
+                              RendererFormDataAction action,
+                              const FormData& data) override;
+  void PingRenderer() override;
+  void DetectAccountCreationForms(
+      const std::vector<autofill::FormStructure*>& forms) override;
+  void SendAutofillTypePredictionsToRenderer(
+      const std::vector<FormStructure*>& forms) override;
+  void RendererShouldClearFilledForm() override;
+  void RendererShouldClearPreviewedForm() override;
+  void RendererShouldAcceptDataListSuggestion(
+      const base::string16& value) override;
+  base::SequencedWorkerPool* GetBlockingPool() override;
+
+  AutofillManager* autofill_manager() { return &autofill_manager_; }
+
+  void RendererShouldFillFieldWithValue(const base::string16& value) override;
+  void RendererShouldPreviewFieldWithValue(
+      const base::string16& value) override;
+  void PopupHidden() override;
+
+ private:
+  AutofillDriverIOS(
+      web::WebState* web_state,
+      AutofillClient* client,
+      id<AutofillDriverIOSBridge> bridge,
+      const std::string& app_locale,
+      AutofillManager::AutofillDownloadManagerState enable_download_manager);
+  ~AutofillDriverIOS() override;
+
+  // The WebState with which this object is associated.
+  web::WebState* web_state_;
+
+  // AutofillDriverIOSBridge instance that is passed in.
+  id<AutofillDriverIOSBridge> bridge_;
+
+  // AutofillManager instance via which this object drives the shared Autofill
+  // code.
+  AutofillManager autofill_manager_;
+  // AutofillExternalDelegate instance that is passed to the AutofillManager.
+  AutofillExternalDelegate autofill_external_delegate_;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CONTENT_BROWSER_AUTOFILL_DRIVER_IOS_H_
diff --git a/components/autofill/ios/browser/autofill_driver_ios.mm b/components/autofill/ios/browser/autofill_driver_ios.mm
new file mode 100644
index 0000000..1087f9dd
--- /dev/null
+++ b/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -0,0 +1,104 @@
+// Copyright 2013 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/autofill/ios/browser/autofill_driver_ios.h"
+
+#include "components/autofill/ios/browser/autofill_driver_ios_bridge.h"
+#include "ios/web/public/browser_state.h"
+#include "ios/web/public/web_state/web_state.h"
+#include "ios/web/public/web_thread.h"
+
+DEFINE_WEB_STATE_USER_DATA_KEY(autofill::AutofillDriverIOS);
+
+namespace autofill {
+
+// static
+void AutofillDriverIOS::CreateForWebStateAndDelegate(
+    web::WebState* web_state,
+    AutofillClient* client,
+    id<AutofillDriverIOSBridge> bridge,
+    const std::string& app_locale,
+    AutofillManager::AutofillDownloadManagerState enable_download_manager) {
+  if (FromWebState(web_state))
+    return;
+
+  web_state->SetUserData(
+      UserDataKey(),
+      new AutofillDriverIOS(web_state, client, bridge, app_locale,
+                            enable_download_manager));
+}
+
+AutofillDriverIOS::AutofillDriverIOS(
+    web::WebState* web_state,
+    AutofillClient* client,
+    id<AutofillDriverIOSBridge> bridge,
+    const std::string& app_locale,
+    AutofillManager::AutofillDownloadManagerState enable_download_manager)
+    : web_state_(web_state),
+      bridge_(bridge),
+      autofill_manager_(this, client, app_locale, enable_download_manager),
+      autofill_external_delegate_(&autofill_manager_, this) {
+  autofill_manager_.SetExternalDelegate(&autofill_external_delegate_);
+}
+
+AutofillDriverIOS::~AutofillDriverIOS() {}
+
+bool AutofillDriverIOS::IsOffTheRecord() const {
+  return web_state_->GetBrowserState()->IsOffTheRecord();
+}
+
+net::URLRequestContextGetter* AutofillDriverIOS::GetURLRequestContext() {
+  return web_state_->GetBrowserState()->GetRequestContext();
+}
+
+base::SequencedWorkerPool* AutofillDriverIOS::GetBlockingPool() {
+  return web::WebThread::GetBlockingPool();
+}
+
+bool AutofillDriverIOS::RendererIsAvailable() {
+  return true;
+}
+
+void AutofillDriverIOS::SendFormDataToRenderer(
+    int query_id,
+    RendererFormDataAction action,
+    const FormData& data) {
+  [bridge_ onFormDataFilled:query_id result:data];
+}
+
+void AutofillDriverIOS::PingRenderer() {
+}
+
+void AutofillDriverIOS::DetectAccountCreationForms(
+    const std::vector<autofill::FormStructure*>& forms) {
+  autofill_manager_.client()->DetectAccountCreationForms(nullptr, forms);
+};
+
+void AutofillDriverIOS::SendAutofillTypePredictionsToRenderer(
+    const std::vector<FormStructure*>& forms) {
+  [bridge_ sendAutofillTypePredictionsToRenderer:forms];
+}
+
+void AutofillDriverIOS::RendererShouldAcceptDataListSuggestion(
+    const base::string16& value) {
+}
+
+void AutofillDriverIOS::RendererShouldClearFilledForm() {
+}
+
+void AutofillDriverIOS::RendererShouldClearPreviewedForm() {
+}
+
+void AutofillDriverIOS::RendererShouldFillFieldWithValue(
+    const base::string16& value) {
+}
+
+void AutofillDriverIOS::RendererShouldPreviewFieldWithValue(
+    const base::string16& value) {
+}
+
+void AutofillDriverIOS::PopupHidden() {
+}
+
+}  // namespace autofill
diff --git a/components/autofill/ios/browser/autofill_driver_ios_bridge.h b/components/autofill/ios/browser/autofill_driver_ios_bridge.h
new file mode 100644
index 0000000..6a00cc85
--- /dev/null
+++ b/components/autofill/ios/browser/autofill_driver_ios_bridge.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_
+#define COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_
+
+namespace autofill {
+struct FormData;
+class FormStructure;
+}
+
+@protocol AutofillDriverIOSBridge
+
+- (void)onFormDataFilled:(uint16)query_id
+                  result:(const autofill::FormData&)result;
+
+- (void)sendAutofillTypePredictionsToRenderer:
+        (const std::vector<autofill::FormStructure*>&)forms;
+
+@end
+
+#endif  // COMPONENTS_AUTOFILL_IOS_BROWSER_AUTOFILL_DRIVER_IOS_BRIDGE_H_
diff --git a/components/components.gyp b/components/components.gyp
index 17e4235b..db6d9b0 100644
--- a/components/components.gyp
+++ b/components/components.gyp
@@ -88,11 +88,15 @@
         'webp_transcode.gypi',
       ],
     }],
+    ['OS != "android"', {
+      'includes': [
+        'feedback.gypi',
+      ]
+    }],
     ['OS != "ios" and OS != "android"', {
       'includes': [
         'audio_modem.gypi',
         'copresence.gypi',
-        'feedback.gypi',
         'proximity_auth.gypi',
         'storage_monitor.gypi',
       ]
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 4f44e2b..4a2f56d 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -165,6 +165,10 @@
             'enhanced_bookmarks/image_store_ios_unittest.mm',
             'enhanced_bookmarks/image_store_unittest.cc',
             'enhanced_bookmarks/item_position_unittest.cc',
+            'feedback/feedback_common_unittest.cc',
+            'feedback/feedback_data_unittest.cc',
+            'feedback/feedback_uploader_chrome_unittest.cc',
+            'feedback/feedback_uploader_unittest.cc',
             'gcm_driver/gcm_account_mapper_unittest.cc',
             'gcm_driver/gcm_channel_status_request_unittest.cc',
             'gcm_driver/gcm_client_impl_unittest.cc',
@@ -397,6 +401,7 @@
             'components.gyp:enhanced_bookmarks',
             'components.gyp:enhanced_bookmarks_test_support',
             'components.gyp:favicon_base',
+            'components.gyp:feedback_component',
             'components.gyp:gcm_driver',
             'components.gyp:gcm_driver_test_support',
             'components.gyp:google_core_browser',
@@ -532,43 +537,87 @@
                 'webp_transcode/webp_decoder_unittest.mm',
               ],
               'sources/': [
+                # First start by excluding all tests on iOS.
                 ['exclude', '\\.cc$'],
                 ['exclude', '\\.mm$'],
+
+                # Include the test runner.
                 ['include', '^test/run_all_unittests\\.cc$'],
+
+                # Include tests for all components that are built on iOS.
                 ['include', '^auto_login_parser/'],
-                ['include', '^autofill/core/'],
+                ['include', '^autofill/'],
                 ['include', '^bookmarks/'],
+                ['include', '^captive_portal/'],
+                ['include', '^cloud_devices/'],
                 ['include', '^component_updater/'],
-                ['include', '^crash/'],
                 ['include', '^content_settings/'],
+                ['include', '^crash/'],
+                ['include', '^cronet/'],
+                ['include', '^crx_file/'],
                 ['include', '^data_reduction_proxy/'],
+                ['include', '^device_event_log/'],
                 ['include', '^dom_distiller/'],
+                ['include', '^domain_reliability/'],
                 ['include', '^enhanced_bookmarks/'],
+                ['include', '^error_page/'],
+                ['include', '^favicon/'],
+                ['include', '^favicon_base/'],
                 ['include', '^gcm_driver/'],
                 ['include', '^google/'],
+                ['include', '^handoff/'],
                 ['include', '^history/'],
+                ['include', '^infobars/'],
                 ['include', '^invalidation/'],
                 ['include', '^json_schema/'],
-                ['include', '^keyed_service/core/'],
+                ['include', '^keyed_service/'],
                 ['include', '^language_usage_metrics/'],
                 ['include', '^leveldb_proto/'],
+                ['include', '^login/'],
                 ['include', '^metrics/'],
+                ['include', '^navigation_metrics/'],
+                ['include', '^network_hints/'],
                 ['include', '^network_time/'],
+                ['include', '^omnibox/'],
+                ['include', '^onc/'],
+                ['include', '^open_from_clipboard/'],
+                ['include', '^os_crypt/'],
+                ['include', '^ownership/'],
+                ['include', '^packed_ct_ev_whitelist/'],
                 ['include', '^password_manager/'],
-                ['include', '^precache/core/'],
+                ['include', '^policy/'],
+                ['include', '^precache/'],
+                ['include', '^pref_registry/'],
                 ['include', '^query_parser/'],
+                ['include', '^rappor/'],
+                ['include', '^renderer_context_menu/'],
                 ['include', '^search/'],
                 ['include', '^search_engines/'],
                 ['include', '^search_provider_logos/'],
-                ['include', '^sessions/ios/'],
-                ['include', '^sessions/serialized_navigation_entry_unittest\\.cc$'],
-                ['exclude', '^signin/core/browser/mutable_profile_oauth2_token_service_unittest\\.cc$'],
+                ['include', '^sessions/'],
+                ['include', '^signin/'],
+                ['include', '^startup_metric_utils/'],
                 ['include', '^suggestions/'],
                 ['include', '^sync_driver/'],
                 ['include', '^translate/'],
+                ['include', '^ui_zoom/'],
+                ['include', '^update_client/'],
                 ['include', '^url_fixer/'],
+                ['include', '^url_matcher/'],
+                ['include', '^user_prefs/'],
                 ['include', '^variations/'],
+                ['include', '^wallpaper/'],
+                ['include', '^web_resource/'],
+                ['include', '^webdata/'],
+                ['include', '^webdata_services/'],
                 ['include', '^webp_transcode/'],
+
+                # Exclude individual tests that are known not to work on iOS.
+                ['exclude', '^signin/core/browser/mutable_profile_oauth2_token_service_unittest\\.cc$'],
+
+                # Exclude all tests that depends on //content (based on layered-
+                # component directory structure).
+                ['exclude', '^[^/]*/content/'],
               ],
               'dependencies': [
                 '../ios/ios_tests.gyp:test_support_ios',
@@ -634,6 +683,10 @@
                 'invalidation/invalidation_service_android_unittest.cc',
               ],
               'sources!': [
+                'feedback/feedback_common_unittest.cc',
+                'feedback/feedback_data_unittest.cc',
+                'feedback/feedback_uploader_chrome_unittest.cc',
+                'feedback/feedback_uploader_unittest.cc',
                 'gcm_driver/gcm_account_mapper_unittest.cc',
                 'gcm_driver/gcm_channel_status_request_unittest.cc',
                 'gcm_driver/gcm_client_impl_unittest.cc',
@@ -651,6 +704,7 @@
                 '../testing/android/native_test.gyp:native_test_native_code',
               ],
               'dependencies!': [
+                'components.gyp:feedback_component',
                 'components.gyp:storage_monitor',
                 'components.gyp:storage_monitor_test_support',
                 'components.gyp:web_modal',
@@ -688,10 +742,6 @@
                 'copresence/rpc/http_post_unittest.cc',
                 'copresence/rpc/rpc_handler_unittest.cc',
                 'copresence/timed_map_unittest.cc',
-                'feedback/feedback_common_unittest.cc',
-                'feedback/feedback_data_unittest.cc',
-                'feedback/feedback_uploader_chrome_unittest.cc',
-                'feedback/feedback_uploader_unittest.cc',
                 'proximity_auth/base64url_unittest.cc',
                 'proximity_auth/bluetooth_connection_finder_unittest.cc',
                 'proximity_auth/bluetooth_connection_unittest.cc',
@@ -713,7 +763,6 @@
                 'components.gyp:copresence',
                 'components.gyp:copresence_test_support',
                 'components.gyp:cryptauth',
-                'components.gyp:feedback_component',
                 'components.gyp:proximity_auth',
               ],
             }],
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.cc b/components/content_settings/core/browser/content_settings_pref_provider.cc
index 1c0dcc35..c506051 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.cc
+++ b/components/content_settings/core/browser/content_settings_pref_provider.cc
@@ -96,7 +96,7 @@
   }
 
   // Read content settings exceptions.
-  ReadContentSettingsFromPref(false);
+  ReadContentSettingsFromPref();
 
   if (!is_incognito_) {
     UMA_HISTOGRAM_COUNTS("ContentSettings.NumberOfExceptions",
@@ -352,7 +352,7 @@
   }
 }
 
-void PrefProvider::ReadContentSettingsFromPref(bool overwrite) {
+void PrefProvider::ReadContentSettingsFromPref() {
   // |DictionaryPrefUpdate| sends out notifications when destructed. This
   // construction order ensures |AutoLock| gets destroyed first and |lock_| is
   // not held when the notifications are sent. Also, |auto_reset| must be still
@@ -365,8 +365,7 @@
   const base::DictionaryValue* all_settings_dictionary =
       prefs_->GetDictionary(prefs::kContentSettingsPatternPairs);
 
-  if (overwrite)
-    value_map_.clear();
+  value_map_.clear();
 
   // Careful: The returned value could be NULL if the pref has never been set.
   if (!all_settings_dictionary)
@@ -491,7 +490,7 @@
   if (updating_preferences_)
     return;
 
-  ReadContentSettingsFromPref(true);
+  ReadContentSettingsFromPref();
 
   NotifyObservers(ContentSettingsPattern(),
                   ContentSettingsPattern(),
diff --git a/components/content_settings/core/browser/content_settings_pref_provider.h b/components/content_settings/core/browser/content_settings_pref_provider.h
index 9d715897..0727e10 100644
--- a/components/content_settings/core/browser/content_settings_pref_provider.h
+++ b/components/content_settings/core/browser/content_settings_pref_provider.h
@@ -68,9 +68,8 @@
  private:
   friend class DeadlockCheckerThread;  // For testing.
   // Reads all content settings exceptions from the preference and load them
-  // into the |value_map_|. The |value_map_| is cleared first if |overwrite| is
-  // true.
-  void ReadContentSettingsFromPref(bool overwrite);
+  // into the |value_map_|. The |value_map_| is cleared first.
+  void ReadContentSettingsFromPref();
 
   // Callback for changes in the pref with the same name.
   void OnContentSettingsPatternPairsChanged();
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index b7aa20e3..54e4deb 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -248,11 +248,6 @@
   }
 }
 
-bool NewInitialMetricsTimingEnabled() {
-  return base::FieldTrialList::FindFullName("UMAInitialMetricsTiming") ==
-      "Enabled";
-}
-
 void MarkAppCleanShutdownAndCommit(CleanExitBeacon* clean_exit_beacon,
                                    PrefService* local_state) {
   clean_exit_beacon->WriteBeaconValue(true);
@@ -889,30 +884,17 @@
       return;
 
     case INIT_TASK_DONE:
-      if (NewInitialMetricsTimingEnabled()) {
-        PrepareInitialMetricsLog();
-        // Stage the first log, which could be a stability log (either one
-        // for created in this session or from a previous session) or the
-        // initial metrics log that was just created.
-        log_manager_.StageNextLogForUpload();
-        if (has_initial_stability_log_) {
-          // The initial stability log was just staged.
-          has_initial_stability_log_ = false;
-          state_ = SENDING_INITIAL_STABILITY_LOG;
-        } else {
-          state_ = SENDING_INITIAL_METRICS_LOG;
-        }
+      PrepareInitialMetricsLog();
+      // Stage the first log, which could be a stability log (either one
+      // for created in this session or from a previous session) or the
+      // initial metrics log that was just created.
+      log_manager_.StageNextLogForUpload();
+      if (has_initial_stability_log_) {
+        // The initial stability log was just staged.
+        has_initial_stability_log_ = false;
+        state_ = SENDING_INITIAL_STABILITY_LOG;
       } else {
-        if (has_initial_stability_log_) {
-          // There's an initial stability log, ready to send.
-          log_manager_.StageNextLogForUpload();
-          has_initial_stability_log_ = false;
-          state_ = SENDING_INITIAL_STABILITY_LOG;
-        } else {
-          PrepareInitialMetricsLog();
-          log_manager_.StageNextLogForUpload();
-          state_ = SENDING_INITIAL_METRICS_LOG;
-        }
+        state_ = SENDING_INITIAL_METRICS_LOG;
       }
       break;
 
@@ -1047,8 +1029,6 @@
                             ResponseCodeToStatus(response_code),
                             NUM_RESPONSE_STATUSES);
 
-  bool suppress_reschedule = false;
-
   bool upload_succeeded = response_code == 200;
 
   // Provide boolean for error recovery (allow us to ignore response_code).
@@ -1074,16 +1054,8 @@
   if (!log_manager_.has_staged_log()) {
     switch (state_) {
       case SENDING_INITIAL_STABILITY_LOG:
-        if (NewInitialMetricsTimingEnabled()) {
-          // The initial metrics log is already in the queue of unsent logs.
-          state_ = SENDING_OLD_LOGS;
-        } else {
-          PrepareInitialMetricsLog();
-          log_manager_.StageNextLogForUpload();
-          SendStagedLog();
-          state_ = SENDING_INITIAL_METRICS_LOG;
-          suppress_reschedule = true;
-        }
+        // The initial metrics log is already in the queue of unsent logs.
+        state_ = SENDING_OLD_LOGS;
         break;
 
       case SENDING_INITIAL_METRICS_LOG:
@@ -1111,13 +1083,7 @@
   // Error 400 indicates a problem with the log, not with the server, so
   // don't consider that a sign that the server is in trouble.
   bool server_is_healthy = upload_succeeded || response_code == 400;
-  // Don't notify the scheduler that the upload is finished if we've only just
-  // sent the initial stability log, but not yet the initial metrics log (treat
-  // the two as a single unit of work as far as the scheduler is concerned).
-  if (!suppress_reschedule) {
-    scheduler_->UploadFinished(server_is_healthy,
-                               log_manager_.has_unsent_logs());
-  }
+  scheduler_->UploadFinished(server_is_healthy, log_manager_.has_unsent_logs());
 
   if (server_is_healthy)
     client_->OnLogUploadComplete();
diff --git a/components/search_engines/keyword_table.cc b/components/search_engines/keyword_table.cc
index 08dea92..59dff732 100644
--- a/components/search_engines/keyword_table.cc
+++ b/components/search_engines/keyword_table.cc
@@ -193,45 +193,6 @@
                                     bool* update_compatible_version) {
   // Migrate if necessary.
   switch (version) {
-    case 21:
-      *update_compatible_version = true;
-      return MigrateToVersion21AutoGenerateKeywordColumn();
-    case 25:
-      *update_compatible_version = true;
-      return MigrateToVersion25AddLogoIDColumn();
-    case 26:
-      *update_compatible_version = true;
-      return MigrateToVersion26AddCreatedByPolicyColumn();
-    case 28:
-      *update_compatible_version = true;
-      return MigrateToVersion28SupportsInstantColumn();
-    case 29:
-      *update_compatible_version = true;
-      return MigrateToVersion29InstantURLToSupportsInstant();
-    case 38:
-      *update_compatible_version = true;
-      return MigrateToVersion38AddLastModifiedColumn();
-    case 39:
-      *update_compatible_version = true;
-      return MigrateToVersion39AddSyncGUIDColumn();
-    case 44:
-      *update_compatible_version = true;
-      return MigrateToVersion44AddDefaultSearchProviderBackup();
-    case 45:
-      *update_compatible_version = true;
-      return MigrateToVersion45RemoveLogoIDAndAutogenerateColumns();
-    case 47:
-      *update_compatible_version = true;
-      return MigrateToVersion47AddAlternateURLsColumn();
-    case 48:
-      *update_compatible_version = true;
-      return MigrateToVersion48RemoveKeywordsBackup();
-    case 49:
-      *update_compatible_version = true;
-      return MigrateToVersion49AddSearchTermsReplacementKeyColumn();
-    case 52:
-      *update_compatible_version = true;
-      return MigrateToVersion52AddImageSearchAndPOSTSupport();
     case 53:
       *update_compatible_version = true;
       return MigrateToVersion53AddNewTabURLColumn();
@@ -315,140 +276,6 @@
   return ColumnsForVersion(WebDatabase::kCurrentVersionNumber, false);
 }
 
-bool KeywordTable::MigrateToVersion21AutoGenerateKeywordColumn() {
-  return db_->Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword "
-                      "INTEGER DEFAULT 0");
-}
-
-bool KeywordTable::MigrateToVersion25AddLogoIDColumn() {
-  return db_->Execute(
-      "ALTER TABLE keywords ADD COLUMN logo_id INTEGER DEFAULT 0");
-}
-
-bool KeywordTable::MigrateToVersion26AddCreatedByPolicyColumn() {
-  return db_->Execute("ALTER TABLE keywords ADD COLUMN created_by_policy "
-                      "INTEGER DEFAULT 0");
-}
-
-bool KeywordTable::MigrateToVersion28SupportsInstantColumn() {
-  return db_->Execute("ALTER TABLE keywords ADD COLUMN supports_instant "
-                      "INTEGER DEFAULT 0");
-}
-
-bool KeywordTable::MigrateToVersion29InstantURLToSupportsInstant() {
-  sql::Transaction transaction(db_);
-  return transaction.Begin() &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url VARCHAR") &&
-      db_->Execute("CREATE TABLE keywords_temp ("
-                   "id INTEGER PRIMARY KEY,"
-                   "short_name VARCHAR NOT NULL,"
-                   "keyword VARCHAR NOT NULL,"
-                   "favicon_url VARCHAR NOT NULL,"
-                   "url VARCHAR NOT NULL,"
-                   "safe_for_autoreplace INTEGER,"
-                   "originating_url VARCHAR,"
-                   "date_created INTEGER DEFAULT 0,"
-                   "usage_count INTEGER DEFAULT 0,"
-                   "input_encodings VARCHAR,"
-                   "show_in_default_list INTEGER,"
-                   "suggest_url VARCHAR,"
-                   "prepopulate_id INTEGER DEFAULT 0,"
-                   "autogenerate_keyword INTEGER DEFAULT 0,"
-                   "logo_id INTEGER DEFAULT 0,"
-                   "created_by_policy INTEGER DEFAULT 0,"
-                   "instant_url VARCHAR)") &&
-      db_->Execute("INSERT INTO keywords_temp SELECT id, short_name, keyword, "
-                   "favicon_url, url, safe_for_autoreplace, originating_url, "
-                   "date_created, usage_count, input_encodings, "
-                   "show_in_default_list, suggest_url, prepopulate_id, "
-                   "autogenerate_keyword, logo_id, created_by_policy, "
-                   "instant_url FROM keywords") &&
-      db_->Execute("DROP TABLE keywords") &&
-      db_->Execute("ALTER TABLE keywords_temp RENAME TO keywords") &&
-      transaction.Commit();
-}
-
-bool KeywordTable::MigrateToVersion38AddLastModifiedColumn() {
-  return db_->Execute(
-      "ALTER TABLE keywords ADD COLUMN last_modified INTEGER DEFAULT 0");
-}
-
-bool KeywordTable::MigrateToVersion39AddSyncGUIDColumn() {
-  return db_->Execute("ALTER TABLE keywords ADD COLUMN sync_guid VARCHAR");
-}
-
-bool KeywordTable::MigrateToVersion44AddDefaultSearchProviderBackup() {
-  std::string query("CREATE TABLE keywords_backup AS SELECT " +
-      ColumnsForVersion(44, false) + " FROM keywords ORDER BY id ASC");
-  sql::Transaction transaction(db_);
-  return transaction.Begin() &&
-      meta_table_->SetValue("Default Search Provider ID Backup",
-                            GetDefaultSearchProviderID()) &&
-      (!db_->DoesTableExist("keywords_backup") ||
-       db_->Execute("DROP TABLE keywords_backup")) &&
-      db_->Execute(query.c_str()) &&
-      transaction.Commit();
-}
-
-bool KeywordTable::MigrateToVersion45RemoveLogoIDAndAutogenerateColumns() {
-  sql::Transaction transaction(db_);
-  if (!transaction.Begin())
-    return false;
-
-  // The version 43 migration should have been written to do this, but since it
-  // wasn't, we'll do it now.  Unfortunately a previous change deleted this for
-  // some users, so we can't be sure this will succeed (so don't bail on error).
-  meta_table_->DeleteKey("Default Search Provider Backup");
-
-  return MigrateKeywordsTableForVersion45("keywords") &&
-      MigrateKeywordsTableForVersion45("keywords_backup") &&
-      meta_table_->SetValue("Default Search Provider ID Backup Signature",
-                            std::string()) &&
-      transaction.Commit();
-}
-
-bool KeywordTable::MigrateToVersion47AddAlternateURLsColumn() {
-  sql::Transaction transaction(db_);
-  return transaction.Begin() &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN "
-                   "alternate_urls VARCHAR DEFAULT ''") &&
-      db_->Execute("ALTER TABLE keywords_backup ADD COLUMN "
-                   "alternate_urls VARCHAR DEFAULT ''") &&
-      meta_table_->SetValue("Default Search Provider ID Backup Signature",
-                            std::string()) &&
-      transaction.Commit();
-}
-
-bool KeywordTable::MigrateToVersion48RemoveKeywordsBackup() {
-  sql::Transaction transaction(db_);
-  return transaction.Begin() &&
-      meta_table_->DeleteKey("Default Search Provider ID Backup") &&
-      meta_table_->DeleteKey("Default Search Provider ID Backup Signature") &&
-      db_->Execute("DROP TABLE keywords_backup") &&
-      transaction.Commit();
-}
-
-bool KeywordTable::MigrateToVersion49AddSearchTermsReplacementKeyColumn() {
-  return db_->Execute("ALTER TABLE keywords ADD COLUMN "
-                      "search_terms_replacement_key VARCHAR DEFAULT ''");
-}
-
-bool KeywordTable::MigrateToVersion52AddImageSearchAndPOSTSupport() {
-  sql::Transaction transaction(db_);
-  return transaction.Begin() &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN image_url "
-                   "VARCHAR DEFAULT ''") &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN search_url_post_params "
-                   "VARCHAR DEFAULT ''") &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN suggest_url_post_params "
-                   "VARCHAR DEFAULT ''") &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN instant_url_post_params "
-                   "VARCHAR DEFAULT ''") &&
-      db_->Execute("ALTER TABLE keywords ADD COLUMN image_url_post_params "
-                   "VARCHAR DEFAULT ''") &&
-      transaction.Commit();
-}
-
 bool KeywordTable::MigrateToVersion53AddNewTabURLColumn() {
   return db_->Execute("ALTER TABLE keywords ADD COLUMN new_tab_url "
                       "VARCHAR DEFAULT ''");
diff --git a/components/search_engines/keyword_table.h b/components/search_engines/keyword_table.h
index 62e7e79..ef45694 100644
--- a/components/search_engines/keyword_table.h
+++ b/components/search_engines/keyword_table.h
@@ -126,19 +126,6 @@
   static std::string GetKeywordColumns();
 
   // Table migration functions.
-  bool MigrateToVersion21AutoGenerateKeywordColumn();
-  bool MigrateToVersion25AddLogoIDColumn();
-  bool MigrateToVersion26AddCreatedByPolicyColumn();
-  bool MigrateToVersion28SupportsInstantColumn();
-  bool MigrateToVersion29InstantURLToSupportsInstant();
-  bool MigrateToVersion38AddLastModifiedColumn();
-  bool MigrateToVersion39AddSyncGUIDColumn();
-  bool MigrateToVersion44AddDefaultSearchProviderBackup();
-  bool MigrateToVersion45RemoveLogoIDAndAutogenerateColumns();
-  bool MigrateToVersion47AddAlternateURLsColumn();
-  bool MigrateToVersion48RemoveKeywordsBackup();
-  bool MigrateToVersion49AddSearchTermsReplacementKeyColumn();
-  bool MigrateToVersion52AddImageSearchAndPOSTSupport();
   bool MigrateToVersion53AddNewTabURLColumn();
   bool MigrateToVersion59RemoveExtensionKeywords();
 
diff --git a/components/test/data/web_database/version_20.sql b/components/test/data/web_database/version_20.sql
deleted file mode 100644
index c3913ef2..0000000
--- a/components/test/data/web_database/version_20.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','20');
-INSERT INTO "meta" VALUES('last_compatible_version','20');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','27');
-INSERT INTO "meta" VALUES('Default Search Provider ID','7');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1);
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2);
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3);
-INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0);
-INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0);
-INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0);
-INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-COMMIT;
diff --git a/components/test/data/web_database/version_21.sql b/components/test/data/web_database/version_21.sql
deleted file mode 100644
index a77ab7e..0000000
--- a/components/test/data/web_database/version_21.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','21');
-INSERT INTO "meta" VALUES('last_compatible_version','21');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','27');
-INSERT INTO "meta" VALUES('Default Search Provider ID','7');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1);
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0);
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0);
-INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-INSERT INTO "autofill" VALUES('Name','John Doe','john doe',10,1);
-INSERT INTO "autofill" VALUES('Name','','',11,1);
-INSERT INTO "autofill" VALUES('Email','jane@example.com','jane@example.com',20,3);
-INSERT INTO "autofill" VALUES('Email','','',21,4);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-INSERT INTO "autofill_dates" VALUES(10,1384299100);
-INSERT INTO "autofill_dates" VALUES(11,1384299200);
-INSERT INTO "autofill_dates" VALUES(20,1384299300);
-INSERT INTO "autofill_dates" VALUES(20,1384299301);
-INSERT INTO "autofill_dates" VALUES(21,1384299401);
-INSERT INTO "autofill_dates" VALUES(21,1384299400);
-INSERT INTO "autofill_dates" VALUES(21,1384299403);
-INSERT INTO "autofill_dates" VALUES(21,1384299402);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_22.sql b/components/test/data/web_database/version_22.sql
deleted file mode 100644
index c7cc8b5..0000000
--- a/components/test/data/web_database/version_22.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','22');
-INSERT INTO "meta" VALUES('last_compatible_version','21');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','27');
-INSERT INTO "meta" VALUES('Default Search Provider ID','7');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL, keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1);
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0);
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0);
-INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_22_corrupt.sql b/components/test/data/web_database/version_22_corrupt.sql
deleted file mode 100644
index 82d9b3f..0000000
--- a/components/test/data/web_database/version_22_corrupt.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','22');
-INSERT INTO "meta" VALUES('last_compatible_version','21');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1);
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0);
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0);
-INSERT INTO "keywords" VALUES(5,'Wikipedia (en)','en.wikipedia.org','','http://en.wikipedia.org/w/index.php?title=Special:Search&search={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(6,'NYTimes','query.nytimes.com','','http://query.nytimes.com/gst/handler.html?query={searchTerms}&opensearch=1',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(7,'eBay','rover.ebay.com','','http://rover.ebay.com/rover/1/711-43047-14818-1/4?satitle={searchTerms}',1,0,'',1283287335,0,'','',0,0);
-INSERT INTO "keywords" VALUES(8,'ff','ff','','http://ff{searchTerms}',0,0,'',1283287356,0,'','',0,0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL, ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL, date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL, scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB,date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR);
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR,card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_25.sql b/components/test/data/web_database/version_25.sql
deleted file mode 100644
index 986ca9f..0000000
--- a/components/test/data/web_database/version_25.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','25');
-INSERT INTO "meta" VALUES('last_compatible_version','25');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,username_element VARCHAR, username_value VARCHAR,password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR,unique_id INTEGER PRIMARY KEY, first_name VARCHAR,middle_name VARCHAR, last_name VARCHAR, email VARCHAR,company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,phone VARCHAR, fax VARCHAR);
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,expiration_month INTEGER, expiration_year INTEGER,verification_code VARCHAR, billing_address VARCHAR,shipping_address VARCHAR, card_number_encrypted BLOB,verification_code_encrypted BLOB);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_26.sql b/components/test/data/web_database/version_26.sql
deleted file mode 100644
index 5cf1a97..0000000
--- a/components/test/data/web_database/version_26.sql
+++ /dev/null
@@ -1,23 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','26');
-INSERT INTO "meta" VALUES('last_compatible_version','26');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR,username_element VARCHAR, username_value VARCHAR,password_element VARCHAR, password_value BLOB, submit_element VARCHAR,signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element,username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR,pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0,date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR,unique_id INTEGER PRIMARY KEY, first_name VARCHAR,middle_name VARCHAR, last_name VARCHAR, email VARCHAR,company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR,city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR,phone VARCHAR, fax VARCHAR);
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY,name_on_card VARCHAR, type VARCHAR, card_number VARCHAR,expiration_month INTEGER, expiration_year INTEGER,verification_code VARCHAR, billing_address VARCHAR,shipping_address VARCHAR, card_number_encrypted BLOB,verification_code_encrypted BLOB);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_27.sql b/components/test/data/web_database/version_27.sql
deleted file mode 100644
index 4733afa..0000000
--- a/components/test/data/web_database/version_27.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','27');
-INSERT INTO "meta" VALUES('last_compatible_version','27');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR);
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_29.sql b/components/test/data/web_database/version_29.sql
deleted file mode 100644
index ab03275..0000000
--- a/components/test/data/web_database/version_29.sql
+++ /dev/null
@@ -1,29 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','29');
-INSERT INTO "meta" VALUES('last_compatible_version','29');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','29');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0,'{google:baseURL}search?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&q={searchTerms}');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6262,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6239,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR);
-INSERT INTO "autofill_profiles" VALUES('Santa Claus, 1 Reindeer Lane',1,'Santa','','Claus','','','1 Reindeer Lane','P.O. Box 56009','North Pole','','H0H 0H0','CANADA','','');
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB);
-INSERT INTO "credit_cards" VALUES('',2,'Kris Kringle','','',12,2020,'','1','',X'',X'');
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_30.sql b/components/test/data/web_database/version_30.sql
deleted file mode 100644
index 698605c..0000000
--- a/components/test/data/web_database/version_30.sql
+++ /dev/null
@@ -1,31 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','30');
-INSERT INTO "meta" VALUES('last_compatible_version','30');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','30');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6245,0,'{google:baseURL}search?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&q={searchTerms}');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6262,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6239,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-INSERT INTO "autofill_profiles" VALUES('Jim Johnson, 789 4th Street',1,'Jim','','Johnson','jim@acme.com','Acme Inc.','789 4th Street','Apt. #4','San Francisco','CA','94102','USA','4155512255','4155512233',1287508123);
-INSERT INTO "autofill_profiles" VALUES('Billy Jean, 1 Ghost Blvd.',3,'Billy','','Jean','billy@thriller.com','Thriller Inc.','1 Ghost Blvd.','','Santa Monica','CA','98990','USA','4431110000','',1287508123);
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-INSERT INTO "credit_cards" VALUES('',2,'Jim X Johnson','','',1,2011,'','1','',X'763130B83A1BEE0CFD7C447C270685B5E2BFF5EC0BC700B38F4C4DD60CDD5D8D66EB09',X'',1287508123);
-INSERT INTO "credit_cards" VALUES('2',4,'Billy X Jean','','',7,2017,'','3','',X'763130EB3DC27FA61AAC9EAC92B303978DD7B62E901B4D9DFB459905E09AAAE7AE7BA1',X'',1287508123);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_31.sql b/components/test/data/web_database/version_31.sql
deleted file mode 100644
index bfa7443..0000000
--- a/components/test/data/web_database/version_31.sql
+++ /dev/null
@@ -1,29 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','31');
-INSERT INTO "meta" VALUES('last_compatible_version','31');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','32');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6247,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6264,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6241,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( label VARCHAR, unique_id INTEGER PRIMARY KEY, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, guid VARCHAR NOT NULL DEFAULT "");
-INSERT INTO "autofill_profiles" VALUES('Elvis Presley, 1122 PBJ Lane',1,'Elvis','','Presley','elvis@elvis.com','Hip Shake Inc.','1122 PBJ Lane','Suite 1','Memphis','TN','38116','UK','9013323322','',1288642516,'A4FF32F6-EF3F-379A-87F2-40A8811182A7');
-CREATE TABLE credit_cards ( label VARCHAR, unique_id INTEGER PRIMARY KEY, name_on_card VARCHAR, type VARCHAR, card_number VARCHAR, expiration_month INTEGER, expiration_year INTEGER, verification_code VARCHAR, billing_address VARCHAR, shipping_address VARCHAR, card_number_encrypted BLOB, verification_code_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, guid VARCHAR NOT NULL DEFAULT "");
-INSERT INTO "credit_cards" VALUES('',2,'Jim J Jones','','',1,2011,'','0','',X'7631309863E9F1F33C2BDBFBFC86708448BDD8B37A495B628C8459A60D0CCD1047E69F',X'',1288642516,'B77F749C-8B0E-44B2-D299-3C80A95E0ADD');
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_32.sql b/components/test/data/web_database/version_32.sql
deleted file mode 100644
index 7030608..0000000
--- a/components/test/data/web_database/version_32.sql
+++ /dev/null
@@ -1,33 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','32');
-INSERT INTO "meta" VALUES('last_compatible_version','32');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, label VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, email VARCHAR, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, phone VARCHAR, fax VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-INSERT INTO "autofill_profiles" VALUES('00580526-FF81-EE2A-0546-1AC593A32E2F','John Doe, 1 Main St','John','','Doe','john@doe.com','Doe Enterprises','1 Main St','Apt 1','Los Altos','CA','94022','USA','4151112222','4153334444',1297882100);
-INSERT INTO "autofill_profiles" VALUES('589636FD-9037-3053-200C-80ABC97D7344','John P. Doe, 1 Main St','John','P.','Doe','john@doe.com','Doe Enterprises','1 Main St','Apt 1','Los Altos','CA','94022','USA','4151112222','4153334444',1297882100);
-INSERT INTO "autofill_profiles" VALUES('4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396','Dave Smith, 2 Main Street','Dave','','Smith','','','2 Main Street','','Los Altos','CA','94022','USA','','',1297882100);
-INSERT INTO "autofill_profiles" VALUES('722DF5C4-F74A-294A-46F0-31FFDED0D635','Dave Smith, 2 Main St','Dave','','Smith','','','2 Main St','','Los Altos','CA','94022','USA','','',1297882100);
-INSERT INTO "autofill_profiles" VALUES('584282AC-5D21-8D73-A2DB-4F892EF61F3F','Alfred E Newman, a@e.com','Alfred','E','Newman','a@e.com','','','','','','','','','',1297882100);
-INSERT INTO "autofill_profiles" VALUES('9E5FE298-62C7-83DF-6293-381BC589183F','3 Main St, Los Altos','','','','','','3 Main St','','Los Altos','CA','94022','USA','','',1297882100);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, label VARCHAR, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX autofill_profiles_label_index ON autofill_profiles (label);
-CREATE INDEX credit_cards_label_index ON credit_cards (label);
-COMMIT;
diff --git a/components/test/data/web_database/version_33.sql b/components/test/data/web_database/version_33.sql
deleted file mode 100644
index a5eb2ae9..0000000
--- a/components/test/data/web_database/version_33.sql
+++ /dev/null
@@ -1,32 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','33');
-INSERT INTO "meta" VALUES('last_compatible_version','33');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-INSERT INTO "autofill_profiles" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','Hip Shake Inc.','1122 PBJ Lane','Suite 1','Memphis','TN','38116','United States',1298621949);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-INSERT INTO "autofill_profile_names" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','Elvis','','Presley');
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-INSERT INTO "autofill_profile_emails" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944','elvis@elvis.com');
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-INSERT INTO "autofill_profile_phones" VALUES('45285F35-4A04-5F47-DBCC-CA8C2F2A5944',0,'9013323322');
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_34.sql b/components/test/data/web_database/version_34.sql
deleted file mode 100644
index 8a29a95..0000000
--- a/components/test/data/web_database/version_34.sql
+++ /dev/null
@@ -1,54 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-INSERT INTO "meta" VALUES('version','34');
-INSERT INTO "meta" VALUES('last_compatible_version','34');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6256,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6273,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6250,0,'');
-INSERT INTO "keywords" VALUES(5,'Search the web (Babylon)','search.babylon.com','','http://search.babylon.com/web/{searchTerms}?babsrc=browsersearch',1,0,'',1299093361,0,'','',0,0,0,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-INSERT INTO "autofill" VALUES('firstname','David','david',1,1);
-INSERT INTO "autofill" VALUES('lastname','Holloway','holloway',2,1);
-INSERT INTO "autofill" VALUES('email','d@gmail.com','d@gmail.com',3,1);
-INSERT INTO "autofill" VALUES('phone','415-551-2222','415-551-2222',4,1);
-INSERT INTO "autofill" VALUES('fax','415-551-2222','415-551-2222',5,1);
-INSERT INTO "autofill" VALUES('address','1122 Boogie Boogie Avenue','1122 boogie boogie avenue',6,1);
-INSERT INTO "autofill" VALUES('city','San Francisco','san francisco',7,1);
-INSERT INTO "autofill" VALUES('zipcode','11001','11001',8,1);
-INSERT INTO "autofill" VALUES('country','UK','uk',9,1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-INSERT INTO "autofill_dates" VALUES(1,1299093389);
-INSERT INTO "autofill_dates" VALUES(2,1299093389);
-INSERT INTO "autofill_dates" VALUES(3,1299093389);
-INSERT INTO "autofill_dates" VALUES(4,1299093389);
-INSERT INTO "autofill_dates" VALUES(5,1299093389);
-INSERT INTO "autofill_dates" VALUES(6,1299093389);
-INSERT INTO "autofill_dates" VALUES(7,1299093389);
-INSERT INTO "autofill_dates" VALUES(8,1299093389);
-INSERT INTO "autofill_dates" VALUES(9,1299093389);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, country_code VARCHAR);
-INSERT INTO "autofill_profiles" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','','1122 Boogie Boogie Avenue','','San Francisco','?','11001','UK',1299093389,'UK');
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-INSERT INTO "autofill_profile_names" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','David','','Holloway');
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-INSERT INTO "autofill_profile_emails" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB','d@gmail.com');
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-INSERT INTO "autofill_profile_phones" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB',0,'4155512222');
-INSERT INTO "autofill_profile_phones" VALUES('F19484ED-363F-4506-997E-E0F23EA834AB',1,'4155512222');
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_35.sql b/components/test/data/web_database/version_35.sql
deleted file mode 100644
index 2c0738cb..0000000
--- a/components/test/data/web_database/version_35.sql
+++ /dev/null
@@ -1,59 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','35');
-INSERT INTO "meta" VALUES('last_compatible_version','35');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,1,'',0,0,'UTF-8','http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,6279,0,'');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,1,'',0,0,'UTF-8','http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,6256,0,'');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-
-/* A "John Doe" profile with all-valid fields. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000001','Acme Inc.','1 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704);
-INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000001','John','','Doe');
-INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000001','john@doe.com');
-INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000001',0,'4151112222');
-INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000001',1,'4151110000');
-
-/* A subset of "John Doe".  Should get discarded. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000002','','1 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704);
-INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000002','John','','Doe');
-INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000002','john@doe.com');
-INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000002',0,'4151112222');
-INSERT INTO "autofill_profile_phones" VALUES('00000000-0000-0000-0000-000000000002',1,'4151110000');
-
-/* A profile with incomplete address.  Should get discarded. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000003','','','Apt 3','San Francisco','CA','94102','United States','US',1300131704);
-INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000003','Jim','','Smith');
-
-/* A profile with bad email. Should get discarded. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000004','Acme Inc.','4 Main Street','Apt 2','San Francisco','CA','94102','United States','US',1300131704);
-INSERT INTO "autofill_profile_emails" VALUES('00000000-0000-0000-0000-000000000004','bademail');
-
-/* A profile with bad State (country == US).  Should get discarded. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000005','Acme Inc.','6 Main Street','Apt 2','San Francisco','BS','94102','United States','US',1300131704);
-INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000006','John','','Doe');
-
-/* A profile with bad zip (country == US).  Should get discarded. */
-INSERT INTO "autofill_profiles" VALUES('00000000-0000-0000-0000-000000000006','Acme Inc.','7 Main Street','Apt 2','San Francisco','CA','bogus','United States','US',1300131704);
-INSERT INTO "autofill_profile_names" VALUES('00000000-0000-0000-0000-000000000007','John','','Doe');
-
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_37.sql b/components/test/data/web_database/version_37.sql
deleted file mode 100644
index 045450c..0000000
--- a/components/test/data/web_database/version_37.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','37');
-INSERT INTO "meta" VALUES('last_compatible_version','37');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_38.sql b/components/test/data/web_database/version_38.sql
deleted file mode 100644
index 679ad987..0000000
--- a/components/test/data/web_database/version_38.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','38');
-INSERT INTO "meta" VALUES('last_compatible_version','38');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_39.sql b/components/test/data/web_database/version_39.sql
deleted file mode 100644
index d8f4c9f1..0000000
--- a/components/test/data/web_database/version_39.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','39');
-INSERT INTO "meta" VALUES('last_compatible_version','39');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
diff --git a/components/test/data/web_database/version_40.sql b/components/test/data/web_database/version_40.sql
deleted file mode 100644
index 5eee626..0000000
--- a/components/test/data/web_database/version_40.sql
+++ /dev/null
@@ -1,29 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','40');
-INSERT INTO "meta" VALUES('last_compatible_version','40');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
-
diff --git a/components/test/data/web_database/version_41.sql b/components/test/data/web_database/version_41.sql
deleted file mode 100644
index 4804d167..0000000
--- a/components/test/data/web_database/version_41.sql
+++ /dev/null
@@ -1,30 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','41');
-INSERT INTO "meta" VALUES('last_compatible_version','41');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
-
-
diff --git a/components/test/data/web_database/version_42.sql b/components/test/data/web_database/version_42.sql
deleted file mode 100644
index 01b99253..0000000
--- a/components/test/data/web_database/version_42.sql
+++ /dev/null
@@ -1,30 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','42');
-INSERT INTO "meta" VALUES('last_compatible_version','42');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Default Search Provider Backup','2Googlegoogle.comhttp://www.google.com/favicon.ico{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}100UTF-81{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}1162620{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=10{1234-5678-90AB-CDEF}');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','33');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,6262,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
-
diff --git a/components/test/data/web_database/version_43.sql b/components/test/data/web_database/version_43.sql
deleted file mode 100644
index e0bcd549..0000000
--- a/components/test/data/web_database/version_43.sql
+++ /dev/null
@@ -1,31 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','43');
-INSERT INTO "meta" VALUES('last_compatible_version','43');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','3');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','37');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,1234,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE keywords_backup (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0, sync_guid VARCHAR);
-INSERT INTO "keywords_backup" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}&q={searchTerms}',1,1,'',0,0,'UTF-8','{google:baseSuggestURL}search?client=chrome&hl={language}&q={searchTerms}',1,1,1234,0,'{google:baseURL}webhp?{google:RLZ}sourceid=chrome-instant&ie={inputEncoding}&ion=1{searchTerms}&nord=1',0,'{1234-5678-90AB-CDEF}');
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-COMMIT;
-
diff --git a/components/test/data/web_database/version_44.sql b/components/test/data/web_database/version_44.sql
deleted file mode 100644
index e36ffea8..0000000
--- a/components/test/data/web_database/version_44.sql
+++ /dev/null
@@ -1,53 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','44');
-INSERT INTO "meta" VALUES('last_compatible_version','44');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','0');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,show_in_default_list INTEGER,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,autogenerate_keyword INTEGER DEFAULT 0,logo_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR);
-CREATE TABLE keywords_backup(
-  id INT,
-  short_name TEXT,
-  keyword TEXT,
-  favicon_url TEXT,
-  url TEXT,
-  safe_for_autoreplace INT,
-  originating_url TEXT,
-  date_created INT,
-  usage_count INT,
-  input_encodings TEXT,
-  show_in_default_list INT,
-  suggest_url TEXT,
-  prepopulate_id INT,
-  autogenerate_keyword INT,
-  logo_id INT,
-  created_by_policy INT,
-  instant_url TEXT,
-  last_modified INT,
-  sync_guid TEXT
-);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE logins (origin_url VARCHAR NOT NULL, action_url VARCHAR, username_element VARCHAR, username_value VARCHAR, password_element VARCHAR, password_value BLOB, submit_element VARCHAR, signon_realm VARCHAR NOT NULL,ssl_valid INTEGER NOT NULL,preferred INTEGER NOT NULL,date_created INTEGER NOT NULL,blacklisted_by_user INTEGER NOT NULL,scheme INTEGER NOT NULL,UNIQUE (origin_url, username_element, username_value, password_element, submit_element, signon_realm));
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, password_value BLOB, date_created INTEGER NOT NULL,UNIQUE (url_hash));
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type));
-CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern));
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX logins_signon ON logins (signon_realm);
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
diff --git a/components/test/data/web_database/version_45.sql b/components/test/data/web_database/version_45.sql
deleted file mode 100644
index 4b1e70a..0000000
--- a/components/test/data/web_database/version_45.sql
+++ /dev/null
@@ -1,53 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('version','45');
-INSERT INTO "meta" VALUES('last_compatible_version','45');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','39');
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type));
-CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern));
-CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR);
-CREATE TABLE keywords_backup(
-  id INT,
-  short_name TEXT,
-  keyword TEXT,
-  favicon_url TEXT,
-  url TEXT,
-  safe_for_autoreplace INT,
-  originating_url TEXT,
-  date_created INT,
-  usage_count INT,
-  input_encodings TEXT,
-  show_in_default_list INT,
-  suggest_url TEXT,
-  prepopulate_id INT,
-  created_by_policy INT,
-  instant_url TEXT,
-  last_modified INT,
-  sync_guid TEXT
-);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
--- following statements are required for testing migration to version 46
-INSERT INTO web_intents VALUES ('http://poodles.com/fuzzer', 'fuzz', 'poodle/*', 'Poodle Fuzzer', 'window');
-INSERT INTO web_intents_defaults VALUES ('fuzz', 'poodle/*', '', 0, 0, 'http://poodles.com/fuzzer');
-COMMIT;
-
diff --git a/components/test/data/web_database/version_45_compatible.sql b/components/test/data/web_database/version_45_compatible.sql
deleted file mode 100644
index 158c40df..0000000
--- a/components/test/data/web_database/version_45_compatible.sql
+++ /dev/null
@@ -1,50 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('version','40');
-INSERT INTO "meta" VALUES('last_compatible_version','45');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','39');
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,UNIQUE (service_url, action, type));
-CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,UNIQUE (action, type, url_pattern));
-CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR);
-CREATE TABLE keywords_backup(
-  id INT,
-  short_name TEXT,
-  keyword TEXT,
-  favicon_url TEXT,
-  url TEXT,
-  safe_for_autoreplace INT,
-  originating_url TEXT,
-  date_created INT,
-  usage_count INT,
-  input_encodings TEXT,
-  show_in_default_list INT,
-  suggest_url TEXT,
-  prepopulate_id INT,
-  created_by_policy INT,
-  instant_url TEXT,
-  last_modified INT,
-  sync_guid TEXT
-);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
-
diff --git a/components/test/data/web_database/version_45_invalid.sql b/components/test/data/web_database/version_45_invalid.sql
deleted file mode 100644
index ff2b94b..0000000
--- a/components/test/data/web_database/version_45_invalid.sql
+++ /dev/null
@@ -1,50 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('version','45');
-INSERT INTO "meta" VALUES('last_compatible_version','45');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','39');
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents (INTEGER blabbity);
-CREATE TABLE web_intents_defaults (VARCHAR hammy);
-CREATE TABLE "keywords" (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR);
-CREATE TABLE keywords_backup(
-  id INT,
-  short_name TEXT,
-  keyword TEXT,
-  favicon_url TEXT,
-  url TEXT,
-  safe_for_autoreplace INT,
-  originating_url TEXT,
-  date_created INT,
-  usage_count INT,
-  input_encodings TEXT,
-  show_in_default_list INT,
-  suggest_url TEXT,
-  prepopulate_id INT,
-  created_by_policy INT,
-  instant_url TEXT,
-  last_modified INT,
-  sync_guid TEXT
-);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
--- following statements are required for testing migration to version 46
-INSERT INTO web_intents VALUES (11);
-INSERT INTO web_intents_defaults VALUES ('fuzz');
-COMMIT;
diff --git a/components/test/data/web_database/version_46.sql b/components/test/data/web_database/version_46.sql
deleted file mode 100644
index 8dcf7cb..0000000
--- a/components/test/data/web_database/version_46.sql
+++ /dev/null
@@ -1,31 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('Default Search Provider ID','0');
-INSERT INTO "meta" VALUES('version','46');
-INSERT INTO "meta" VALUES('last_compatible_version','46');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','0');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','39');
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents (service_url LONGVARCHAR,action VARCHAR,type VARCHAR,title LONGVARCHAR,disposition VARCHAR,scheme VARCHAR,UNIQUE (service_url, action, type));
-CREATE TABLE web_intents_defaults (action VARCHAR,type VARCHAR,url_pattern LONGVARCHAR,user_date INTEGER,suppression INTEGER,service_url LONGVARCHAR,scheme VARCHAR,UNIQUE (action, type, url_pattern));
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR);
-CREATE TABLE keywords_backup(id INT,short_name TEXT,keyword TEXT,favicon_url TEXT,url TEXT,safe_for_autoreplace INT,originating_url TEXT,date_created INT,usage_count INT,input_encodings TEXT,show_in_default_list INT,suggest_url TEXT,prepopulate_id INT,created_by_policy INT,instant_url TEXT,last_modified INT,sync_guid TEXT);
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
diff --git a/components/test/data/web_database/version_47.sql b/components/test/data/web_database/version_47.sql
deleted file mode 100644
index aae06e8..0000000
--- a/components/test/data/web_database/version_47.sql
+++ /dev/null
@@ -1,50 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','47');
-INSERT INTO "meta" VALUES('last_compatible_version','47');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','46');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup','2');
-INSERT INTO "meta" VALUES('Default Search Provider ID Backup Signature','');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR);
-CREATE TABLE keywords_backup(
-  id INT,
-  short_name TEXT,
-  keyword TEXT,
-  favicon_url TEXT,
-  url TEXT,
-  safe_for_autoreplace INT,
-  originating_url TEXT,
-  date_created INT,
-  usage_count INT,
-  input_encodings TEXT,
-  show_in_default_list INT,
-  suggest_url TEXT,
-  prepopulate_id INT,
-  created_by_policy INT,
-  instant_url TEXT,
-  last_modified INT,
-  sync_guid TEXT,
-  alternate_urls TEXT
-);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type));
-CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern));
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
diff --git a/components/test/data/web_database/version_48.sql b/components/test/data/web_database/version_48.sql
deleted file mode 100644
index 53a9ed7..0000000
--- a/components/test/data/web_database/version_48.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','48');
-INSERT INTO "meta" VALUES('last_compatible_version','48');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','48');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR);
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type));
-CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern));
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
diff --git a/components/test/data/web_database/version_49.sql b/components/test/data/web_database/version_49.sql
deleted file mode 100644
index 02a4fd9..0000000
--- a/components/test/data/web_database/version_49.sql
+++ /dev/null
@@ -1,31 +0,0 @@
-PRAGMA foreign_keys=OFF;
-BEGIN TRANSACTION;
-CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
-INSERT INTO "meta" VALUES('version','49');
-INSERT INTO "meta" VALUES('last_compatible_version','48');
-INSERT INTO "meta" VALUES('Builtin Keyword Version','54');
-INSERT INTO "meta" VALUES('Default Search Provider ID','2');
-CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, pair_id INTEGER PRIMARY KEY, count INTEGER DEFAULT 1);
-CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_dates ( pair_id INTEGER DEFAULT 0, date_created INTEGER DEFAULT 0);
-CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, address_line_1 VARCHAR, address_line_2 VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, country VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0);
-CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR);
-CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
-CREATE TABLE autofill_profile_phones ( guid VARCHAR, type INTEGER DEFAULT 0, number VARCHAR);
-CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
-CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR);
-INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client=chrome&q={searchTerms}&{google:cursorPosition}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:instantEnabledParameter}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'711AEC98-A563-FD8B-87D5-427C60828A43','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}"]','espv');
-INSERT INTO "keywords" VALUES(3,'Yahoo!','yahoo.com','http://search.yahoo.com/favicon.ico','http://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'http://ff.search.yahoo.com/gossip?output=fxjson&command={searchTerms}',2,0,'',0,'7A35F8C9-ADD7-2C08-475E-B51151C79514','[]','');
-INSERT INTO "keywords" VALUES(4,'Bing','bing.com','http://www.bing.com/s/wlflag.ico','http://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,'',0,0,'UTF-8',1,'http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,'',0,'94DA8067-BC2D-9033-0EDD-2F667874C223','[]','');
-CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
-CREATE TABLE web_app_icons (url LONGVARCHAR,width int,height int,image BLOB, UNIQUE (url, width, height));
-CREATE TABLE web_apps (url LONGVARCHAR UNIQUE,has_all_images INTEGER NOT NULL);
-CREATE TABLE web_intents ( service_url LONGVARCHAR, action VARCHAR, type VARCHAR, title LONGVARCHAR, disposition VARCHAR, scheme VARCHAR, UNIQUE (service_url, action, scheme, type));
-CREATE TABLE web_intents_defaults ( action VARCHAR, type VARCHAR, url_pattern LONGVARCHAR, user_date INTEGER, suppression INTEGER, service_url LONGVARCHAR, scheme VARCHAR, UNIQUE (action, scheme, type, url_pattern));
-CREATE INDEX autofill_name ON autofill (name);
-CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE INDEX autofill_dates_pair_id ON autofill_dates (pair_id);
-CREATE INDEX web_apps_url_index ON web_apps (url);
-CREATE INDEX web_intents_index ON web_intents (action);
-CREATE INDEX web_intents_default_index ON web_intents_defaults (action);
-COMMIT;
diff --git a/components/test/data/web_database/version_62.sql b/components/test/data/web_database/version_62.sql
new file mode 100644
index 0000000..e23ab8b
--- /dev/null
+++ b/components/test/data/web_database/version_62.sql
@@ -0,0 +1,26 @@
+PRAGMA foreign_keys=OFF;
+BEGIN TRANSACTION;
+CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
+INSERT INTO "meta" VALUES('version','60');
+INSERT INTO "meta" VALUES('last_compatible_version','59');
+INSERT INTO "meta" VALUES('Builtin Keyword Version','79');
+CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
+CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value));
+CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card VARCHAR, expiration_month INTEGER, expiration_year INTEGER, card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '');
+CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, company_name VARCHAR, street_address VARCHAR, dependent_locality VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code VARCHAR);
+CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name VARCHAR);
+CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR);
+CREATE TABLE autofill_profile_phones ( guid VARCHAR, number VARCHAR);
+CREATE TABLE autofill_profiles_trash ( guid VARCHAR);
+CREATE TABLE masked_credit_cards (id VARCHAR,status VARCHAR,name_on_card VARCHAR,type VARCHAR,last_four VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0);
+CREATE TABLE unmasked_credit_cards (id VARCHAR,card_number_encrypted VARCHAR);
+CREATE TABLE server_addresses (id VARCHAR,company_name VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code VARCHAR);
+CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,show_in_default_list INTEGER,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,instant_url VARCHAR,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,search_terms_replacement_key VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,instant_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR);
+INSERT INTO "keywords" VALUES(2,'Google','google.com','http://www.google.com/favicon.ico','{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:bookmarkBarPinned}{google:searchClient}{google:sourceId}{google:instantExtendedEnabledParameter}{google:omniboxStartMarginParameter}{google:contextualSearchVersion}ie={inputEncoding}',1,'',0,0,'UTF-8',1,'{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}',1,0,'{google:baseURL}webhp?sourceid=chrome-instant&{google:RLZ}{google:forceInstantResults}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}{google:omniboxStartMarginParameter}ie={inputEncoding}',0,'EAB7604D-85AD-455A-AA7F-3A1B68CDDA0C','["{google:baseURL}#q={searchTerms}","{google:baseURL}search#q={searchTerms}","{google:baseURL}webhp#q={searchTerms}","{google:baseURL}s?q={searchTerms}"]','espv','{google:baseURL}searchbyimage/upload','','','','encoded_image={google:imageThumbnail},image_url={google:imageURL},sbisrc={google:imageSearchSource},original_width={google:imageOriginalWidth},original_height={google:imageOriginalHeight}','{google:baseURL}_/chrome/newtab?{google:RLZ}{google:instantExtendedEnabledParameter}{google:ntpIsThemedParameter}ie={inputEncoding}');
+INSERT INTO "keywords" VALUES(3,'Bing','bing.com','https://www.bing.com/s/a/bing_p.ico','https://www.bing.com/search?setmkt=en-US&q={searchTerms}',1,'',0,0,'UTF-8',1,'http://api.bing.com/osjson.aspx?query={searchTerms}&language={language}',3,0,'',0,'865547E0-515C-482B-A202-F79CA3743BF8','[]','','','','','','','https://www.bing.com/chrome/newtab?setmkt=en-US');
+INSERT INTO "keywords" VALUES(4,'Yahoo!','yahoo.com','https://search.yahoo.com/favicon.ico','https://search.yahoo.com/search?ei={inputEncoding}&fr=crmas&p={searchTerms}',1,'',0,0,'UTF-8',1,'https://search.yahoo.com/sugg/chrome?output=fxjson&appid=crmas&command={searchTerms}',2,0,'',0,'9C8E4670-5993-46EF-8BEF-8012124C299D','[]','','','','','','','');
+INSERT INTO "keywords" VALUES(5,'AOL','aol.com','http://search.aol.com/favicon.ico','http://search.aol.com/aol/search?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://autocomplete.search.aol.com/autocomplete/get?output=json&it=&q={searchTerms}',35,0,'',0,'946DE8D0-0602-4C1A-BE0C-E44EDE8DCCA3','[]','','','','','','','');
+INSERT INTO "keywords" VALUES(6,'Ask','ask.com','http://sp.ask.com/sh/i/a16/favicon/favicon.ico','http://www.ask.com/web?q={searchTerms}',1,'',0,0,'UTF-8',1,'http://ss.ask.com/query?q={searchTerms}&li=ff',4,0,'',0,'F5C5564A-42A4-432B-A59E-2306689DF48B','[]','','','','','','','');
+CREATE INDEX autofill_name ON autofill (name);
+CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
+COMMIT;
diff --git a/components/web_modal/native_web_contents_modal_dialog.h b/components/web_modal/native_web_contents_modal_dialog.h
index 4bb956a..ef459b1e 100644
--- a/components/web_modal/native_web_contents_modal_dialog.h
+++ b/components/web_modal/native_web_contents_modal_dialog.h
@@ -11,21 +11,8 @@
 
 // TODO(gbillock): rename this file
 
-#if defined(OS_MACOSX)
-// Use a void* since none of the gfx::Native* types are suitable for
-// representing the web contents modal dialog under Cocoa.
-typedef void* NativeWebContentsModalDialog;
-#else
-typedef gfx::NativeView NativeWebContentsModalDialog;
-#endif
-
-#if defined(OS_MACOSX)
-// Use a void* since none of the gfx::Native* types are suitable for
-// representing a popup window under Cocoa.
-typedef void* NativePopup;
-#else
-typedef gfx::NativeView NativePopup;
-#endif
+using NativeWebContentsModalDialog = gfx::NativeWindow;
+using NativePopup = gfx::NativeWindow;
 
 }  // namespace web_modal
 
diff --git a/components/webdata/common/web_database.cc b/components/webdata/common/web_database.cc
index 018663da..675f7c5 100644
--- a/components/webdata/common/web_database.cc
+++ b/components/webdata/common/web_database.cc
@@ -14,7 +14,9 @@
 // corresponding changes must happen in the unit tests, and new migration test
 // added.  See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
 // static
-const int WebDatabase::kCurrentVersionNumber = 62;
+const int WebDatabase::kCurrentVersionNumber = 63;
+
+const int WebDatabase::kDeprecatedVersionNumber = 51;
 
 namespace {
 
@@ -87,7 +89,13 @@
   if (!db_.Open(db_name))
     return sql::INIT_FAILURE;
 
-  // Initialize various tables
+  // Clobber really old databases.
+  static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber,
+                "Deprecation version must be less than current");
+  sql::MetaTable::RazeIfDeprecated(&db_, kDeprecatedVersionNumber);
+
+  // Scope initialization in a transaction so we can't be partially
+  // initialized.
   sql::Transaction transaction(&db_);
   if (!transaction.Begin())
     return sql::INIT_FAILURE;
@@ -135,22 +143,7 @@
   if (current_version > meta_table_.GetVersionNumber())
     ChangeVersion(&meta_table_, current_version, false);
 
-  if (current_version < 20) {
-    // Versions 1 - 19 are unhandled.  Version numbers greater than
-    // kCurrentVersionNumber should have already been weeded out by the caller.
-    //
-    // When the version is too old, we return failure error code.  The schema
-    // is too out of date to migrate.
-    //
-    // There should not be a released product that makes a database too old to
-    // migrate. If we do encounter such a legacy database, we will need a
-    // better solution to handle it (i.e., pop up a dialog to tell the user,
-    // erase all their prefs and start over, etc.).
-    LOG(WARNING) << "Web database version " << current_version
-                 << " is too old to handle.";
-    NOTREACHED();
-    return sql::INIT_FAILURE;
-  }
+  DCHECK_GT(current_version, kDeprecatedVersionNumber);
 
   for (int next_version = current_version + 1;
        next_version <= kCurrentVersionNumber;
diff --git a/components/webdata/common/web_database.h b/components/webdata/common/web_database.h
index 22730fe..c6d0c1d5 100644
--- a/components/webdata/common/web_database.h
+++ b/components/webdata/common/web_database.h
@@ -27,6 +27,8 @@
   };
   // Exposed publicly so the keyword table can access it.
   static const int kCurrentVersionNumber;
+  // The newest version of the database Chrome will NOT try to migrate.
+  static const int kDeprecatedVersionNumber;
 
   WebDatabase();
   virtual ~WebDatabase();
diff --git a/components/webdata/common/web_database_migration_unittest.cc b/components/webdata/common/web_database_migration_unittest.cc
index fbba5cd..765883b 100644
--- a/components/webdata/common/web_database_migration_unittest.cc
+++ b/components/webdata/common/web_database_migration_unittest.cc
@@ -38,122 +38,6 @@
 
 namespace {
 
-void AutofillProfile31FromStatement(const sql::Statement& s,
-                                    AutofillProfile* profile,
-                                    base::string16* label,
-                                    int* unique_id,
-                                    int64* date_modified) {
-  DCHECK(profile);
-  DCHECK(label);
-  DCHECK(unique_id);
-  DCHECK(date_modified);
-  *label = s.ColumnString16(0);
-  *unique_id = s.ColumnInt(1);
-  profile->SetRawInfo(autofill::NAME_FIRST, s.ColumnString16(2));
-  profile->SetRawInfo(autofill::NAME_MIDDLE, s.ColumnString16(3));
-  profile->SetRawInfo(autofill::NAME_LAST, s.ColumnString16(4));
-  profile->SetRawInfo(autofill::EMAIL_ADDRESS, s.ColumnString16(5));
-  profile->SetRawInfo(autofill::COMPANY_NAME, s.ColumnString16(6));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_LINE1, s.ColumnString16(7));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_LINE2, s.ColumnString16(8));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_CITY, s.ColumnString16(9));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_STATE, s.ColumnString16(10));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_ZIP, s.ColumnString16(11));
-  profile->SetInfo(
-      autofill::AutofillType(autofill::ADDRESS_HOME_COUNTRY),
-      s.ColumnString16(12), "en-US");
-  profile->SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(13));
-  *date_modified = s.ColumnInt64(15);
-  profile->set_guid(s.ColumnString(16));
-  EXPECT_TRUE(base::IsValidGUID(profile->guid()));
-}
-
-void AutofillProfile33FromStatement(const sql::Statement& s,
-                                    AutofillProfile* profile,
-                                    int64* date_modified) {
-  DCHECK(profile);
-  DCHECK(date_modified);
-  profile->set_guid(s.ColumnString(0));
-  EXPECT_TRUE(base::IsValidGUID(profile->guid()));
-  profile->SetRawInfo(autofill::COMPANY_NAME, s.ColumnString16(1));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_STREET_ADDRESS,
-                      s.ColumnString16(2));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_CITY, s.ColumnString16(3));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_STATE, s.ColumnString16(4));
-  profile->SetRawInfo(autofill::ADDRESS_HOME_ZIP, s.ColumnString16(5));
-  profile->SetInfo(
-      autofill::AutofillType(autofill::ADDRESS_HOME_COUNTRY),
-      s.ColumnString16(6), "en-US");
-  *date_modified = s.ColumnInt64(7);
-}
-
-void CreditCard31FromStatement(const sql::Statement& s,
-                              CreditCard* credit_card,
-                              base::string16* label,
-                              int* unique_id,
-                              std::string* encrypted_number,
-                              int64* date_modified) {
-  DCHECK(credit_card);
-  DCHECK(label);
-  DCHECK(unique_id);
-  DCHECK(encrypted_number);
-  DCHECK(date_modified);
-  *label = s.ColumnString16(0);
-  *unique_id = s.ColumnInt(1);
-  credit_card->SetRawInfo(autofill::CREDIT_CARD_NAME, s.ColumnString16(2));
-  credit_card->SetRawInfo(autofill::CREDIT_CARD_TYPE, s.ColumnString16(3));
-  credit_card->SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, s.ColumnString16(5));
-  credit_card->SetRawInfo(
-      autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(6));
-  int encrypted_number_len = s.ColumnByteLength(10);
-  if (encrypted_number_len) {
-    encrypted_number->resize(encrypted_number_len);
-    memcpy(&(*encrypted_number)[0], s.ColumnBlob(10), encrypted_number_len);
-  }
-  *date_modified = s.ColumnInt64(12);
-  credit_card->set_guid(s.ColumnString(13));
-  EXPECT_TRUE(base::IsValidGUID(credit_card->guid()));
-}
-
-void CreditCard32FromStatement(const sql::Statement& s,
-                               CreditCard* credit_card,
-                               std::string* encrypted_number,
-                               int64* date_modified) {
-  DCHECK(credit_card);
-  DCHECK(encrypted_number);
-  DCHECK(date_modified);
-  credit_card->set_guid(s.ColumnString(0));
-  EXPECT_TRUE(base::IsValidGUID(credit_card->guid()));
-  credit_card->SetRawInfo(autofill::CREDIT_CARD_NAME, s.ColumnString16(1));
-  credit_card->SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH, s.ColumnString16(2));
-  credit_card->SetRawInfo(
-      autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(3));
-  int encrypted_number_len = s.ColumnByteLength(4);
-  if (encrypted_number_len) {
-    encrypted_number->resize(encrypted_number_len);
-    memcpy(&(*encrypted_number)[0], s.ColumnBlob(4), encrypted_number_len);
-  }
-  *date_modified = s.ColumnInt64(5);
-}
-
-void CheckHasBackupData(sql::MetaTable* meta_table) {
-  std::string value;
-  EXPECT_TRUE(meta_table->GetValue(
-      "Default Search Provider ID Backup", &value));
-  EXPECT_TRUE(meta_table->GetValue(
-      "Default Search Provider ID Backup Signature", &value));
-}
-
-void CheckNoBackupData(const sql::Connection& connection,
-                       sql::MetaTable* meta_table) {
-  std::string value;
-  EXPECT_FALSE(meta_table->GetValue(
-      "Default Search Provider ID Backup", &value));
-  EXPECT_FALSE(meta_table->GetValue(
-      "Default Search Provider ID Backup Signature", &value));
-  EXPECT_FALSE(connection.DoesTableExist("keywords_backup"));
-}
-
 std::string RemoveQuotes(const std::string& has_quotes) {
   std::string no_quotes;
   // SQLite quotes: http://www.sqlite.org/lang_keywords.html
@@ -248,7 +132,7 @@
   DISALLOW_COPY_AND_ASSIGN(WebDatabaseMigrationTest);
 };
 
-const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 62;
+const int WebDatabaseMigrationTest::kCurrentTestedVersionNumber = 63;
 
 void WebDatabaseMigrationTest::LoadDatabase(
     const base::FilePath::StringType& file) {
@@ -267,15 +151,23 @@
   sql::Connection connection;
   ASSERT_TRUE(connection.Open(GetDatabasePath()));
   const std::string& expected_schema = RemoveQuotes(connection.GetSchema());
-  static const int kFirstVersion = 53;
-  for (int i = kFirstVersion; i < kCurrentTestedVersionNumber; ++i) {
+  for (int i = WebDatabase::kDeprecatedVersionNumber + 1;
+       i < kCurrentTestedVersionNumber; ++i) {
+    // We don't test version 52 because there's a slight discrepancy in the
+    // initialization code and the migration code (relating to schema
+    // formatting). Fixing the bug is possible, but would require updating every
+    // version_nn.sql file.
+    if (i == 52)
+      continue;
+
     connection.Raze();
     const base::FilePath& file_name = base::FilePath::FromUTF8Unsafe(
         "version_" + base::IntToString(i) + ".sql");
     ASSERT_NO_FATAL_FAILURE(LoadDatabase(file_name.value()))
         << "Failed to load " << file_name.MaybeAsASCII();
     DoMigration();
-    EXPECT_EQ(expected_schema, RemoveQuotes(connection.GetSchema()));
+    EXPECT_EQ(expected_schema, RemoveQuotes(connection.GetSchema()))
+        << "For version " << i;
   }
 }
 
@@ -314,1851 +206,8 @@
   }
 }
 
-// Tests that absent Autofill tables do not create any problems when migrating
-// from a DB written by the earliest publicly released version of Chrome.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion20ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_20.sql")));
-
-  // Verify pre-conditions.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_FALSE(connection.DoesTableExist("autofill"));
-    EXPECT_FALSE(connection.DoesTableExist("autofill_profiles"));
-    EXPECT_FALSE(connection.DoesTableExist("credit_cards"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Mostly this test just verifies that no SQL errors occur during migration;
-    // but might as well verify that the tables were created as well.
-    EXPECT_TRUE(connection.DoesTableExist("autofill"));
-    EXPECT_TRUE(connection.DoesTableExist("autofill_profiles"));
-    EXPECT_TRUE(connection.DoesTableExist("credit_cards"));
-  }
-}
-
-// Tests that rows with empty values get removed from the autofill tables.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion21ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_21.sql")));
-
-  // Verify pre-conditions.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Both empty and non-empty values are allowed in a version 21 database.
-    sql::Statement s_autofill(connection.GetUniqueStatement(
-        "SELECT name, value, value_lower, pair_id, count FROM autofill"));
-    sql::Statement s_dates(connection.GetUniqueStatement(
-        "SELECT pair_id, date_created FROM autofill_dates"));
-
-    // An entry with a non-empty value.
-    ASSERT_TRUE(s_autofill.Step());
-    EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
-    EXPECT_EQ(ASCIIToUTF16("John Doe"), s_autofill.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("john doe"), s_autofill.ColumnString16(2));
-    EXPECT_EQ(10, s_autofill.ColumnInt(3));
-    EXPECT_EQ(1, s_autofill.ColumnInt(4));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(10, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299100, s_dates.ColumnInt64(1));
-
-    // An entry with an empty value.
-    ASSERT_TRUE(s_autofill.Step());
-    EXPECT_EQ(ASCIIToUTF16("Name"), s_autofill.ColumnString16(0));
-    EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2));
-    EXPECT_EQ(11, s_autofill.ColumnInt(3));
-    EXPECT_EQ(1, s_autofill.ColumnInt(4));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(11, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299200, s_dates.ColumnInt64(1));
-
-    // Another entry with a non-empty value.
-    ASSERT_TRUE(s_autofill.Step());
-    EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
-    EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s_autofill.ColumnString16(2));
-    EXPECT_EQ(20, s_autofill.ColumnInt(3));
-    EXPECT_EQ(3, s_autofill.ColumnInt(4));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(20, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299300, s_dates.ColumnInt64(1));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(20, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299301, s_dates.ColumnInt64(1));
-
-    // Another entry with an empty value.
-    ASSERT_TRUE(s_autofill.Step());
-    EXPECT_EQ(ASCIIToUTF16("Email"), s_autofill.ColumnString16(0));
-    EXPECT_EQ(base::string16(), s_autofill.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s_autofill.ColumnString16(2));
-    EXPECT_EQ(21, s_autofill.ColumnInt(3));
-    EXPECT_EQ(4, s_autofill.ColumnInt(4));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(21, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299401, s_dates.ColumnInt64(1));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(21, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299400, s_dates.ColumnInt64(1));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(21, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299403, s_dates.ColumnInt64(1));
-    ASSERT_TRUE(s_dates.Step());
-    EXPECT_EQ(21, s_dates.ColumnInt(0));
-    EXPECT_EQ(1384299402, s_dates.ColumnInt64(1));
-
-    // No more entries expected.
-    ASSERT_FALSE(s_autofill.Step());
-    ASSERT_FALSE(s_dates.Step());
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Entries with empty values should have been dropped.  The remaining
-    // entries should have been preserved.
-    sql::Statement s(
-        connection.GetUniqueStatement(
-            "SELECT name, value, value_lower, date_created, date_last_used,"
-            " count "
-            "FROM autofill "
-            "ORDER BY name, value ASC"));
-
-    // "jane@example.com"
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ(ASCIIToUTF16("Email"), s.ColumnString16(0));
-    EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("jane@example.com"), s.ColumnString16(2));
-    EXPECT_EQ(1384299300, s.ColumnInt64(3));
-    EXPECT_EQ(1384299301, s.ColumnInt64(4));
-    EXPECT_EQ(3, s.ColumnInt(5));
-
-    // "John Doe"
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ(ASCIIToUTF16("Name"), s.ColumnString16(0));
-    EXPECT_EQ(ASCIIToUTF16("John Doe"), s.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("john doe"), s.ColumnString16(2));
-    EXPECT_EQ(1384299100, s.ColumnInt64(3));
-    EXPECT_EQ(1384299100, s.ColumnInt64(4));
-    EXPECT_EQ(1, s.ColumnInt(5));
-
-    // No more entries expected.
-    ASSERT_FALSE(s.Step());
-  }
-}
-
-// Tests that the |credit_card| table gets added to the schema for a version 22
-// database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion22ToCurrent) {
-  // This schema is taken from a build prior to the addition of the
-  // |credit_card| table.  Version 22 of the schema.  Contrast this with the
-  // corrupt version below.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_22.sql")));
-
-  // Verify pre-conditions.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // No |credit_card| table prior to version 23.
-    ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
-    ASSERT_FALSE(
-        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // |credit_card| table now exists.
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
-    EXPECT_TRUE(
-        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
-  }
-}
-
-// Tests that the |credit_card| table gets added to the schema for a corrupt
-// version 22 database.  The corruption is that the |credit_cards| table exists
-// but the schema version number was not set correctly to 23 or later.  This
-// test exercises code introduced to fix bug http://crbug.com/50699 that
-// resulted from the corruption.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion22CorruptedToCurrent) {
-  // This schema is taken from a build after the addition of the |credit_card|
-  // table.  Due to a bug in the migration logic the version is set incorrectly
-  // to 22 (it should have been updated to 23 at least).
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_22_corrupt.sql")));
-
-  // Verify pre-conditions.  These are expectations for corrupt version 22 of
-  // the database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Columns existing and not existing before current version.
-    ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
-    ASSERT_TRUE(
-        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
-    ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-
-    // Columns existing and not existing before version 25.
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
-    EXPECT_TRUE(
-        connection.DoesColumnExist("credit_cards", "card_number_encrypted"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
-  }
-}
-
-// Tests that the |keywords| |created_by_policy| column gets added to the schema
-// for a version 25 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion25ToCurrent) {
-  // This schema is taken from a build prior to the addition of the |keywords|
-  // |created_by_policy| column.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_25.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 25 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // |keywords| |created_by_policy| column should have been added.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
-  }
-}
-
-// Tests that the credit_cards.billing_address column is changed from a string
-// to an int whilst preserving the associated billing address. This version of
-// the test makes sure a stored label is converted to an ID.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringLabels) {
-  // This schema is taken from a build prior to the change of column type for
-  // credit_cards.billing_address from string to int.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_26.sql")));
-
-  // Verify pre-conditions. These are expectations for version 26 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Columns existing and not existing before current version.
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
-
-    std::string stmt = "INSERT INTO autofill_profiles"
-      "(label, unique_id, first_name, middle_name, last_name, email,"
-      " company_name, address_line_1, address_line_2, city, state, zipcode,"
-      " country, phone, fax)"
-      "VALUES ('Home',1,'','','','','','','','','','','','','')";
-    sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
-    ASSERT_TRUE(s.Run());
-
-    // Insert a CC linked to an existing address.
-    std::string stmt2 = "INSERT INTO credit_cards"
-      "(label, unique_id, name_on_card, type, card_number,"
-      " expiration_month, expiration_year, verification_code, billing_address,"
-      " shipping_address, card_number_encrypted, verification_code_encrypted)"
-      "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','Home','','','')";
-    sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
-    ASSERT_TRUE(s2.Run());
-
-    // |billing_address| is a string.
-    std::string stmt3 = "SELECT billing_address FROM credit_cards";
-    sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
-
-    // Verify the credit card data is converted.
-    sql::Statement s(connection.GetUniqueStatement(
-        "SELECT guid, name_on_card, expiration_month, expiration_year, "
-        "card_number_encrypted, date_modified "
-        "FROM credit_cards"));
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ("Jack", s.ColumnString(1));
-    EXPECT_EQ(2, s.ColumnInt(2));
-    EXPECT_EQ(2012, s.ColumnInt(3));
-    // Column 5 is encrypted number blob.
-    // Column 6 is date_modified.
-  }
-}
-
-// Tests that the credit_cards.billing_address column is changed from a string
-// to an int whilst preserving the associated billing address. This version of
-// the test makes sure a stored string ID is converted to an integer ID.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion26ToCurrentStringIDs) {
-  // This schema is taken from a build prior to the change of column type for
-  // credit_cards.billing_address from string to int.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_26.sql")));
-
-  // Verify pre-conditions. These are expectations for version 26 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
-
-    std::string stmt = "INSERT INTO autofill_profiles"
-      "(label, unique_id, first_name, middle_name, last_name, email,"
-      " company_name, address_line_1, address_line_2, city, state, zipcode,"
-      " country, phone, fax)"
-      "VALUES ('Home',1,'','','','','','','','','','','','','')";
-    sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
-    ASSERT_TRUE(s.Run());
-
-    // Insert a CC linked to an existing address.
-    std::string stmt2 = "INSERT INTO credit_cards"
-      "(label, unique_id, name_on_card, type, card_number,"
-      " expiration_month, expiration_year, verification_code, billing_address,"
-      " shipping_address, card_number_encrypted, verification_code_encrypted)"
-      "VALUES ('label',2,'Jack','Visa','1234',2,2012,'','1','','','')";
-    sql::Statement s2(connection.GetUniqueStatement(stmt2.c_str()));
-    ASSERT_TRUE(s2.Run());
-
-    // |billing_address| is a string.
-    std::string stmt3 = "SELECT billing_address FROM credit_cards";
-    sql::Statement s3(connection.GetUniqueStatement(stmt3.c_str()));
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ(s3.ColumnType(0), sql::COLUMN_TYPE_TEXT);
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // |keywords| |created_by_policy| column should have been added.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "created_by_policy"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
-
-    // Verify the credit card data is converted.
-    sql::Statement s(connection.GetUniqueStatement(
-        "SELECT guid, name_on_card, expiration_month, expiration_year, "
-        "card_number_encrypted, date_modified "
-        "FROM credit_cards"));
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ("Jack", s.ColumnString(1));
-    EXPECT_EQ(2, s.ColumnInt(2));
-    EXPECT_EQ(2012, s.ColumnInt(3));
-    // Column 5 is encrypted credit card number blo b.
-    // Column 6 is date_modified.
-  }
-}
-
-// Makes sure instant_url is added correctly to keywords.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion27ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_27.sql")));
-
-  // Verify pre-conditions. These are expectations for version 27 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    ASSERT_FALSE(connection.DoesColumnExist("keywords", "instant_url"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Make sure supports_instant (added in Version 28) was ultimately dropped
-    // again and instant_url was added.
-    EXPECT_FALSE(connection.DoesColumnExist("keywords", "supports_instant"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "instant_url"));
-
-    // Check that instant_url is empty.
-    std::string stmt = "SELECT instant_url FROM keywords";
-    sql::Statement s(connection.GetUniqueStatement(stmt.c_str()));
-    ASSERT_TRUE(s.Step());
-    EXPECT_EQ(std::string(), s.ColumnString(0));
-
-    // Verify the data made it over.
-    stmt = "SELECT " + KeywordTable::GetKeywordColumns() + " FROM keywords";
-    sql::Statement s2(connection.GetUniqueStatement(stmt.c_str()));
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ(2, s2.ColumnInt(0));
-    EXPECT_EQ("Google", s2.ColumnString(1));
-    EXPECT_EQ("google.com", s2.ColumnString(2));
-    EXPECT_EQ("http://www.google.com/favicon.ico", s2.ColumnString(3));
-    EXPECT_EQ("{google:baseURL}search?{google:RLZ}{google:acceptedSuggestion}"\
-        "{google:originalQueryForSuggestion}sourceid=chrome&ie={inputEncoding}"\
-        "&q={searchTerms}",
-        s2.ColumnString(4));
-    EXPECT_TRUE(s2.ColumnBool(5));
-    EXPECT_EQ(std::string(), s2.ColumnString(6));
-    EXPECT_EQ(0, s2.ColumnInt(7));
-    EXPECT_EQ(0, s2.ColumnInt(8));
-    EXPECT_EQ(std::string("UTF-8"), s2.ColumnString(9));
-    EXPECT_TRUE(s2.ColumnBool(10));
-    EXPECT_EQ(std::string("{google:baseSuggestURL}search?client=chrome&hl="
-                          "{language}&q={searchTerms}"), s2.ColumnString(11));
-    EXPECT_EQ(1, s2.ColumnInt(12));
-    EXPECT_FALSE(s2.ColumnBool(13));
-    EXPECT_EQ(std::string(), s2.ColumnString(14));
-    EXPECT_EQ(0, s2.ColumnInt(15));
-    EXPECT_EQ(std::string(), s2.ColumnString(16));
-  }
-}
-
-// Makes sure date_modified is added correctly to autofill_profiles and
-// credit_cards.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion29ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_29.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 29 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
-                                            "date_modified"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
-                                            "date_modified"));
-  }
-
-  Time pre_creation_time = Time::Now();
-  DoMigration();
-  Time post_creation_time = Time::Now();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Check that the columns were created.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "date_modified"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
-                                           "date_modified"));
-
-    sql::Statement s_profiles(connection.GetUniqueStatement(
-        "SELECT date_modified FROM autofill_profiles "));
-    ASSERT_TRUE(s_profiles.is_valid());
-    while (s_profiles.Step()) {
-      EXPECT_GE(s_profiles.ColumnInt64(0),
-                pre_creation_time.ToTimeT());
-      EXPECT_LE(s_profiles.ColumnInt64(0),
-                post_creation_time.ToTimeT());
-    }
-    EXPECT_TRUE(s_profiles.Succeeded());
-
-    sql::Statement s_credit_cards(connection.GetUniqueStatement(
-        "SELECT date_modified FROM credit_cards "));
-    ASSERT_TRUE(s_credit_cards.is_valid());
-    while (s_credit_cards.Step()) {
-      EXPECT_GE(s_credit_cards.ColumnInt64(0),
-                pre_creation_time.ToTimeT());
-      EXPECT_LE(s_credit_cards.ColumnInt64(0),
-                post_creation_time.ToTimeT());
-    }
-    EXPECT_TRUE(s_credit_cards.Succeeded());
-  }
-}
-
-// Makes sure guids are added to autofill_profiles and credit_cards tables.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion30ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_30.sql")));
-
-  // Verify pre-conditions. These are expectations for version 29 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "guid"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    ASSERT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
-
-    // Check that guids are non-null, non-empty, conforms to guid format, and
-    // are different.
-    sql::Statement s(
-        connection.GetUniqueStatement("SELECT guid FROM autofill_profiles"));
-
-    ASSERT_TRUE(s.Step());
-    std::string guid1 = s.ColumnString(0);
-    EXPECT_TRUE(base::IsValidGUID(guid1));
-
-    ASSERT_TRUE(s.Step());
-    std::string guid2 = s.ColumnString(0);
-    EXPECT_TRUE(base::IsValidGUID(guid2));
-
-    EXPECT_NE(guid1, guid2);
-  }
-}
-
-// Removes unique IDs and make GUIDs the primary key.  Also removes unused
-// columns.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion31ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_31.sql")));
-
-  // Verify pre-conditions. These are expectations for version 30 of the
-  // database.
-  AutofillProfile profile;
-  base::string16 profile_label;
-  int profile_unique_id = 0;
-  int64 profile_date_modified = 0;
-  CreditCard credit_card;
-  base::string16 cc_label;
-  int cc_unique_id = 0;
-  std::string cc_number_encrypted;
-  int64 cc_date_modified = 0;
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Verify existence of columns we'll be changing.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "unique_id"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "type"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "card_number"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
-                                           "verification_code"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "billing_address"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "shipping_address"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards",
-                                           "verification_code_encrypted"));
-
-    // Fetch data in the database prior to migration.
-    sql::Statement s1(
-        connection.GetUniqueStatement(
-            "SELECT label, unique_id, first_name, middle_name, last_name, "
-            "email, company_name, address_line_1, address_line_2, city, state, "
-            "zipcode, country, phone, fax, date_modified, guid "
-            "FROM autofill_profiles"));
-    ASSERT_TRUE(s1.Step());
-    EXPECT_NO_FATAL_FAILURE(AutofillProfile31FromStatement(
-        s1, &profile, &profile_label, &profile_unique_id,
-        &profile_date_modified));
-
-    sql::Statement s2(
-        connection.GetUniqueStatement(
-            "SELECT label, unique_id, name_on_card, type, card_number, "
-            "expiration_month, expiration_year, verification_code, "
-            "billing_address, shipping_address, card_number_encrypted, "
-            "verification_code_encrypted, date_modified, guid "
-            "FROM credit_cards"));
-    ASSERT_TRUE(s2.Step());
-    EXPECT_NO_FATAL_FAILURE(CreditCard31FromStatement(s2,
-                                                      &credit_card,
-                                                      &cc_label,
-                                                      &cc_unique_id,
-                                                      &cc_number_encrypted,
-                                                      &cc_date_modified));
-
-    EXPECT_NE(profile_unique_id, cc_unique_id);
-    EXPECT_NE(profile.guid(), credit_card.guid());
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Verify existence of columns we'll be changing.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "unique_id"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "guid"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "unique_id"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "type"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "card_number"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
-                                            "verification_code"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "billing_address"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
-                                            "shipping_address"));
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards",
-                                            "verification_code_encrypted"));
-
-    // Verify data in the database after the migration.
-    sql::Statement s1(
-        connection.GetUniqueStatement(
-            "SELECT guid, company_name, street_address, city, state, zipcode,"
-            " country_code, date_modified "
-            "FROM autofill_profiles"));
-    ASSERT_TRUE(s1.Step());
-
-    AutofillProfile profile_a;
-    int64 profile_date_modified_a = 0;
-    EXPECT_NO_FATAL_FAILURE(AutofillProfile33FromStatement(
-        s1, &profile_a, &profile_date_modified_a));
-    EXPECT_EQ(profile.guid(), profile_a.guid());
-    EXPECT_EQ(profile.GetRawInfo(autofill::COMPANY_NAME),
-              profile_a.GetRawInfo(autofill::COMPANY_NAME));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_LINE1),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_LINE1));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_LINE2),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_LINE2));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_CITY),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_CITY));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_STATE),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_STATE));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_ZIP),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_ZIP));
-    EXPECT_EQ(profile.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY),
-              profile_a.GetRawInfo(autofill::ADDRESS_HOME_COUNTRY));
-    EXPECT_EQ(profile_date_modified, profile_date_modified_a);
-
-    sql::Statement s2(
-        connection.GetUniqueStatement(
-            "SELECT guid, name_on_card, expiration_month, "
-            "expiration_year, card_number_encrypted, date_modified "
-            "FROM credit_cards"));
-    ASSERT_TRUE(s2.Step());
-
-    CreditCard credit_card_a;
-    base::string16 cc_label_a;
-    std::string cc_number_encrypted_a;
-    int64 cc_date_modified_a = 0;
-    EXPECT_NO_FATAL_FAILURE(CreditCard32FromStatement(s2,
-                                                      &credit_card_a,
-                                                      &cc_number_encrypted_a,
-                                                      &cc_date_modified_a));
-    EXPECT_EQ(credit_card, credit_card_a);
-    EXPECT_EQ(cc_label, cc_label_a);
-    EXPECT_EQ(cc_number_encrypted, cc_number_encrypted_a);
-    EXPECT_EQ(cc_date_modified, cc_date_modified_a);
-  }
-}
-
-// Factor |autofill_profiles| address information separately from name, email,
-// and phone.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion32ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_32.sql")));
-
-  // Verify pre-conditions. These are expectations for version 32 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Verify existence of columns we'll be changing.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "label"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "first_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "middle_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "last_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "email"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "company_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "address_line_1"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "address_line_2"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "country"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "phone"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "fax"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "date_modified"));
-
-    EXPECT_FALSE(connection.DoesTableExist("autofill_profile_names"));
-    EXPECT_FALSE(connection.DoesTableExist("autofill_profile_emails"));
-    EXPECT_FALSE(connection.DoesTableExist("autofill_profile_phones"));
-
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "label"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // Verify changes to columns.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "label"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "first_name"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
-                                            "middle_name"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "last_name"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "email"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "company_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "street_address"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "city"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "state"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "zipcode"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "country_code"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "phone"));
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles", "fax"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "date_modified"));
-
-    // New "names" table.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
-                                           "first_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
-                                           "middle_name"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_names",
-                                           "last_name"));
-
-    // New "emails" table.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_emails", "email"));
-
-    // New "phones" table.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones", "guid"));
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profile_phones",
-                                           "number"));
-
-    EXPECT_FALSE(connection.DoesColumnExist("credit_cards", "label"));
-
-    // Verify data in the database after the migration.
-    sql::Statement s1(
-        connection.GetUniqueStatement(
-            "SELECT guid, company_name, street_address, city, state, zipcode, "
-            " country_code, date_modified "
-            "FROM autofill_profiles"));
-
-    // John Doe.
-    ASSERT_TRUE(s1.Step());
-    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s1.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("Doe Enterprises"), s1.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("1 Main St\n"
-                           "Apt 1"),
-              s1.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3));
-    EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4));
-    EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5));
-    EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6));
-    EXPECT_EQ(1297882100L, s1.ColumnInt64(7));
-
-    // John P. Doe.
-    // Gets merged during migration from 35 to 37 due to multi-valued fields.
-
-    // Dave Smith.
-    ASSERT_TRUE(s1.Step());
-    EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s1.ColumnString(0));
-    EXPECT_EQ(base::string16(), s1.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("2 Main Street"), s1.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3));
-    EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4));
-    EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5));
-    EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6));
-    EXPECT_EQ(1297882100L, s1.ColumnInt64(7));
-
-    // Dave Smith (Part 2).
-    ASSERT_TRUE(s1.Step());
-    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s1.ColumnString(0));
-    EXPECT_EQ(base::string16(), s1.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("2 Main St"), s1.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3));
-    EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4));
-    EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5));
-    EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6));
-    EXPECT_EQ(1297882100L, s1.ColumnInt64(7));
-
-    // Alfred E Newman.
-    // Gets culled during migration from 35 to 36 due to incomplete address.
-
-    // 3 Main St.
-    ASSERT_TRUE(s1.Step());
-    EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s1.ColumnString(0));
-    EXPECT_EQ(base::string16(), s1.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("3 Main St"), s1.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Los Altos"), s1.ColumnString16(3));
-    EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4));
-    EXPECT_EQ(ASCIIToUTF16("94022"), s1.ColumnString16(5));
-    EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6));
-    EXPECT_EQ(1297882100L, s1.ColumnInt64(7));
-
-    // That should be all.
-    EXPECT_FALSE(s1.Step());
-
-    sql::Statement s2(
-        connection.GetUniqueStatement(
-            "SELECT guid, first_name, middle_name, last_name "
-            "FROM autofill_profile_names"));
-
-    // John Doe.
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3));
-
-    // John P. Doe.  Note same guid as above due to merging of multi-valued
-    // fields.
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s2.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("John"), s2.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("P."), s2.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Doe"), s2.ColumnString16(3));
-
-    // Dave Smith.
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s2.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3));
-
-    // Dave Smith (Part 2).
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s2.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("Dave"), s2.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("Smith"), s2.ColumnString16(3));
-
-    // Alfred E Newman.
-    // Gets culled during migration from 35 to 36 due to incomplete address.
-
-    // 3 Main St.
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s2.ColumnString(0));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(1));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(2));
-    EXPECT_EQ(base::string16(), s2.ColumnString16(3));
-
-    // Should be all.
-    EXPECT_FALSE(s2.Step());
-
-    sql::Statement s3(
-        connection.GetUniqueStatement(
-            "SELECT guid, email "
-            "FROM autofill_profile_emails"));
-
-    // John Doe.
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s3.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("john@doe.com"), s3.ColumnString16(1));
-
-    // John P. Doe.
-    // Gets culled during migration from 35 to 37 due to merging of John Doe and
-    // John P. Doe addresses.
-
-    // 2 Main Street.
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s3.ColumnString(0));
-    EXPECT_EQ(base::string16(), s3.ColumnString16(1));
-
-    // 2 Main St.
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s3.ColumnString(0));
-    EXPECT_EQ(base::string16(), s3.ColumnString16(1));
-
-    // Alfred E Newman.
-    // Gets culled during migration from 35 to 36 due to incomplete address.
-
-    // 3 Main St.
-    ASSERT_TRUE(s3.Step());
-    EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s3.ColumnString(0));
-    EXPECT_EQ(base::string16(), s3.ColumnString16(1));
-
-    // Should be all.
-    EXPECT_FALSE(s3.Step());
-
-    sql::Statement s4(
-        connection.GetUniqueStatement(
-            "SELECT guid, number "
-            "FROM autofill_profile_phones"));
-
-    // John Doe phone.
-    ASSERT_TRUE(s4.Step());
-    EXPECT_EQ("00580526-FF81-EE2A-0546-1AC593A32E2F", s4.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("4151112222"), s4.ColumnString16(1));
-
-    // John Doe fax.
-    // Gets culled after fax type removed.
-
-    // John P. Doe phone.
-    // Gets culled during migration from 35 to 37 due to merging of John Doe and
-    // John P. Doe addresses.
-
-    // John P. Doe fax.
-    // Gets culled during migration from 35 to 37 due to merging of John Doe and
-    // John P. Doe addresses.
-
-    // 2 Main Street phone.
-    ASSERT_TRUE(s4.Step());
-    EXPECT_EQ("4C74A9D8-7EEE-423E-F9C2-E7FA70ED1396", s4.ColumnString(0));
-    EXPECT_EQ(base::string16(), s4.ColumnString16(1));
-
-    // 2 Main Street fax.
-    // Gets culled after fax type removed.
-
-    // 2 Main St phone.
-    ASSERT_TRUE(s4.Step());
-    EXPECT_EQ("722DF5C4-F74A-294A-46F0-31FFDED0D635", s4.ColumnString(0));
-    EXPECT_EQ(0, s4.ColumnInt(1));  // 0 means phone.
-    EXPECT_EQ(base::string16(), s4.ColumnString16(2));
-
-    // 2 Main St fax.
-    // Gets culled after fax type removed.
-
-    // Note no phone or fax for Alfred E Newman.
-
-    // 3 Main St phone.
-    ASSERT_TRUE(s4.Step());
-    EXPECT_EQ("9E5FE298-62C7-83DF-6293-381BC589183F", s4.ColumnString(0));
-    EXPECT_EQ(base::string16(), s4.ColumnString16(1));
-
-    // 2 Main St fax.
-    // Gets culled after fax type removed.
-
-    // Should be all.
-    EXPECT_FALSE(s4.Step());
-  }
-}
-
-// Adds a column for the autofill profile's country code.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion33ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_33.sql")));
-
-  // Verify pre-conditions. These are expectations for version 33 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_FALSE(connection.DoesColumnExist("autofill_profiles",
-                                            "country_code"));
-
-    // Check that the country value is the one we expect.
-    sql::Statement s(
-        connection.GetUniqueStatement("SELECT country FROM autofill_profiles"));
-
-    ASSERT_TRUE(s.Step());
-    std::string country = s.ColumnString(0);
-    EXPECT_EQ("United States", country);
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "country_code"));
-
-    // Check that the country code is properly converted.
-    sql::Statement s(connection.GetUniqueStatement(
-        "SELECT country_code FROM autofill_profiles"));
-
-    ASSERT_TRUE(s.Step());
-    std::string country_code = s.ColumnString(0);
-    EXPECT_EQ("US", country_code);
-  }
-}
-
-// Cleans up bad country code "UK" in favor of good country code "GB".
-TEST_F(WebDatabaseMigrationTest, MigrateVersion34ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_34.sql")));
-
-  // Verify pre-conditions. These are expectations for version 34 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "country_code"));
-
-    // Check that the country_code value is the one we expect.
-    sql::Statement s(
-        connection.GetUniqueStatement("SELECT country_code "
-                                      "FROM autofill_profiles"));
-
-    ASSERT_TRUE(s.Step());
-    std::string country_code = s.ColumnString(0);
-    EXPECT_EQ("UK", country_code);
-
-    // Should have only one.
-    ASSERT_FALSE(s.Step());
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles",
-                                           "country_code"));
-
-    // Check that the country_code code is properly converted.
-    sql::Statement s(connection.GetUniqueStatement(
-        "SELECT country_code FROM autofill_profiles"));
-
-    ASSERT_TRUE(s.Step());
-    std::string country_code = s.ColumnString(0);
-    EXPECT_EQ("GB", country_code);
-
-    // Should have only one.
-    ASSERT_FALSE(s.Step());
-  }
-}
-
-// Cleans up invalid profiles based on more agressive merging.  Filters out
-// profiles that are subsets of other profiles, and profiles with invalid email,
-// state, and incomplete address.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion35ToCurrent) {
-  // Initialize the database.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_35.sql")));
-
-  // Verify pre-conditions. These are expectations for version 34 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    EXPECT_FALSE(connection.DoesTableExist("autofill_profiles_trash"));
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-
-    // Check that there are 6 profiles prior to merge.
-    sql::Statement s(
-        connection.GetUniqueStatement("SELECT guid FROM autofill_profiles"));
-    int i = 0;
-    while (s.Step())
-      ++i;
-    EXPECT_EQ(6, i);
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    ASSERT_TRUE(connection.DoesTableExist("autofill_profiles_trash"));
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles_trash", "guid"));
-    ASSERT_TRUE(connection.DoesColumnExist("autofill_profiles", "guid"));
-
-    // Verify data in the database after the migration.
-    sql::Statement s1(
-        connection.GetUniqueStatement(
-            "SELECT guid, company_name, street_address, city, state, zipcode,"
-            " country_code, date_modified "
-            "FROM autofill_profiles"));
-
-    // John Doe.
-    ASSERT_TRUE(s1.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000001", s1.ColumnString(0));
-    EXPECT_EQ(ASCIIToUTF16("Acme Inc."), s1.ColumnString16(1));
-    EXPECT_EQ(ASCIIToUTF16("1 Main Street\n"
-                           "Apt 2"),
-              s1.ColumnString16(2));
-    EXPECT_EQ(ASCIIToUTF16("San Francisco"), s1.ColumnString16(3));
-    EXPECT_EQ(ASCIIToUTF16("CA"), s1.ColumnString16(4));
-    EXPECT_EQ(ASCIIToUTF16("94102"), s1.ColumnString16(5));
-    EXPECT_EQ(ASCIIToUTF16("US"), s1.ColumnString16(6));
-    EXPECT_EQ(1300131704, s1.ColumnInt64(7));
-
-    // That should be it.
-    ASSERT_FALSE(s1.Step());
-
-    // Check that there 5 trashed profile after the merge.
-    sql::Statement s2(
-        connection.GetUniqueStatement("SELECT guid "
-                                      "FROM autofill_profiles_trash"));
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000002", s2.ColumnString(0));
-
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000003", s2.ColumnString(0));
-
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000004", s2.ColumnString(0));
-
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000005", s2.ColumnString(0));
-
-    ASSERT_TRUE(s2.Step());
-    EXPECT_EQ("00000000-0000-0000-0000-000000000006", s2.ColumnString(0));
-
-    // That should be it.
-    ASSERT_FALSE(s2.Step());
-  }
-}
-
-// Tests that the |keywords| |last_modified| column gets added to the schema for
-// a version 37 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion37ToCurrent) {
-  // This schema is taken from a build prior to the addition of the |keywords|
-  // |last_modified| column.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_37.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 37 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Columns existing and not existing before current version.
-    ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords", "last_modified"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // |keywords| |last_modified| column should have been added.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "last_modified"));
-  }
-}
-
-// Tests that the |keywords| |sync_guid| column gets added to the schema for
-// a version 38 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion38ToCurrent) {
-  // This schema is taken from a build prior to the addition of the |keywords|
-  // |sync_guid| column.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_38.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 38 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Columns existing and not existing before current version.
-    ASSERT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords", "sync_guid"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // |keywords| |sync_guid| column should have been added.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "id"));
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "sync_guid"));
-  }
-}
-
-// Tests that no backup data is added to a version 39 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion39ToCurrent) {
-  // This schema is taken from a build prior to the addition of the default
-  // search provider backup field to the meta table.
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_39.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 39 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 39, 39));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the backup data is removed from the database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion40ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_40.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 40 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 40, 40));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-
-    EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the backup data is removed from the database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion41ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_41.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 41 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 41, 41));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-
-    EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the backup data is removed from the database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion42ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_42.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 42 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 42, 42));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-
-    EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
-
-    EXPECT_FALSE(connection.DoesTableExist("keywords_backup"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the backup data is removed from the database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion43ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_43.sql")));
-
-  int64 previous_default_search_provider_id;
-
-  // Verify pre-conditions.  These are expectations for version 43 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 43, 43));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(default_search_provider_id, 0);
-    previous_default_search_provider_id = default_search_provider_id;
-
-    EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
-    EXPECT_TRUE(connection.DoesTableExist("keywords_backup"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(
-        &connection,
-        kCurrentTestedVersionNumber,
-        kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    // Default search provider ID should not change.
-    EXPECT_EQ(previous_default_search_provider_id, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the |autogenerate_keyword| and |logo_id| columns get removed from
-// the keyword table schema for a version 45 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion44ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_44.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 44 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 44, 44));
-
-    ASSERT_TRUE(connection.DoesColumnExist("keywords", "autogenerate_keyword"));
-    ASSERT_TRUE(connection.DoesColumnExist("keywords", "logo_id"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    // We should have removed this obsolete key.
-    std::string default_search_provider_backup;
-    EXPECT_FALSE(meta_table.GetValue("Default Search Provider Backup",
-                                     &default_search_provider_backup));
-
-    // Two columns should have been removed.
-    EXPECT_FALSE(connection.DoesColumnExist("keywords",
-                                            "autogenerate_keyword"));
-    EXPECT_FALSE(connection.DoesColumnExist("keywords", "logo_id"));
-
-    // Backup data should have been removed.
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Previously, this tested that the web_intents and web_intents_defaults tables
-// were modified to include "scheme" columns. Since the web_intents and
-// web_intents_defaults tables are now obsolete, this test checks to ensure that
-// they are properly removed.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion45ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_45.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 45 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 45, 45));
-
-    ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents"));
-    ASSERT_FALSE(connection.DoesColumnExist(
-        "scheme", "web_intents_defaults"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(
-        &connection,
-        kCurrentTestedVersionNumber,
-        kCurrentTestedVersionNumber));
-
-    // finally ensure the migration code cleaned up after itself
-    EXPECT_FALSE(connection.DoesTableExist("web_intents"));
-    EXPECT_FALSE(connection.DoesTableExist("web_intents_defaults"));
-  }
-}
-
-// Previously, this tested that the web_intents and web_intents_defaults tables
-// were modified to include "scheme" columns. Since the web_intents and
-// web_intents_defaults tables are now obsolete, this test checks to ensure that
-// they are properly removed.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion45InvalidToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_45_invalid.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 45 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 45, 45));
-
-    ASSERT_FALSE(connection.DoesColumnExist("scheme", "web_intents"));
-    ASSERT_FALSE(connection.DoesColumnExist(
-        "scheme", "web_intents_defaults"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(
-        &connection,
-        kCurrentTestedVersionNumber,
-        kCurrentTestedVersionNumber));
-
-    EXPECT_FALSE(connection.DoesTableExist("web_intents"));
-    EXPECT_FALSE(connection.DoesTableExist("web_intents_defaults"));
-  }
-}
-
-// Check that current version is forced to compatible version before migration,
-// if the former is smaller.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion45CompatibleToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_45_compatible.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 45 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    // Database is actually version 45 but the version field states 40.
-    ASSERT_TRUE(meta_table.Init(&connection, 40, 45));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-    EXPECT_LE(45, VersionFromConnection(&connection));
-  }
-}
-
-// Tests that the |alternate_urls| column is added to the keyword table schema
-// for a version 47 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion46ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_46.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 46 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 46, 46));
-
-    ASSERT_FALSE(connection.DoesColumnExist("keywords", "alternate_urls"));
-    ASSERT_FALSE(connection.DoesColumnExist("keywords_backup",
-                                            "alternate_urls"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // A new column should have been created.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords", "alternate_urls"));
-  }
-}
-
-// Tests that the backup data is removed from the database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion47ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_47.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 47 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 47, 47));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckHasBackupData(&meta_table));
-    EXPECT_TRUE(connection.DoesTableExist("keywords_backup"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, kCurrentTestedVersionNumber,
-                                kCurrentTestedVersionNumber));
-
-    int64 default_search_provider_id = 0;
-    EXPECT_TRUE(meta_table.GetValue(KeywordTable::kDefaultSearchProviderKey,
-                                    &default_search_provider_id));
-    EXPECT_NE(0, default_search_provider_id);
-
-    EXPECT_NO_FATAL_FAILURE(CheckNoBackupData(connection, &meta_table));
-  }
-}
-
-// Tests that the |search_terms_replacement_key| column is added to the keyword
-// table schema for a version 49 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion48ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(
-      LoadDatabase(FILE_PATH_LITERAL("version_48.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 48 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    sql::MetaTable meta_table;
-    ASSERT_TRUE(meta_table.Init(&connection, 48, 48));
-
-    ASSERT_FALSE(connection.DoesColumnExist("keywords",
-                                            "search_terms_replacement_key"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // A new column should have been created.
-    EXPECT_TRUE(connection.DoesColumnExist("keywords",
-                                           "search_terms_replacement_key"));
-  }
-}
-
-// Tests that the |origin| column is added to the autofill_profiles and
-// credit_cards table schemas for a version 50 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion49ToCurrent) {
-  ASSERT_NO_FATAL_FAILURE(LoadDatabase(FILE_PATH_LITERAL("version_49.sql")));
-
-  // Verify pre-conditions.  These are expectations for version 49 of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-
-    ASSERT_FALSE(connection.DoesColumnExist("autofill_profiles", "origin"));
-    ASSERT_FALSE(connection.DoesColumnExist("credit_cards", "origin"));
-  }
-
-  DoMigration();
-
-  // Verify post-conditions.  These are expectations for current version of the
-  // database.
-  {
-    sql::Connection connection;
-    ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    ASSERT_TRUE(sql::MetaTable::DoesTableExist(&connection));
-
-    // Check version.
-    EXPECT_EQ(kCurrentTestedVersionNumber, VersionFromConnection(&connection));
-
-    // A new column should have been created in both tables.
-    EXPECT_TRUE(connection.DoesColumnExist("autofill_profiles", "origin"));
-    EXPECT_TRUE(connection.DoesColumnExist("credit_cards", "origin"));
-  }
-}
-
-// Tests that the columns |image_url|, |search_url_post_params|,
-// |suggest_url_post_params|, |instant_url_post_params|, and
-// |image_url_post_params| are added to the keyword table schema for a version
-// 50 database.
-TEST_F(WebDatabaseMigrationTest, MigrateVersion50ToCurrent) {
+// Versions below 52 are deprecated. This verifies that old databases are razed.
+TEST_F(WebDatabaseMigrationTest, RazeDeprecatedVersionAndReinit) {
   ASSERT_NO_FATAL_FAILURE(
       LoadDatabase(FILE_PATH_LITERAL("version_50.sql")));
 
diff --git a/content/browser/android/media_players_observer.cc b/content/browser/android/media_players_observer.cc
new file mode 100644
index 0000000..c4fd472
--- /dev/null
+++ b/content/browser/android/media_players_observer.cc
@@ -0,0 +1,60 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/media_players_observer.h"
+
+#include <climits>
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+MediaPlayersObserver::MediaPlayersObserver(WebContents* web_contents)
+    : AudioStateProvider(web_contents) {
+}
+
+MediaPlayersObserver::~MediaPlayersObserver() {}
+
+bool MediaPlayersObserver::IsAudioStateAvailable() const {
+  return true;
+}
+
+// This audio state provider does not have a monitor
+AudioStreamMonitor* MediaPlayersObserver::audio_stream_monitor() {
+  return nullptr;
+}
+
+void MediaPlayersObserver::OnAudibleStateChanged(RenderFrameHost* rfh,
+                                                int player_id,
+                                                bool is_audible) {
+  audio_status_map_[Key(rfh, player_id)] = is_audible;
+  UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::RemovePlayer(RenderFrameHost* rfh, int player_id) {
+  size_t num_erased_entries = audio_status_map_.erase(Key(rfh, player_id));
+  DCHECK_EQ(1u, num_erased_entries);
+  UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::RenderFrameDeleted(RenderFrameHost* rfh) {
+  StatusMap::iterator begin = audio_status_map_.lower_bound(Key(rfh, 0));
+  StatusMap::iterator end = audio_status_map_.upper_bound(Key(rfh, INT_MAX));
+  audio_status_map_.erase(begin, end);
+  UpdateStatusAndNotify();
+}
+
+void MediaPlayersObserver::UpdateStatusAndNotify() {
+  for (const auto& player_status : audio_status_map_) {
+    if (player_status.second) {
+      Notify(true);  // at least one player is making noise
+      return;
+    }
+  }
+
+  Notify(false);
+}
+
+} // namespace content
diff --git a/content/browser/android/media_players_observer.h b/content/browser/android/media_players_observer.h
new file mode 100644
index 0000000..b01a3bf
--- /dev/null
+++ b/content/browser/android/media_players_observer.h
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
+#define CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
+
+#include <map>
+
+#include "base/macros.h"
+#include "content/browser/media/audio_state_provider.h"
+
+namespace content {
+
+class RenderFrameHost;
+
+// On Android the MediaPlayerAndroid objects report
+// the audible state to us.
+class MediaPlayersObserver : public AudioStateProvider {
+ public:
+  explicit MediaPlayersObserver(WebContents* web_contents);
+  ~MediaPlayersObserver() override;
+
+  bool IsAudioStateAvailable() const override;
+
+  // This audio state provider does not have a monitor,
+  // the method returns nullptr.
+  AudioStreamMonitor* audio_stream_monitor() override;
+
+  // These methods constitute the observer pattern, should
+  // be called when corresponding event happens. They will notify
+  // WebContents whenever its audible state as a whole changes.
+  void OnAudibleStateChanged(RenderFrameHost* rfh, int player_id,
+                             bool is_audible);
+  void RemovePlayer(RenderFrameHost* rfh, int player_id);
+  void RenderFrameDeleted(RenderFrameHost* rfh);
+
+ private:
+  void UpdateStatusAndNotify();
+
+  // Audible status per player ID and frame
+  typedef std::pair<RenderFrameHost*, int> Key;
+  typedef std::map<Key, bool> StatusMap;
+  StatusMap audio_status_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(MediaPlayersObserver);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_ANDROID_MEDIA_PLAYERS_OBSERVER_H_
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc
index 647a062..2d422c9 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -30,9 +30,13 @@
 
 void SoftwareBrowserCompositorOutputSurface::SwapBuffers(
     cc::CompositorFrame* frame) {
-  for (size_t i = 0; i < frame->metadata.latency_info.size(); i++) {
-    frame->metadata.latency_info[i].AddLatencyNumber(
-        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+  base::TimeTicks swap_time = base::TimeTicks::Now();
+  for (auto& latency : frame->metadata.latency_info) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+        swap_time, 1);
   }
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
diff --git a/content/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
index 6e47a1f..3afc669 100644
--- a/content/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -236,9 +236,14 @@
 }
 
 bool SessionStorageDatabase::DeleteNamespace(const std::string& namespace_id) {
-  if (!LazyOpen(false)) {
-    // No need to create the database if it doesn't exist.
-    return true;
+  {
+    // The caller should have called other methods to open the DB before this
+    // function. Otherwise, DB stores nothing interesting related to the
+    // specified namespace.
+    // Do nothing if the DB is not open (or we know it has failed already),
+    base::AutoLock auto_lock(db_lock_);
+    if (!IsOpen() || db_error_ || is_inconsistent_)
+      return false;
   }
   DBOperation operation(this);
   // Itereate through the areas in the namespace.
diff --git a/content/browser/fileapi/blob_storage_context_unittest.cc b/content/browser/fileapi/blob_storage_context_unittest.cc
index 9602b3a..29270b7 100644
--- a/content/browser/fileapi/blob_storage_context_unittest.cc
+++ b/content/browser/fileapi/blob_storage_context_unittest.cc
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "storage/browser/blob/blob_storage_context.h"
+
+#include <limits>
+#include <string>
+
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
@@ -11,24 +16,19 @@
 #include "content/browser/fileapi/blob_storage_host.h"
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_handle.h"
+#include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/blob_data_snapshot.h"
-#include "storage/browser/blob/blob_storage_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using storage::BlobDataBuilder;
 using storage::BlobDataHandle;
+using storage::BlobDataItem;
 using storage::BlobDataSnapshot;
 using storage::BlobStorageContext;
 using storage::DataElement;
 
 namespace content {
-
 namespace {
-// This is necessary to clean up the blobs after the handles are released.
-void RunEventLoopTillIdle() {
-  base::RunLoop run_loop;
-  run_loop.RunUntilIdle();
-}
 
 void SetupBasicBlob(BlobStorageHost* host, const std::string& id) {
   EXPECT_TRUE(host->StartBuildingBlob(id));
@@ -38,6 +38,7 @@
   EXPECT_TRUE(host->FinishBuildingBlob(id, "text/plain"));
   EXPECT_FALSE(host->StartBuildingBlob(id));
 }
+
 }  // namespace
 
 TEST(BlobStorageContextTest, IncrementDecrementRef) {
@@ -54,7 +55,7 @@
   blob_data_handle = context.GetBlobDataFromUUID(kId);
   EXPECT_TRUE(blob_data_handle);
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Make sure its still there after inc/dec.
   EXPECT_TRUE(host.IncrementBlobRefCount(kId));
@@ -62,7 +63,7 @@
   blob_data_handle = context.GetBlobDataFromUUID(kId);
   EXPECT_TRUE(blob_data_handle);
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Make sure it goes away in the end.
   EXPECT_TRUE(host.DecrementBlobRefCount(kId));
@@ -113,7 +114,7 @@
   // Should disappear after dropping both handles.
   blob_data_handle.reset();
   another_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   blob_data_handle = context.GetBlobDataFromUUID(kId);
   EXPECT_FALSE(blob_data_handle);
@@ -147,11 +148,11 @@
   EXPECT_EQ(10lu, context.memory_usage());
 
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(10lu, context.memory_usage());
   blob_data_handle2.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(0lu, context.memory_usage());
 }
@@ -190,7 +191,7 @@
   blob_data_handle.reset();
   data2.reset();
 
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   blob_data_handle = context.GetBlobDataFromUUID(kId1);
   EXPECT_FALSE(blob_data_handle);
@@ -205,7 +206,7 @@
   scoped_ptr<BlobDataHandle> blob_data_handle3 =
       context.AddFinishedBlob(&builder3);
   blob_data_handle2.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   blob_data_handle2 = context.GetBlobDataFromUUID(kId2);
   EXPECT_FALSE(blob_data_handle2);
@@ -222,7 +223,43 @@
   blob_data_handle.reset();
   blob_data_handle2.reset();
   blob_data_handle3.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST(BlobStorageContextTest, AddFinishedBlob_LargeOffset) {
+  // A value which does not fit in a 4-byte data type. Used to confirm that
+  // large values are supported on 32-bit Chromium builds. Regression test for:
+  // crbug.com/458122.
+  const uint64_t kLargeSize = std::numeric_limits<uint64_t>::max();
+
+  const uint64_t kBlobLength = 5;
+  const std::string kId1("id1");
+  const std::string kId2("id2");
+  base::MessageLoop fake_io_message_loop;
+
+  BlobDataBuilder builder1(kId1);
+  builder1.AppendFileSystemFile(GURL(), 0, kLargeSize, base::Time::Now());
+
+  BlobDataBuilder builder2(kId2);
+  builder2.AppendBlob(kId1, kLargeSize - kBlobLength, kBlobLength);
+
+  BlobStorageContext context;
+  scoped_ptr<BlobDataHandle> blob_data_handle1 =
+      context.AddFinishedBlob(&builder1);
+  scoped_ptr<BlobDataHandle> blob_data_handle2 =
+      context.AddFinishedBlob(&builder2);
+
+  ASSERT_TRUE(blob_data_handle1);
+  ASSERT_TRUE(blob_data_handle2);
+  scoped_ptr<BlobDataSnapshot> data = blob_data_handle2->CreateSnapshot();
+  ASSERT_EQ(1u, data->items().size());
+  const scoped_refptr<BlobDataItem> item = data->items()[0];
+  EXPECT_EQ(kLargeSize - kBlobLength, item->offset());
+  EXPECT_EQ(kBlobLength, item->length());
+
+  blob_data_handle1.reset();
+  blob_data_handle2.reset();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST(BlobStorageContextTest, CompoundBlobs) {
@@ -276,7 +313,7 @@
   EXPECT_EQ(*data, canonicalized_blob_data2);
 
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 }
 
 TEST(BlobStorageContextTest, PublicBlobUrls) {
@@ -297,7 +334,7 @@
   EXPECT_EQ(kId, blob_data_handle->uuid());
   scoped_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   // The url registration should keep the blob alive even after
   // explicit references are dropped.
@@ -305,7 +342,7 @@
   blob_data_handle = context.GetBlobDataFromPublicURL(kUrl);
   EXPECT_TRUE(blob_data_handle);
   blob_data_handle.reset();
-  RunEventLoopTillIdle();
+  base::RunLoop().RunUntilIdle();
 
   // Finally get rid of the url registration and the blob.
   EXPECT_TRUE(host.RevokePublicBlobURL(kUrl));
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index ad4fd75..27285fbc 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -69,13 +69,9 @@
 
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override {
-    // TODO(nasko): Re-enable this logging once RenderFrameHostChanged observer
-    // methods are fixed. See https://crbug.com/450799.
-    /*
     if (old_host)
-      LogWhatHappened("RenderFrameChanged(old)", old_host);
-    LogWhatHappened("RenderFrameChanged(new)", new_host);
-    */
+      LogWhatHappened("RenderFrameHostChanged(old)", old_host);
+    LogWhatHappened("RenderFrameHostChanged(new)", new_host);
   }
 
   void RenderFrameDeleted(RenderFrameHost* render_frame_host) override {
@@ -213,9 +209,15 @@
 
   // Simulate attaching a series of frames to build the frame tree.
   main_test_rfh()->OnCreateChildFrame(14, std::string(), SandboxFlags::NONE);
-  EXPECT_EQ("RenderFrameCreated(14) -> 1: [14: []]", activity.GetLog());
+  EXPECT_EQ(
+      "RenderFrameHostChanged(new)(14) -> 1: []\n"
+      "RenderFrameCreated(14) -> 1: [14: []]",
+      activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(18, std::string(), SandboxFlags::NONE);
-  EXPECT_EQ("RenderFrameCreated(18) -> 1: [14: [], 18: []]", activity.GetLog());
+  EXPECT_EQ(
+      "RenderFrameHostChanged(new)(18) -> 1: [14: []]\n"
+      "RenderFrameCreated(18) -> 1: [14: [], 18: []]",
+      activity.GetLog());
   frame_tree->RemoveFrame(root->child_at(0));
   EXPECT_EQ("RenderFrameDeleted(14) -> 1: [18: []]", activity.GetLog());
   frame_tree->RemoveFrame(root->child_at(0));
@@ -228,9 +230,15 @@
   TreeWalkingWebContentsLogger activity(contents());
 
   main_test_rfh()->OnCreateChildFrame(22, std::string(), SandboxFlags::NONE);
-  EXPECT_EQ("RenderFrameCreated(22) -> 1: [22: []]", activity.GetLog());
+  EXPECT_EQ(
+      "RenderFrameHostChanged(new)(22) -> 1: []\n"
+      "RenderFrameCreated(22) -> 1: [22: []]",
+      activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(23, std::string(), SandboxFlags::NONE);
-  EXPECT_EQ("RenderFrameCreated(23) -> 1: [22: [], 23: []]", activity.GetLog());
+  EXPECT_EQ(
+      "RenderFrameHostChanged(new)(23) -> 1: [22: []]\n"
+      "RenderFrameCreated(23) -> 1: [22: [], 23: []]",
+      activity.GetLog());
 
   // Crash the renderer
   main_test_rfh()->OnMessageReceived(FrameHostMsg_RenderProcessGone(
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index 7e39192..864c7c3 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -351,4 +351,8 @@
     UMA_HISTOGRAM_MEMORY_KB("Overscroll.ScreenshotSize", screenshot_->size());
 }
 
+GURL NavigationEntryImpl::GetHistoryURLForDataURL() const {
+  return GetBaseURLForDataURL().is_empty() ? GURL() : GetVirtualURL();
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_entry_impl.h b/content/browser/frame_host/navigation_entry_impl.h
index 8fadcb3..c69c978e 100644
--- a/content/browser/frame_host/navigation_entry_impl.h
+++ b/content/browser/frame_host/navigation_entry_impl.h
@@ -225,6 +225,9 @@
     frame_tree_node_id_ = frame_tree_node_id;
   }
 
+  // Returns the history URL for a data URL to use in Blink.
+  GURL GetHistoryURLForDataURL() const;
+
 #if defined(OS_ANDROID)
   base::TimeTicks intent_received_timestamp() const {
     return intent_received_timestamp_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 8a599b1..75e61001 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -50,6 +50,13 @@
 }  // namespace
 
 // static
+bool NavigationRequest::ShouldMakeNetworkRequest(const GURL& url) {
+  // Data urls should not make network requests.
+  // TODO(clamy): same document navigations should not make network requests.
+  return !url.SchemeIs(url::kDataScheme);
+}
+
+// static
 scoped_ptr<NavigationRequest> NavigationRequest::CreateBrowserInitiated(
     FrameTreeNode* frame_tree_node,
     const NavigationEntryImpl& entry,
@@ -90,7 +97,8 @@
       CommonNavigationParams(entry.GetURL(), entry.GetReferrer(),
                              entry.GetTransitionType(), navigation_type,
                              !entry.IsViewSourceMode(),ui_timestamp,
-                             report_type),
+                             report_type, entry.GetBaseURLForDataURL(),
+                             entry.GetHistoryURLForDataURL()),
       BeginNavigationParams(method, headers.ToString(),
                             LoadFlagFromNavigationType(navigation_type),
                             false),
@@ -158,13 +166,24 @@
 NavigationRequest::~NavigationRequest() {
 }
 
-void NavigationRequest::BeginNavigation() {
+bool NavigationRequest::BeginNavigation() {
   DCHECK(!loader_);
   DCHECK(state_ == NOT_STARTED || state_ == WAITING_FOR_RENDERER_RESPONSE);
   state_ = STARTED;
-  loader_ = NavigationURLLoader::Create(
-      frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
-      frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
+
+  if (ShouldMakeNetworkRequest(common_params_.url)) {
+    loader_ = NavigationURLLoader::Create(
+        frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
+        frame_tree_node_->frame_tree_node_id(), info_.Pass(), this);
+    return true;
+  }
+
+  // There is no need to make a network request for this navigation, so commit
+  // it immediately.
+  state_ = RESPONSE_STARTED;
+  frame_tree_node_->navigator()->CommitNavigation(
+      frame_tree_node_, nullptr, scoped_ptr<StreamHandle>());
+  return false;
 
   // TODO(davidben): Fire (and add as necessary) observer methods such as
   // DidStartProvisionalLoadForFrame for the navigation.
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 948dbd1..56e993d 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -52,6 +52,10 @@
     FAILED,
   };
 
+  // Helper function to determine if the navigation request to |url| should be
+  // sent to the network stack.
+  static bool ShouldMakeNetworkRequest(const GURL& url);
+
   // Creates a request for a browser-intiated navigation.
   static scoped_ptr<NavigationRequest> CreateBrowserInitiated(
       FrameTreeNode* frame_tree_node,
@@ -70,11 +74,11 @@
 
   ~NavigationRequest() override;
 
-  // Called on the UI thread by the Navigator to start the navigation on the IO
-  // thread.
+  // Called on the UI thread by the Navigator to start the navigation. Returns
+  // whether a request was made on the IO thread.
   // TODO(clamy): see if ResourceRequestBody could be un-refcounted to avoid
   // threading subtleties.
-  void BeginNavigation();
+  bool BeginNavigation();
 
   const CommonNavigationParams& common_params() const { return common_params_; }
 
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 3e78f54..72f9f87 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -94,7 +94,8 @@
   params->common_params = CommonNavigationParams(
       entry.GetURL(), entry.GetReferrer(), entry.GetTransitionType(),
       GetNavigationType(controller->GetBrowserContext(), entry, reload_type),
-      !entry.IsViewSourceMode(), ui_timestamp, report_type);
+      !entry.IsViewSourceMode(), ui_timestamp, report_type,
+      entry.GetBaseURLForDataURL(), entry.GetHistoryURLForDataURL());
   params->commit_params = CommitNavigationParams(
       entry.GetPageState(), entry.GetIsOverridingUserAgent(), navigation_start);
   params->is_post = entry.GetHasPostData();
@@ -106,10 +107,6 @@
             entry.GetBrowserInitiatedPostData()->size());
   }
 
-  if (!entry.GetBaseURLForDataURL().is_empty()) {
-    params->base_url_for_data_url = entry.GetBaseURLForDataURL();
-    params->history_url_for_data_url = entry.GetVirtualURL();
-  }
   params->should_replace_current_entry = entry.should_replace_entry();
   // This is used by the old performance infrastructure to set up DocumentState
   // associated with the RenderView.
@@ -733,19 +730,22 @@
   CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnableBrowserSideNavigation));
 
+  NavigationRequest* navigation_request =
+      navigation_request_map_.get(frame_tree_node->frame_tree_node_id());
+  DCHECK(navigation_request);
+  DCHECK(response ||
+         !NavigationRequest::ShouldMakeNetworkRequest(
+             navigation_request->common_params().url));
+
   // HTTP 204 (No Content) and HTTP 205 (Reset Content) responses should not
   // commit; they leave the frame showing the previous page.
-  if (response->head.headers.get() &&
+  if (response && response->head.headers.get() &&
       (response->head.headers->response_code() == 204 ||
        response->head.headers->response_code() == 205)) {
     CancelNavigation(frame_tree_node);
     return;
   }
 
-  NavigationRequest* navigation_request =
-      navigation_request_map_.get(frame_tree_node->frame_tree_node_id());
-  DCHECK(navigation_request);
-
   // Select an appropriate renderer to commit the navigation.
   RenderFrameHostImpl* render_frame_host =
       frame_tree_node->render_manager()->GetFrameHostForNavigation(
@@ -864,12 +864,13 @@
   if (!navigation_request)
     return;
 
-  // First start the request on the IO thread.
-  navigation_request->BeginNavigation();
-
-  // Then notify the RenderFrameHostManager so it can speculatively create a
-  // RenderFrameHost (and potentially a new renderer process) in parallel.
-  frame_tree_node->render_manager()->BeginNavigation(*navigation_request);
+  // Start the request.
+   if (navigation_request->BeginNavigation()) {
+    // If the request was sent to the IO thread, notify the
+    // RenderFrameHostManager so it can speculatively create a RenderFrameHost
+    // (and potentially a new renderer process) in parallel.
+    frame_tree_node->render_manager()->BeginNavigation(*navigation_request);
+  }
 }
 
 void NavigatorImpl::RecordNavigationMetrics(
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc
index 82a49874..7eb3be69 100644
--- a/content/browser/frame_host/navigator_impl_unittest.cc
+++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -941,4 +941,50 @@
   EXPECT_FALSE(rfhm->IsOnSwappedOutList(rfh1));
 }
 
+// PlzNavigate: Verify that data urls are properly handled.
+TEST_F(NavigatorTestWithBrowserSideNavigation, DataUrls) {
+  const GURL kUrl1("http://wikipedia.org/");
+  const GURL kUrl2("data:text/html,test");
+
+  // Navigate to an initial site.
+  contents()->NavigateAndCommit(kUrl1);
+  FrameTreeNode* node = main_test_rfh()->frame_tree_node();
+
+  // Navigate to a data url.
+  RequestNavigation(node, kUrl2);
+  NavigationRequest* navigation_request =
+      GetNavigationRequestForFrameTreeNode(node);
+  ASSERT_TRUE(navigation_request);
+  EXPECT_EQ(NavigationRequest::WAITING_FOR_RENDERER_RESPONSE,
+            navigation_request->state());
+  main_test_rfh()->SendBeforeUnloadACK(true);
+
+  // The request should not have been sent to the IO thread but committed
+  // immediately.
+  EXPECT_EQ(NavigationRequest::RESPONSE_STARTED,
+            navigation_request->state());
+  EXPECT_FALSE(navigation_request->loader_for_testing());
+  TestRenderFrameHost* speculative_rfh = GetSpeculativeRenderFrameHost(node);
+  ASSERT_TRUE(speculative_rfh);
+  speculative_rfh->SendNavigate(0, kUrl2);
+  EXPECT_EQ(main_test_rfh(), speculative_rfh);
+
+  // Go back to the initial site.
+  contents()->NavigateAndCommit(kUrl1);
+
+  // Do a renderer-initiated navigation to a data url. The request should not be
+  // sent to the IO thread, nor committed.
+  TestRenderFrameHost* main_rfh = main_test_rfh();
+  main_rfh->SendBeginNavigationWithURL(kUrl2, true);
+  navigation_request = GetNavigationRequestForFrameTreeNode(node);
+  ASSERT_TRUE(navigation_request);
+  EXPECT_EQ(NavigationRequest::RESPONSE_STARTED,
+            navigation_request->state());
+  EXPECT_FALSE(navigation_request->loader_for_testing());
+  speculative_rfh = GetSpeculativeRenderFrameHost(node);
+  ASSERT_TRUE(speculative_rfh);
+  speculative_rfh->SendNavigate(0, kUrl2);
+  EXPECT_EQ(main_test_rfh(), speculative_rfh);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 38f4192..272aeb2 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -21,6 +21,7 @@
 #include "content/browser/frame_host/frame_accessibility.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
+#include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/navigator.h"
 #include "content/browser/frame_host/navigator_impl.h"
 #include "content/browser/frame_host/render_frame_host_delegate.h"
@@ -1495,11 +1496,11 @@
     ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
         GetProcess()->GetID(), params.common_params.url);
     if (params.common_params.url.SchemeIs(url::kDataScheme) &&
-        params.base_url_for_data_url.SchemeIs(url::kFileScheme)) {
+        params.common_params.base_url_for_data_url.SchemeIs(url::kFileScheme)) {
       // If 'data:' is used, and we have a 'file:' base url, grant access to
       // local files.
       ChildProcessSecurityPolicyImpl::GetInstance()->GrantRequestURL(
-          GetProcess()->GetID(), params.base_url_for_data_url);
+          GetProcess()->GetID(), params.common_params.base_url_for_data_url);
     }
   }
 
@@ -1666,6 +1667,8 @@
     scoped_ptr<StreamHandle> body,
     const CommonNavigationParams& common_params,
     const CommitNavigationParams& commit_params) {
+  DCHECK((response && body.get()) ||
+          !NavigationRequest::ShouldMakeNetworkRequest(common_params.url));
   // TODO(clamy): Check if we have to add security checks for the browser plugin
   // guests.
 
@@ -1673,9 +1676,11 @@
   // completing a RFH swap or unload handler.
   SetState(RenderFrameHostImpl::STATE_DEFAULT);
 
+  const GURL body_url = body.get() ? body->GetURL() : GURL();
+  const ResourceResponseHead head = response ?
+      response->head : ResourceResponseHead();
   Send(new FrameMsg_CommitNavigation(
-      routing_id_, response->head, body->GetURL(),
-      common_params, commit_params));
+      routing_id_, head, body_url, common_params, commit_params));
   // TODO(clamy): Check if we should start the throbber for non javascript urls
   // here.
 
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index f9e2bf9..b9328a4 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -109,6 +109,14 @@
   SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id,
                                            frame_routing_id, flags));
 
+  // Notify the delegate of the creation of the current RenderFrameHost.
+  // Do this only for subframes, as the main frame case is taken care of by
+  // WebContentsImpl::Init.
+  if (!frame_tree_node_->IsMainFrame()) {
+    delegate_->NotifySwappedFromRenderManager(
+        nullptr, render_frame_host_.get(), false);
+  }
+
   // Keep track of renderer processes as they start to shut down or are
   // crashed/killed.
   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_CLOSED,
@@ -224,14 +232,18 @@
     // Now that we've created a new renderer, be sure to hide it if it isn't
     // our primary one.  Otherwise, we might crash if we try to call Show()
     // on it later.
-    if (dest_render_frame_host != render_frame_host_ &&
-        dest_render_frame_host->GetView()) {
-      dest_render_frame_host->GetView()->Hide();
+    if (dest_render_frame_host != render_frame_host_) {
+      if (dest_render_frame_host->GetView())
+        dest_render_frame_host->GetView()->Hide();
     } else {
-      // Notify here as we won't be calling CommitPending (which does the
-      // notify).
-      delegate_->NotifySwappedFromRenderManager(
-          NULL, render_frame_host_.get(), frame_tree_node_->IsMainFrame());
+      // TODO(nasko): This is a very ugly hack. The Chrome extensions process
+      // manager still uses NotificationService and expects to see a
+      // RenderViewHost changed notification after WebContents and
+      // RenderFrameHostManager are completely initialized. This should be
+      // removed once the process manager moves away from NotificationService.
+      // See https://crbug.com/462682.
+      delegate_->NotifyMainFrameSwappedFromRenderManager(
+          nullptr, render_frame_host_->render_view_host());
     }
   }
 
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index 15338be..073908a 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -137,6 +137,11 @@
     virtual void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
                                                 RenderFrameHost* new_host,
                                                 bool is_main_frame) = 0;
+    // TODO(nasko): This should be removed once extensions no longer use
+    // NotificationService. See https://crbug.com/462682.
+    virtual void NotifyMainFrameSwappedFromRenderManager(
+        RenderViewHost* old_host,
+        RenderViewHost* new_host) = 0;
     virtual NavigationControllerImpl&
         GetControllerForRenderManager() = 0;
 
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index b949142..18eefc7 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -316,12 +316,19 @@
 bool UseSurfacesEnabled() {
 #if defined(OS_ANDROID)
   return false;
-#else
+#endif
+  bool enabled = false;
+#if (defined(USE_AURA) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
+  enabled = true;
+#endif
+
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
 
-  return command_line.HasSwitch(switches::kUseSurfaces);
-#endif
+  // Flags override.
+  enabled |= command_line.HasSwitch(switches::kUseSurfaces);
+  enabled &= !command_line.HasSwitch(switches::kDisableSurfaces);
+  return enabled;
 }
 
 int GpuRasterizationMSAASampleCount() {
diff --git a/content/browser/loader/cross_site_resource_handler.cc b/content/browser/loader/cross_site_resource_handler.cc
index 44d24ce..ccdd321 100644
--- a/content/browser/loader/cross_site_resource_handler.cc
+++ b/content/browser/loader/cross_site_resource_handler.cc
@@ -68,6 +68,13 @@
       RenderFrameHostImpl::FromID(params.global_request_id.child_id,
                                   params.render_frame_id);
   if (rfh) {
+    if (rfh->GetParent()) {
+      // We should only swap processes for subframes in --site-per-process mode.
+      // CrossSiteResourceHandler is not installed on subframe requests in
+      // default Chrome.
+      CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSitePerProcess));
+    }
     rfh->OnCrossSiteResponse(
         params.global_request_id, cross_site_transferring_request.Pass(),
         params.transfer_url_chain, params.referrer,
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 19eb7560..e539eaa 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -2149,6 +2149,10 @@
   // thread where they can be passed along to the respective RVHs.
   scoped_ptr<LoadInfoMap> info_map(new LoadInfoMap());
 
+  tracked_objects::ScopedTracker tracking_profile0(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "455952 ResourceDispatcherHostImpl::GetLoadInfoForAllRoutes0"));
+
   for (const auto& loader : pending_loaders_) {
     // Also poll for upload progress on this timer and send upload progress ipc
     // messages to the plugin process.
@@ -2220,6 +2224,10 @@
   if (info_map->empty())
     return;
 
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "455952 ResourceDispatcherHostImpl::UpdateLoadInfo2"));
+
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&ResourceDispatcherHostImpl::UpdateLoadInfoOnUIThread,
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index 5fecd39..8600a75 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -7,6 +7,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/command_line.h"
 #include "content/browser/android/content_view_core_impl.h"
+#include "content/browser/android/media_players_observer.h"
 #include "content/browser/media/android/browser_demuxer_android.h"
 #include "content/browser/media/android/media_resource_getter_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
@@ -57,10 +58,11 @@
 
 // static
 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
-    RenderFrameHost* rfh) {
+    RenderFrameHost* rfh,
+    MediaPlayersObserver* audio_monitor) {
   if (g_factory)
-    return g_factory(rfh);
-  return new BrowserMediaPlayerManager(rfh);
+    return g_factory(rfh, audio_monitor);
+  return new BrowserMediaPlayerManager(rfh, audio_monitor);
 }
 
 ContentViewCoreImpl* BrowserMediaPlayerManager::GetContentViewCore() const {
@@ -121,8 +123,10 @@
 }
 
 BrowserMediaPlayerManager::BrowserMediaPlayerManager(
-    RenderFrameHost* render_frame_host)
+    RenderFrameHost* render_frame_host,
+    MediaPlayersObserver* audio_monitor)
     : render_frame_host_(render_frame_host),
+      audio_monitor_(audio_monitor),
       fullscreen_player_id_(kInvalidMediaPlayerId),
       fullscreen_player_is_released_(false),
       web_contents_(WebContents::FromRenderFrameHost(render_frame_host)),
@@ -254,6 +258,12 @@
     video_view_->OnVideoSizeChanged(width, height);
 }
 
+void BrowserMediaPlayerManager::OnAudibleStateChanged(
+    int player_id, bool is_audible) {
+  audio_monitor_->OnAudibleStateChanged(
+      render_frame_host_, player_id, is_audible);
+}
+
 media::MediaResourceGetter*
 BrowserMediaPlayerManager::GetMediaResourceGetter() {
   if (!media_resource_getter_.get()) {
@@ -518,6 +528,7 @@
     if ((*it)->player_id() == player_id) {
       ReleaseMediaResources(player_id);
       players_.erase(it);
+      audio_monitor_->RemovePlayer(render_frame_host_, player_id);
       break;
     }
   }
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h
index e0a40132..bec4695 100644
--- a/content/browser/media/android/browser_media_player_manager.h
+++ b/content/browser/media/android/browser_media_player_manager.h
@@ -30,6 +30,7 @@
 class BrowserDemuxerAndroid;
 class ContentViewCoreImpl;
 class ExternalVideoSurfaceContainer;
+class MediaPlayersObserver;
 class RenderFrameHost;
 class WebContents;
 
@@ -42,7 +43,8 @@
     : public media::MediaPlayerManager {
  public:
   // Permits embedders to provide an extended version of the class.
-  typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*);
+  typedef BrowserMediaPlayerManager* (*Factory)(RenderFrameHost*,
+                                                MediaPlayersObserver*);
   static void RegisterFactory(Factory factory);
 
   // Permits embedders to handle custom urls.
@@ -50,7 +52,9 @@
       media::MediaUrlInterceptor* media_url_interceptor);
 
   // Returns a new instance using the registered factory if available.
-  static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh);
+  static BrowserMediaPlayerManager* Create(
+      RenderFrameHost* rfh,
+      MediaPlayersObserver* audio_monitor);
 
   ContentViewCoreImpl* GetContentViewCore() const;
 
@@ -83,6 +87,9 @@
                       const base::TimeDelta& current_time) override;
   void OnError(int player_id, int error) override;
   void OnVideoSizeChanged(int player_id, int width, int height) override;
+  void OnAudibleStateChanged(
+      int player_id, bool is_audible_now) override;
+
   media::MediaResourceGetter* GetMediaResourceGetter() override;
   media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
   media::MediaPlayerAndroid* GetFullscreenPlayer() override;
@@ -118,7 +125,8 @@
 
  protected:
   // Clients must use Create() or subclass constructor.
-  explicit BrowserMediaPlayerManager(RenderFrameHost* render_frame_host);
+  BrowserMediaPlayerManager(RenderFrameHost* render_frame_host,
+                            MediaPlayersObserver* audio_monitor);
 
   WebContents* web_contents() const { return web_contents_; }
 
@@ -168,6 +176,8 @@
 
   RenderFrameHost* const render_frame_host_;
 
+  MediaPlayersObserver* audio_monitor_;
+
   // An array of managed players.
   ScopedVector<media::MediaPlayerAndroid> players_;
 
diff --git a/content/browser/media/audio_state_provider.cc b/content/browser/media/audio_state_provider.cc
new file mode 100644
index 0000000..e09356a
--- /dev/null
+++ b/content/browser/media/audio_state_provider.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/media/audio_state_provider.h"
+
+#include "base/logging.h"
+#include "content/browser/media/audio_stream_monitor.h"
+#include "content/public/browser/web_contents.h"
+
+namespace content {
+
+AudioStateProvider::AudioStateProvider(WebContents* contents)
+    : web_contents_(contents),
+      was_recently_audible_(false) {
+  DCHECK(web_contents_);
+}
+
+bool AudioStateProvider::WasRecentlyAudible() const {
+  return was_recently_audible_;
+}
+
+void AudioStateProvider::Notify(bool new_state) {
+  if (was_recently_audible_ != new_state) {
+    was_recently_audible_ = new_state;
+    web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
+  }
+}
+
+} // namespace content
diff --git a/content/browser/media/audio_state_provider.h b/content/browser/media/audio_state_provider.h
new file mode 100644
index 0000000..5bd1b718
--- /dev/null
+++ b/content/browser/media/audio_state_provider.h
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
+#define CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+class WebContents;
+class AudioStreamMonitor;
+
+// This class is associated with a WebContents, and maintains the audible
+// state regarding all the players in it.
+// The audible state is true if at least one player is playing a sound.
+// Whenever the audible state of the WebContents as a whole changes, this
+// class sends a notification to it.
+//
+// Each WebContentsImpl owns an AudioStateProvider
+class CONTENT_EXPORT AudioStateProvider {
+ public:
+  explicit AudioStateProvider(WebContents* web_contents);
+  virtual ~AudioStateProvider() {}
+
+  // Indicates whether this service is available on the system.
+  virtual bool IsAudioStateAvailable() const = 0;
+
+  // If this provider uses monitoring (i.e. measure the signal),
+  // return its monitor.
+  virtual AudioStreamMonitor* audio_stream_monitor() = 0;
+
+  // Returns true if the WebContents is playing or has recently been
+  // playing the sound.
+  virtual bool WasRecentlyAudible() const;
+
+  void set_was_recently_audible_for_testing(bool value) {
+    was_recently_audible_ = value;
+  }
+
+ protected:
+  // Notify WebContents that the audio state has changed.
+  void Notify(bool new_state);
+
+  // The WebContents instance instance to receive indicator toggle
+  // notifications.  This pointer should be valid for the lifetime of
+  // AudioStreamMonitor.
+  WebContents* const web_contents_;
+
+  // The audio state that is being maintained
+  bool  was_recently_audible_;
+
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MEDIA_AUDIO_STATE_PROVIDER_H_
diff --git a/content/browser/media/audio_stream_monitor.cc b/content/browser/media/audio_stream_monitor.cc
index 1d2f76f7..4c0bc0a 100644
--- a/content/browser/media/audio_stream_monitor.cc
+++ b/content/browser/media/audio_stream_monitor.cc
@@ -21,23 +21,36 @@
   WebContentsImpl* const web_contents =
       static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(
           RenderFrameHost::FromID(render_process_id, render_frame_id)));
-  return web_contents ? web_contents->audio_stream_monitor() : NULL;
+
+  if (!web_contents)
+    return nullptr;
+
+  AudioStateProvider* audio_provider = web_contents->audio_state_provider();
+  return audio_provider ? audio_provider->audio_stream_monitor() : nullptr;
 }
 
 }  // namespace
 
 AudioStreamMonitor::AudioStreamMonitor(WebContents* contents)
-    : web_contents_(contents),
-      clock_(&default_tick_clock_),
-      was_recently_audible_(false) {
-  DCHECK(web_contents_);
+    : AudioStateProvider(contents),
+      clock_(&default_tick_clock_)
+{
 }
 
 AudioStreamMonitor::~AudioStreamMonitor() {}
 
+bool AudioStreamMonitor::IsAudioStateAvailable() const {
+  return media::AudioOutputController::will_monitor_audio_levels();
+}
+
+// This provider is the monitor.
+AudioStreamMonitor* AudioStreamMonitor::audio_stream_monitor() {
+  return this;
+}
+
 bool AudioStreamMonitor::WasRecentlyAudible() const {
   DCHECK(thread_checker_.CalledOnValidThread());
-  return was_recently_audible_;
+  return AudioStateProvider::WasRecentlyAudible();
 }
 
 // static
@@ -46,7 +59,7 @@
     int render_frame_id,
     int stream_id,
     const ReadPowerAndClipCallback& read_power_callback) {
-  if (!monitoring_available())
+  if (!media::AudioOutputController::will_monitor_audio_levels())
     return;
   BrowserThread::PostTask(BrowserThread::UI,
                           FROM_HERE,
@@ -61,7 +74,7 @@
 void AudioStreamMonitor::StopMonitoringStream(int render_process_id,
                                               int render_frame_id,
                                               int stream_id) {
-  if (!monitoring_available())
+  if (!media::AudioOutputController::will_monitor_audio_levels())
     return;
   BrowserThread::PostTask(BrowserThread::UI,
                           FROM_HERE,
@@ -138,16 +151,12 @@
 }
 
 void AudioStreamMonitor::MaybeToggle() {
-  const bool indicator_was_on = was_recently_audible_;
   const base::TimeTicks off_time =
       last_blurt_time_ + base::TimeDelta::FromMilliseconds(kHoldOnMilliseconds);
   const base::TimeTicks now = clock_->NowTicks();
   const bool should_indicator_be_on = now < off_time;
 
-  if (should_indicator_be_on != indicator_was_on) {
-    was_recently_audible_ = should_indicator_be_on;
-    web_contents_->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
-  }
+  Notify(should_indicator_be_on);
 
   if (!should_indicator_be_on) {
     off_timer_.Stop();
diff --git a/content/browser/media/audio_stream_monitor.h b/content/browser/media/audio_stream_monitor.h
index d1a32d5..b3cbf16 100644
--- a/content/browser/media/audio_stream_monitor.h
+++ b/content/browser/media/audio_stream_monitor.h
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "content/browser/media/audio_state_provider.h"
 #include "content/common/content_export.h"
 #include "media/audio/audio_output_controller.h"
 
@@ -22,7 +23,6 @@
 }
 
 namespace content {
-class WebContents;
 
 // Repeatedly polls audio streams for their power levels, and "debounces" the
 // information into a simple, binary "was recently audible" result for the audio
@@ -32,23 +32,23 @@
 // to turn on/off repeatedly and annoy the user.  AudioStreamMonitor sends UI
 // update notifications only when needed, but may be queried at any time.
 //
-// Each WebContentsImpl owns an AudioStreamMonitor.
-class CONTENT_EXPORT AudioStreamMonitor {
+class CONTENT_EXPORT AudioStreamMonitor : public AudioStateProvider {
  public:
   explicit AudioStreamMonitor(WebContents* contents);
-  ~AudioStreamMonitor();
+  ~AudioStreamMonitor() override;
 
   // Indicates if audio stream monitoring is available.  It's only available if
   // AudioOutputController can and will monitor output power levels.
-  static bool monitoring_available() {
-    return media::AudioOutputController::will_monitor_audio_levels();
-  }
+  bool IsAudioStateAvailable() const override;
+
+  // This provider is a monitor, the method returns |this|.
+  AudioStreamMonitor* audio_stream_monitor() override;
 
   // Returns true if audio has recently been audible from the tab.  This is
   // usually called whenever the tab data model is refreshed; but there are
   // other use cases as well (e.g., the OOM killer uses this to de-prioritize
   // the killing of tabs making sounds).
-  bool WasRecentlyAudible() const;
+  bool WasRecentlyAudible() const override;
 
   // Starts or stops audio level monitoring respectively for the stream owned by
   // the specified renderer.  Safe to call from any thread.
@@ -66,10 +66,6 @@
                                    int render_frame_id,
                                    int stream_id);
 
-  void set_was_recently_audible_for_testing(bool value) {
-    was_recently_audible_ = value;
-  }
-
  private:
   friend class AudioStreamMonitorTest;
 
@@ -112,11 +108,6 @@
   // on, |off_timer_| is started to re-invoke this method in the future.
   void MaybeToggle();
 
-  // The WebContents instance instance to receive indicator toggle
-  // notifications.  This pointer should be valid for the lifetime of
-  // AudioStreamMonitor.
-  WebContents* const web_contents_;
-
   // Note: |clock_| is always |&default_tick_clock_|, except during unit
   // testing.
   base::DefaultTickClock default_tick_clock_;
@@ -134,10 +125,6 @@
   // Records the last time at which sound was audible from any stream.
   base::TimeTicks last_blurt_time_;
 
-  // Set to true if the last call to MaybeToggle() determined the indicator
-  // should be turned on.
-  bool was_recently_audible_;
-
   // Calls Poll() at regular intervals while |poll_callbacks_| is non-empty.
   base::RepeatingTimer<AudioStreamMonitor> poll_timer_;
 
diff --git a/content/browser/media/audio_stream_monitor_unittest.cc b/content/browser/media/audio_stream_monitor_unittest.cc
index 0d206216..0607b75 100644
--- a/content/browser/media/audio_stream_monitor_unittest.cc
+++ b/content/browser/media/audio_stream_monitor_unittest.cc
@@ -52,7 +52,13 @@
     WebContentsImpl* web_contents = reinterpret_cast<WebContentsImpl*>(
         RenderViewHostTestHarness::web_contents());
     web_contents->SetDelegate(&mock_web_contents_delegate_);
-    monitor_ = web_contents->audio_stream_monitor();
+
+    AudioStateProvider* provider =  web_contents->audio_state_provider();
+    ASSERT_TRUE(provider);
+
+    monitor_ = provider->audio_stream_monitor();
+    ASSERT_TRUE(monitor_);
+
     const_cast<base::TickClock*&>(monitor_->clock_) = &clock_;
   }
 
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index cc90b55e..f87cfb1 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -8,11 +8,13 @@
 #include "base/stl_util.h"
 #include "content/browser/media/cdm/browser_cdm_manager.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "ipc/ipc_message_macros.h"
 
 #if defined(OS_ANDROID)
+#include "content/browser/android/media_players_observer.h"
 #include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/common/media/media_player_messages_android.h"
 #include "media/base/android/media_player_android.h"
@@ -22,7 +24,8 @@
 
 MediaWebContentsObserver::MediaWebContentsObserver(
     WebContents* web_contents)
-    : WebContentsObserver(web_contents) {
+    : WebContentsObserver(web_contents)
+{
 }
 
 MediaWebContentsObserver::~MediaWebContentsObserver() {
@@ -35,6 +38,10 @@
   // Always destroy the media players before CDMs because we do not support
   // detaching CDMs from media players yet. See http://crbug.com/330324
   media_player_managers_.erase(key);
+
+  MediaPlayersObserver* audio_observer = GetMediaPlayersObserver();
+  if (audio_observer)
+    audio_observer->RenderFrameDeleted(render_frame_host);
 #endif
   // TODO(xhwang): Currently MediaWebContentsObserver, BrowserMediaPlayerManager
   // and BrowserCdmManager all run on browser UI thread. So this call is okay.
@@ -161,11 +168,24 @@
   if (!media_player_managers_.contains(key)) {
     media_player_managers_.set(
         key,
-        make_scoped_ptr(BrowserMediaPlayerManager::Create(render_frame_host)));
+        make_scoped_ptr(BrowserMediaPlayerManager::Create(
+            render_frame_host, GetMediaPlayersObserver())));
   }
   return media_player_managers_.get(key);
 }
 
+MediaPlayersObserver*
+MediaWebContentsObserver::GetMediaPlayersObserver() const {
+  AudioStateProvider* provider =
+      static_cast<WebContentsImpl*>(web_contents())->audio_state_provider();
+
+  MediaPlayersObserver* audio_observer =
+      static_cast<MediaPlayersObserver*>(provider);
+
+  DCHECK(audio_observer);
+  return audio_observer;
+}
+
 #if defined(VIDEO_HOLE)
 void MediaWebContentsObserver::OnFrameInfoUpdated() {
   for (MediaPlayerManagerMap::iterator iter = media_player_managers_.begin();
diff --git a/content/browser/media/media_web_contents_observer.h b/content/browser/media/media_web_contents_observer.h
index 3b451a8..2eb08c1 100644
--- a/content/browser/media/media_web_contents_observer.h
+++ b/content/browser/media/media_web_contents_observer.h
@@ -7,11 +7,16 @@
 
 #include "base/compiler_specific.h"
 #include "base/containers/scoped_ptr_hash_map.h"
+#include "base/memory/scoped_ptr.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/web_contents_observer.h"
 
 namespace content {
 
+#if defined(OS_ANDROID)
+class MediaPlayersObserver;
+#endif  // defined(OS_ANDROID)
+
 class BrowserCdmManager;
 class BrowserMediaPlayerManager;
 
@@ -45,6 +50,8 @@
 
   void OnSetCdm(RenderFrameHost* render_frame_host, int player_id, int cdm_id);
 
+  MediaPlayersObserver* GetMediaPlayersObserver() const;
+
 #if defined(VIDEO_HOLE)
   void OnFrameInfoUpdated();
 #endif  // defined(VIDEO_HOLE)
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc
index fc613c84..cdd5cb9 100644
--- a/content/browser/media/webrtc_browsertest.cc
+++ b/content/browser/media/webrtc_browsertest.cc
@@ -371,9 +371,7 @@
 // MediaStream that has been created based on a MediaStream created with
 // getUserMedia. When video is flowing, the VideoTrack is removed and an
 // AudioTrack is added instead.
-// TODO(phoglund): This test is manual since not all buildbots has an audio
-// input.
-IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, MANUAL_CallAndModifyStream) {
+IN_PROC_BROWSER_TEST_F(MAYBE_WebRtcBrowserTest, CallAndModifyStream) {
   MakeTypicalPeerConnectionCall(
       "callWithNewVideoMediaStreamLaterSwitchToAudio();");
 }
diff --git a/content/browser/renderer_host/render_widget_host_latency_tracker.cc b/content/browser/renderer_host/render_widget_host_latency_tracker.cc
index 9cbd986..8de5512 100644
--- a/content/browser/renderer_host/render_widget_host_latency_tracker.cc
+++ b/content/browser/renderer_host/render_widget_host_latency_tracker.cc
@@ -150,10 +150,10 @@
     1, 50000, 50)
 
 void ComputeScrollLatencyHistograms(
-    const LatencyInfo::LatencyComponent& swap_component,
+    const LatencyInfo::LatencyComponent& gpu_swap_component,
     int64 latency_component_id,
-    const ui::LatencyInfo& latency) {
-  DCHECK(!swap_component.event_time.is_null());
+    const LatencyInfo& latency) {
+  DCHECK(!gpu_swap_component.event_time.is_null());
   LatencyInfo::LatencyComponent first_original_component, original_component;
   if (latency.FindLatency(
           ui::INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
@@ -164,7 +164,7 @@
     for (size_t i = 0; i < first_original_component.event_count; i++) {
       UMA_HISTOGRAM_CUSTOM_COUNTS(
           "Event.Latency.TouchToFirstScrollUpdateSwap",
-          (swap_component.event_time - first_original_component.event_time)
+          (gpu_swap_component.event_time - first_original_component.event_time)
               .InMicroseconds(),
           1, 1000000, 100);
     }
@@ -181,7 +181,7 @@
   for (size_t i = 0; i < original_component.event_count; i++) {
     UMA_HISTOGRAM_CUSTOM_COUNTS(
         "Event.Latency.TouchToScrollUpdateSwap",
-        (swap_component.event_time - original_component.event_time)
+        (gpu_swap_component.event_time - original_component.event_time)
             .InMicroseconds(),
         1, 1000000, 100);
   }
@@ -235,17 +235,19 @@
       "Event.Latency.ScrollUpdate.RendererSwapToBrowserNotified",
       renderer_swap_component, browser_received_swap_component);
 
-  LatencyInfo::LatencyComponent gpu_swap_component;
-  if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT,
-                           0, &gpu_swap_component))
-    return;
-
   UMA_HISTOGRAM_SCROLL_LATENCY_LONG(
       "Event.Latency.ScrollUpdate.BrowserNotifiedToBeforeGpuSwap",
       browser_received_swap_component, gpu_swap_component);
 
+  LatencyInfo::LatencyComponent gpu_swap_ack_component;
+  if (!latency.FindLatency(
+          ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
+          &gpu_swap_ack_component))
+    return;
+
   UMA_HISTOGRAM_SCROLL_LATENCY_SHORT("Event.Latency.ScrollUpdate.GpuSwap",
-                                     gpu_swap_component, swap_component);
+                                     gpu_swap_component,
+                                     gpu_swap_ack_component);
 }
 
 // LatencyComponents generated in the renderer must have component IDs
@@ -389,11 +391,10 @@
 }
 
 void RenderWidgetHostLatencyTracker::OnFrameSwapped(
-    const ui::LatencyInfo& latency) {
-  LatencyInfo::LatencyComponent swap_component;
-  if (!latency.FindLatency(
-          ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
-          &swap_component)) {
+    const LatencyInfo& latency) {
+  LatencyInfo::LatencyComponent gpu_swap_component;
+  if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0,
+                           &gpu_swap_component)) {
     return;
   }
 
@@ -401,28 +402,21 @@
   if (latency.FindLatency(ui::TAB_SHOW_COMPONENT, latency_component_id_,
                           &tab_switch_component)) {
     base::TimeDelta delta =
-        swap_component.event_time - tab_switch_component.event_time;
+        gpu_swap_component.event_time - tab_switch_component.event_time;
     for (size_t i = 0; i < tab_switch_component.event_count; i++) {
       UMA_HISTOGRAM_TIMES("MPArch.RWH_TabSwitchPaintDuration", delta);
     }
   }
 
-  LatencyInfo::LatencyComponent rwh_component;
   if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
-                           latency_component_id_, &rwh_component)) {
+                           latency_component_id_, nullptr)) {
     return;
   }
 
-  ComputeScrollLatencyHistograms(swap_component, latency_component_id_,
+  ComputeScrollLatencyHistograms(gpu_swap_component, latency_component_id_,
                                  latency);
 
-  ui::LatencyInfo::LatencyComponent gpu_swap_component;
-  if (!latency.FindLatency(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0,
-                           &gpu_swap_component)) {
-    return;
-  }
-
-  ui::LatencyInfo::LatencyComponent browser_swap_component;
+  LatencyInfo::LatencyComponent browser_swap_component;
   if (latency.FindLatency(
           ui::INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT, 0,
           &browser_swap_component)) {
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index 747319e..d6468fd 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -426,22 +426,6 @@
   context_->UpdateServiceWorker(registration);
 }
 
-void ServiceWorkerVersion::SendMessage(
-    const IPC::Message& message, const StatusCallback& callback) {
-  if (running_status() != RUNNING) {
-    // Schedule calling this method after starting the worker.
-    StartWorker(base::Bind(&RunTaskAfterStartWorker,
-                           weak_factory_.GetWeakPtr(), callback,
-                           base::Bind(&self::SendMessage,
-                                      weak_factory_.GetWeakPtr(),
-                                      message, callback)));
-    return;
-  }
-
-  ServiceWorkerStatusCode status = embedded_worker_->SendMessage(message);
-  RunSoon(base::Bind(callback, status));
-}
-
 void ServiceWorkerVersion::DispatchMessageEvent(
     const base::string16& message,
     const std::vector<TransferredMessagePort>& sent_message_ports,
diff --git a/content/browser/service_worker/service_worker_version.h b/content/browser/service_worker/service_worker_version.h
index 2aeaabb..220c67a 100644
--- a/content/browser/service_worker/service_worker_version.h
+++ b/content/browser/service_worker/service_worker_version.h
@@ -166,13 +166,6 @@
   // Starts an update now.
   void StartUpdate();
 
-  // Sends an IPC message to the worker.
-  // If the worker is not running this first tries to start it by
-  // calling StartWorker internally.
-  // |callback| can be null if the sender does not need to know if the
-  // message is successfully sent or not.
-  void SendMessage(const IPC::Message& message, const StatusCallback& callback);
-
   // Sends a message event to the associated embedded worker.
   void DispatchMessageEvent(
       const base::string16& message,
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 7cf16e2d..bdcea477 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -250,31 +250,31 @@
   EXPECT_EQ(SERVICE_WORKER_OK, status3);
 }
 
-TEST_F(ServiceWorkerVersionTest, SendMessage) {
+TEST_F(ServiceWorkerVersionTest, DispatchEventToStoppedWorker) {
   EXPECT_EQ(ServiceWorkerVersion::STOPPED, version_->running_status());
 
-  // Send a message without starting the worker.
+  // Dispatch an event without starting the worker.
   ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-  version_->SendMessage(TestMsg_Message(),
-                        CreateReceiverOnCurrentThread(&status));
+  version_->SetStatus(ServiceWorkerVersion::INSTALLING);
+  version_->DispatchInstallEvent(-1, CreateReceiverOnCurrentThread(&status));
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(SERVICE_WORKER_OK, status);
 
   // The worker should be now started.
   EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
 
-  // Stop the worker, and then send the message immediately.
-  ServiceWorkerStatusCode msg_status = SERVICE_WORKER_ERROR_FAILED;
+  // Stop the worker, and then dispatch an event immediately after that.
+  status = SERVICE_WORKER_ERROR_FAILED;
   ServiceWorkerStatusCode stop_status = SERVICE_WORKER_ERROR_FAILED;
   version_->StopWorker(CreateReceiverOnCurrentThread(&stop_status));
-  version_->SendMessage(TestMsg_Message(),
-                       CreateReceiverOnCurrentThread(&msg_status));
+  version_->DispatchInstallEvent(
+      -1, CreateReceiverOnCurrentThread(&status));
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(SERVICE_WORKER_OK, stop_status);
 
-  // SendMessage should return SERVICE_WORKER_OK since the worker should have
-  // been restarted to deliver the message.
-  EXPECT_EQ(SERVICE_WORKER_OK, msg_status);
+  // Dispatch an event should return SERVICE_WORKER_OK since the worker
+  // should have been restarted to dispatch the event.
+  EXPECT_EQ(SERVICE_WORKER_OK, status);
 
   // The worker should be now started again.
   EXPECT_EQ(ServiceWorkerVersion::RUNNING, version_->running_status());
diff --git a/content/browser/speech/speech_recognition_browsertest.cc b/content/browser/speech/speech_recognition_browsertest.cc
index 62b22ad23..8bc0749f 100644
--- a/content/browser/speech/speech_recognition_browsertest.cc
+++ b/content/browser/speech/speech_recognition_browsertest.cc
@@ -94,7 +94,7 @@
   }
 
   std::string GetPageFragment() {
-    return shell()->web_contents()->GetURL().ref();
+    return shell()->web_contents()->GetLastCommittedURL().ref();
   }
 
   const StreamingServerState &streaming_server_state() {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index ede1642..5d51ed1 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -108,6 +108,7 @@
 #if defined(OS_ANDROID)
 #include "content/browser/android/content_video_view.h"
 #include "content/browser/android/date_time_chooser_android.h"
+#include "content/browser/android/media_players_observer.h"
 #include "content/browser/media/android/browser_media_player_manager.h"
 #include "content/browser/web_contents/web_contents_android.h"
 #endif
@@ -358,7 +359,6 @@
       geolocation_service_context_(new GeolocationServiceContext()),
       accessibility_mode_(
           BrowserAccessibilityStateImpl::GetInstance()->accessibility_mode()),
-      audio_stream_monitor_(this),
       virtual_keyboard_requested_(false),
       loading_weak_factory_(this) {
   frame_tree_.SetFrameRemoveListener(
@@ -367,6 +367,12 @@
 #if defined(ENABLE_BROWSER_CDMS)
   media_web_contents_observer_.reset(new MediaWebContentsObserver(this));
 #endif
+
+#if defined(OS_ANDROID)
+  audio_state_provider_.reset(new MediaPlayersObserver(this));
+#else
+  audio_state_provider_.reset(new AudioStreamMonitor(this));
+#endif
 }
 
 WebContentsImpl::~WebContentsImpl() {
@@ -1041,7 +1047,7 @@
   // Create and release the audio power save blocker depending on whether the
   // tab is actively producing audio or not.
   if ((changed_flags & INVALIDATE_TYPE_TAB) &&
-      AudioStreamMonitor::monitoring_available()) {
+      audio_state_provider_->IsAudioStateAvailable()) {
     if (WasRecentlyAudible()) {
       if (!audio_power_save_blocker_)
         CreateAudioPowerSaveBlocker();
@@ -1272,6 +1278,13 @@
     RenderViewCreated(GetRenderViewHost());
     GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true);
   }
+
+  // Ensure that observers are notified of the creation of this WebContents's
+  // main RenderFrameHost. It must be done here for main frames, since the
+  // NotifySwappedFromRenderManager expects view_ to already be created and that
+  // happens after RenderFrameHostManager::Init.
+  NotifySwappedFromRenderManager(
+      nullptr, GetRenderManager()->current_frame_host(), true);
 }
 
 void WebContentsImpl::OnWebContentsDestroyed(WebContentsImpl* web_contents) {
@@ -2516,7 +2529,7 @@
 }
 
 bool WebContentsImpl::WasRecentlyAudible() {
-  return audio_stream_monitor_.WasRecentlyAudible();
+  return audio_state_provider_->WasRecentlyAudible();
 }
 
 void WebContentsImpl::GetManifest(const GetManifestCallback& callback) {
@@ -3203,7 +3216,7 @@
   // monitoring, release the audio power save blocker here instead of during
   // NotifyNavigationStateChanged().
   if (active_audio_players_.empty() &&
-      !AudioStreamMonitor::monitoring_available()) {
+      !audio_state_provider_->IsAudioStateAvailable()) {
     audio_power_save_blocker_.reset();
   }
 
@@ -3226,7 +3239,7 @@
     // If we don't have audio stream monitoring, allocate the audio power save
     // blocker here instead of during NotifyNavigationStateChanged().
     if (!audio_power_save_blocker_ &&
-        !AudioStreamMonitor::monitoring_available()) {
+        !audio_state_provider_->IsAudioStateAvailable()) {
       CreateAudioPowerSaveBlocker();
     }
   }
@@ -4184,7 +4197,7 @@
                                                      RenderFrameHost* new_host,
                                                      bool is_main_frame) {
   if (is_main_frame) {
-    NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : NULL,
+    NotifyViewSwapped(old_host ? old_host->GetRenderViewHost() : nullptr,
                       new_host->GetRenderViewHost());
 
     // Make sure the visible RVH reflects the new delegate's preferences.
@@ -4197,6 +4210,12 @@
   NotifyFrameSwapped(old_host, new_host);
 }
 
+void WebContentsImpl::NotifyMainFrameSwappedFromRenderManager(
+    RenderViewHost* old_host,
+    RenderViewHost* new_host) {
+  NotifyViewSwapped(old_host, new_host);
+}
+
 int WebContentsImpl::CreateOpenerRenderViewsForRenderManager(
     SiteInstance* instance) {
   if (!opener_)
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ae57bea4..2e0e9661 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -22,7 +22,7 @@
 #include "content/browser/frame_host/navigator_delegate.h"
 #include "content/browser/frame_host/render_frame_host_delegate.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
-#include "content/browser/media/audio_stream_monitor.h"
+#include "content/browser/media/audio_state_provider.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
 #include "content/browser/renderer_host/render_widget_host_delegate.h"
 #include "content/common/accessibility_mode_enums.h"
@@ -568,6 +568,9 @@
   void NotifySwappedFromRenderManager(RenderFrameHost* old_host,
                                       RenderFrameHost* new_host,
                                       bool is_main_frame) override;
+  void NotifyMainFrameSwappedFromRenderManager(
+      RenderViewHost* old_host,
+      RenderViewHost* new_host) override;
   int CreateOpenerRenderViewsForRenderManager(SiteInstance* instance) override;
   NavigationControllerImpl& GetControllerForRenderManager() override;
   scoped_ptr<WebUIImpl> CreateWebUIForRenderManager(const GURL& url) override;
@@ -666,8 +669,8 @@
   // Forces overscroll to be disabled (used by touch emulation).
   void SetForceDisableOverscrollContent(bool force_disable);
 
-  AudioStreamMonitor* audio_stream_monitor() {
-    return &audio_stream_monitor_;
+  AudioStateProvider* audio_state_provider() {
+    return audio_state_provider_.get();
   }
 
   bool has_audio_power_save_blocker_for_testing() const {
@@ -1022,6 +1025,11 @@
   scoped_ptr<PowerSaveBlocker> audio_power_save_blocker_;
   scoped_ptr<PowerSaveBlocker> video_power_save_blocker_;
 
+  // Tells whether this WebContents is actively producing sound.
+  // Order is important: the |frame_tree_| destruction uses
+  // |audio_state_provider_|.
+  scoped_ptr<AudioStateProvider> audio_state_provider_;
+
   // Manages the frame tree of the page and process swaps in each node.
   FrameTree frame_tree_;
 
@@ -1236,9 +1244,6 @@
   // is created, and broadcast to all frames when it changes.
   AccessibilityMode accessibility_mode_;
 
-  // Monitors power levels for audio streams associated with this WebContents.
-  AudioStreamMonitor audio_stream_monitor_;
-
   // Created on-demand to mute all audio output from this WebContents.
   scoped_ptr<WebContentsAudioMuter> audio_muter_;
 
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index da3c82e..187f3c4 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -9,7 +9,7 @@
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/media/audio_stream_monitor.h"
+#include "content/browser/media/audio_state_provider.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/web_ui_controller_factory_registry.h"
@@ -2891,20 +2891,20 @@
   EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
 
   TestRenderFrameHost* rfh = contents()->GetMainFrame();
-  AudioStreamMonitor* monitor = contents()->audio_stream_monitor();
+  AudioStateProvider* audio_state = contents()->audio_state_provider();
 
   // The audio power save blocker should not be based on having a media player
   // when audio stream monitoring is available.
-  if (AudioStreamMonitor::monitoring_available()) {
+  if (audio_state->IsAudioStateAvailable()) {
     // Send a fake audio stream monitor notification.  The audio power save
     // blocker should be created.
-    monitor->set_was_recently_audible_for_testing(true);
+    audio_state->set_was_recently_audible_for_testing(true);
     contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
     EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
 
     // Send another fake notification, this time when WasRecentlyAudible() will
     // be false.  The power save blocker should be released.
-    monitor->set_was_recently_audible_for_testing(false);
+    audio_state->set_was_recently_audible_for_testing(false);
     contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
     EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
   }
@@ -2916,7 +2916,7 @@
       0, kPlayerAudioVideoId, true, true, false));
   EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Upon hiding the video power save blocker should be released.
   contents()->WasHidden();
@@ -2929,7 +2929,7 @@
       0, kPlayerVideoOnlyId, true, false, false));
   EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Showing the WebContents should result in the creation of the blocker.
   contents()->WasShown();
@@ -2941,7 +2941,7 @@
       0, kPlayerAudioOnlyId, false, true, false));
   EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Start a remote player. There should be no change in the power save
   // blockers.
@@ -2949,7 +2949,7 @@
       0, kPlayerRemoteId, true, true, true));
   EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Destroy the original audio video player.  Both power save blockers should
   // remain.
@@ -2957,7 +2957,7 @@
       FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
   EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Destroy the audio only player.  The video power save blocker should remain.
   rfh->OnMessageReceived(
@@ -2984,7 +2984,7 @@
       0, kPlayerAudioVideoId, true, true, false));
   EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
   EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
-            !AudioStreamMonitor::monitoring_available());
+            !audio_state->IsAudioStateAvailable());
 
   // Crash the renderer.
   contents()->GetMainFrame()->OnMessageReceived(
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index a9ca4b86..c3b5b62 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -212,6 +212,8 @@
   IPC_STRUCT_TRAITS_MEMBER(allow_download)
   IPC_STRUCT_TRAITS_MEMBER(ui_timestamp)
   IPC_STRUCT_TRAITS_MEMBER(report_type)
+  IPC_STRUCT_TRAITS_MEMBER(base_url_for_data_url)
+  IPC_STRUCT_TRAITS_MEMBER(history_url_for_data_url)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(content::BeginNavigationParams)
@@ -284,14 +286,6 @@
   // succesful when the navigation commits.
   IPC_STRUCT_MEMBER(bool, should_clear_history_list)
 
-  // Base URL for use in WebKit's SubstituteData.
-  // Is only used with data: URLs.
-  IPC_STRUCT_MEMBER(GURL, base_url_for_data_url)
-
-  // History URL for use in WebKit's SubstituteData.
-  // Is only used with data: URLs.
-  IPC_STRUCT_MEMBER(GURL, history_url_for_data_url)
-
   // Any redirect URLs that occurred before |url|. Useful for cross-process
   // navigations; defaults to empty.
   IPC_STRUCT_MEMBER(std::vector<GURL>, redirects)
diff --git a/content/common/gpu/image_transport_surface.cc b/content/common/gpu/image_transport_surface.cc
index 02fbdfa4..b6367dd4 100644
--- a/content/common/gpu/image_transport_surface.cc
+++ b/content/common/gpu/image_transport_surface.cc
@@ -191,8 +191,12 @@
   // GetVsyncValues before SwapBuffers to work around Mali driver bug:
   // crbug.com/223558.
   SendVSyncUpdateIfAvailable();
-  for (auto& latency : latency_info_)
-    latency.AddLatencyNumber(ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0);
+
+  base::TimeTicks swap_time = base::TimeTicks::Now();
+  for (auto& latency : latency_info_) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+  }
 
   // We use WeakPtr here to avoid manual management of life time of an instance
   // of this class. Callback will not be called once the instance of this class
@@ -206,6 +210,13 @@
 bool PassThroughImageTransportSurface::PostSubBuffer(
     int x, int y, int width, int height) {
   SendVSyncUpdateIfAvailable();
+
+  base::TimeTicks swap_time = base::TimeTicks::Now();
+  for (auto& latency : latency_info_) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+  }
+
   // We use WeakPtr here to avoid manual management of life time of an instance
   // of this class. Callback will not be called once the instance of this class
   // is destroyed. However, this also means that the callback can be run on
@@ -216,9 +227,11 @@
 }
 
 void PassThroughImageTransportSurface::SwapBuffersCallBack() {
-  for (size_t i = 0; i < latency_info_.size(); i++) {
-    latency_info_[i].AddLatencyNumber(
-        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
+  base::TimeTicks swap_ack_time = base::TimeTicks::Now();
+  for (auto& latency : latency_info_) {
+    latency.AddLatencyNumberWithTimestamp(
+        ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
+        swap_ack_time, 1);
   }
 
   helper_->stub()->SendSwapBuffersCompleted(latency_info_);
diff --git a/content/common/gpu/image_transport_surface_linux.cc b/content/common/gpu/image_transport_surface_linux.cc
index b648b19..db36efe 100644
--- a/content/common/gpu/image_transport_surface_linux.cc
+++ b/content/common/gpu/image_transport_surface_linux.cc
@@ -13,9 +13,13 @@
     const gfx::GLSurfaceHandle& handle) {
   DCHECK(handle.handle);
   DCHECK(handle.transport_type == gfx::NATIVE_DIRECT);
-  scoped_refptr<gfx::GLSurface> surface =
-      gfx::GLSurface::CreateViewGLSurface(handle.handle);
-  if (!surface.get())
+  scoped_refptr<gfx::GLSurface> surface;
+#if defined(USE_OZONE)
+  surface = gfx::GLSurface::CreateSurfacelessViewGLSurface(handle.handle);
+#endif
+  if (!surface)
+    surface = gfx::GLSurface::CreateViewGLSurface(handle.handle);
+  if (!surface)
     return surface;
   return scoped_refptr<gfx::GLSurface>(new PassThroughImageTransportSurface(
       manager, stub, surface.get()));
diff --git a/content/common/gpu/media/rendering_helper.cc b/content/common/gpu/media/rendering_helper.cc
index cf83611..3ceea1f 100644
--- a/content/common/gpu/media/rendering_helper.cc
+++ b/content/common/gpu/media/rendering_helper.cc
@@ -314,6 +314,9 @@
   message_loop_ = base::MessageLoop::current();
 
   gl_surface_ = gfx::GLSurface::CreateViewGLSurface(window_);
+#if defined(USE_OZONE)
+  gl_surface_->Resize(platform_window_delegate_->GetSize());
+#endif  // defined(USE_OZONE)
   screen_size_ = gl_surface_->GetSize();
 
   gl_context_ = gfx::GLContext::CreateGLContext(
@@ -364,7 +367,8 @@
     CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status;
     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
     glClear(GL_COLOR_BUFFER_BIT);
-    glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+    glBindFramebufferEXT(GL_FRAMEBUFFER,
+                         gl_surface_->GetBackingFrameBufferObject());
   }
 
   // These vertices and texture coords. map (0,0) in the texture to the
@@ -504,6 +508,7 @@
     glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_);
   }
 
+  gl_surface_->Destroy();
   gl_context_->ReleaseCurrent(gl_surface_.get());
   gl_context_ = NULL;
   gl_surface_ = NULL;
@@ -570,7 +575,8 @@
   glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_);
   GLSetViewPort(area);
   RenderTexture(texture_target, texture_id);
-  glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+  glBindFramebufferEXT(GL_FRAMEBUFFER,
+                       gl_surface_->GetBackingFrameBufferObject());
 
   // Need to flush the GL commands before we return the tnumbnail texture to
   // the decoder.
@@ -661,7 +667,8 @@
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                &rgba[0]);
-  glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+  glBindFramebufferEXT(GL_FRAMEBUFFER,
+                       gl_surface_->GetBackingFrameBufferObject());
   rgb->resize(num_pixels * 3);
   // Drop the alpha channel, but check as we go that it is all 0xff.
   bool solid = true;
@@ -698,7 +705,13 @@
         static_cast<base::WaitableEvent*>(NULL)));
   }
 
-  glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
+  int tex_flip = 1;
+#if defined(USE_OZONE)
+  // Ozone surfaceless renders flipped from normal GL, so there's no need to
+  // do an extra flip.
+  tex_flip = 0;
+#endif  // defined(USE_OZONE)
+  glUniform1i(glGetUniformLocation(program_, "tex_flip"), tex_flip);
 
   // Frames that will be returned to the client (via the no_longer_needed_cb)
   // after this vector falls out of scope at the end of this method. We need
diff --git a/content/common/input/input_param_traits.cc b/content/common/input/input_param_traits.cc
index 33769fe0..1f4b7e4 100644
--- a/content/common/input/input_param_traits.cc
+++ b/content/common/input/input_param_traits.cc
@@ -6,6 +6,7 @@
 
 #include "content/common/content_param_traits.h"
 #include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
 #include "content/common/input/web_input_event_traits.h"
 #include "content/common/input_messages.h"
@@ -62,6 +63,10 @@
       WriteParam(m, *content::SyntheticSmoothScrollGestureParams::Cast(
           p.gesture_params()));
       break;
+    case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+      WriteParam(m, *content::SyntheticSmoothDragGestureParams::Cast(
+                 p.gesture_params()));
+      break;
     case content::SyntheticGestureParams::PINCH_GESTURE:
       WriteParam(m, *content::SyntheticPinchGestureParams::Cast(
           p.gesture_params()));
@@ -70,10 +75,6 @@
       WriteParam(m, *content::SyntheticTapGestureParams::Cast(
           p.gesture_params()));
       break;
-    // TODO(ssid): When API and IPC messages are set up, implement this.
-    case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
-      NOTIMPLEMENTED();
-      break;
   }
 }
 
@@ -90,6 +91,10 @@
           ReadGestureParams<content::SyntheticSmoothScrollGestureParams>(m,
                                                                          iter);
       break;
+    case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+      gesture_params =
+          ReadGestureParams<content::SyntheticSmoothDragGestureParams>(m, iter);
+      break;
     case content::SyntheticGestureParams::PINCH_GESTURE:
       gesture_params =
           ReadGestureParams<content::SyntheticPinchGestureParams>(m, iter);
@@ -116,6 +121,11 @@
               p.gesture_params()),
           l);
       break;
+    case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
+      LogParam(
+          *content::SyntheticSmoothDragGestureParams::Cast(p.gesture_params()),
+          l);
+      break;
     case content::SyntheticGestureParams::PINCH_GESTURE:
       LogParam(
           *content::SyntheticPinchGestureParams::Cast(p.gesture_params()),
@@ -126,10 +136,6 @@
           *content::SyntheticTapGestureParams::Cast(p.gesture_params()),
           l);
       break;
-    // TODO(ssid): When API and IPC messages are set up, implement this.
-    case content::SyntheticGestureParams::SMOOTH_DRAG_GESTURE:
-      NOTIMPLEMENTED();
-      break;
   }
 }
 
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 14967b48..5bdda8f 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -17,6 +17,7 @@
 #include "content/common/input/synthetic_gesture_packet.h"
 #include "content/common/input/synthetic_gesture_params.h"
 #include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
 #include "content/common/input/synthetic_tap_gesture_params.h"
 #include "content/common/input/touch_action.h"
@@ -77,6 +78,13 @@
   IPC_STRUCT_TRAITS_MEMBER(gesture_source_type)
 IPC_STRUCT_TRAITS_END()
 
+IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothDragGestureParams)
+  IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams)
+  IPC_STRUCT_TRAITS_MEMBER(start_point)
+  IPC_STRUCT_TRAITS_MEMBER(distances)
+  IPC_STRUCT_TRAITS_MEMBER(speed_in_pixels_s)
+IPC_STRUCT_TRAITS_END()
+
 IPC_STRUCT_TRAITS_BEGIN(content::SyntheticSmoothScrollGestureParams)
   IPC_STRUCT_TRAITS_PARENT(content::SyntheticGestureParams)
   IPC_STRUCT_TRAITS_MEMBER(anchor)
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 4171937..3213337f 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ref_counted_memory.h"
 
 namespace content {
+
 CommonNavigationParams::CommonNavigationParams()
     : transition(ui::PAGE_TRANSITION_LINK),
       navigation_type(FrameMsg_Navigate_Type::NORMAL),
@@ -21,14 +22,18 @@
     FrameMsg_Navigate_Type::Value navigation_type,
     bool allow_download,
     base::TimeTicks ui_timestamp,
-    FrameMsg_UILoadMetricsReportType::Value report_type)
+    FrameMsg_UILoadMetricsReportType::Value report_type,
+    const GURL& base_url_for_data_url,
+    const GURL& history_url_for_data_url)
     : url(url),
       referrer(referrer),
       transition(transition),
       navigation_type(navigation_type),
       allow_download(allow_download),
       ui_timestamp(ui_timestamp),
-      report_type(report_type) {
+      report_type(report_type),
+      base_url_for_data_url(base_url_for_data_url),
+      history_url_for_data_url(history_url_for_data_url) {
 }
 
 CommonNavigationParams::~CommonNavigationParams() {
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index 757d1a7..58e2ca5 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -38,7 +38,9 @@
                          FrameMsg_Navigate_Type::Value navigation_type,
                          bool allow_download,
                          base::TimeTicks ui_timestamp,
-                         FrameMsg_UILoadMetricsReportType::Value report_type);
+                         FrameMsg_UILoadMetricsReportType::Value report_type,
+                         const GURL& base_url_for_data_url,
+                         const GURL& history_url_for_data_url);
   ~CommonNavigationParams();
 
   // The URL to navigate to.
@@ -66,6 +68,14 @@
 
   // The report type to be used when recording the metric using |ui_timestamp|.
   FrameMsg_UILoadMetricsReportType::Value report_type;
+
+  // Base URL for use in Blink's SubstituteData.
+  // Is only used with data: URLs.
+  GURL base_url_for_data_url;
+
+  // History URL for use in Blink's SubstituteData.
+  // Is only used with data: URLs.
+  GURL history_url_for_data_url;
 };
 
 // PlzNavigate: parameters needed to start a navigation on the IO thread.
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index e0afa125..7715d1b 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -355,6 +355,8 @@
       'browser/android/interstitial_page_delegate_android.h',
       'browser/android/load_url_params.cc',
       'browser/android/load_url_params.h',
+      'browser/android/media_players_observer.cc',
+      'browser/android/media_players_observer.h',
       'browser/android/overscroll_controller_android.cc',
       'browser/android/overscroll_controller_android.h',
       'browser/android/overscroll_glow.cc',
@@ -928,6 +930,8 @@
       'browser/media/android/media_drm_credential_manager.h',
       'browser/media/android/media_resource_getter_impl.cc',
       'browser/media/android/media_resource_getter_impl.h',
+      'browser/media/audio_state_provider.cc',
+      'browser/media/audio_state_provider.h',
       'browser/media/audio_stream_monitor.cc',
       'browser/media/audio_stream_monitor.h',
       'browser/media/capture/audio_mirroring_manager.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 602f098a..9d5a2dc 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -99,6 +99,7 @@
       'public/test/test_synchronous_compositor_android.h',
       'public/test/test_utils.cc',
       'public/test/test_utils.h',
+      'public/test/test_web_contents_factory.h',
       'public/test/unittest_test_suite.cc',
       'public/test/unittest_test_suite.h',
       'public/test/web_contents_observer_sanity_checker.cc',
@@ -164,6 +165,7 @@
       'test/test_render_view_host_factory.h',
       'test/test_web_contents.cc',
       'test/test_web_contents.h',
+      'test/test_web_contents_factory.cc',
       'test/web_gesture_curve_mock.cc',
       'test/web_gesture_curve_mock.h',
       'test/web_layer_tree_view_impl_for_testing.cc',
@@ -1118,6 +1120,7 @@
           'sources!': [
             'browser/geolocation/network_location_provider_unittest.cc',
             'browser/geolocation/wifi_data_provider_common_unittest.cc',
+            'browser/media/audio_stream_monitor_unittest.cc',
             'browser/webui/url_data_manager_backend_unittest.cc',
           ],
           'dependencies': [
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index f73bb0d1..b34d42f 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -61,6 +61,7 @@
 
 #if defined(SANITIZER_COVERAGE)
 #include <sanitizer/common_interface_defs.h>
+#include <sanitizer/coverage_interface.h>
 #endif
 
 const int kGpuTimeout = 10000;
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 226e4ea..00ea68a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -5,6 +5,7 @@
 package org.chromium.content.browser;
 
 import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
 import android.app.Activity;
 import android.app.SearchManager;
 import android.content.ClipboardManager;
@@ -2806,6 +2807,7 @@
     /**
      * @see View#onInitializeAccessibilityEvent(AccessibilityEvent)
      */
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         // Note: this is only used by the script-injecting accessibility code.
         event.setClassName(this.getClass().getName());
@@ -2820,9 +2822,7 @@
         int maxScrollYPix = Math.max(0, mRenderCoordinates.getMaxVerticalScrollPixInt());
         event.setScrollable(maxScrollXPix > 0 || maxScrollYPix > 0);
 
-        // Setting the maximum scroll values requires API level 15 or higher.
-        final int sdkVersionRequiredToSetScroll = 15;
-        if (Build.VERSION.SDK_INT >= sdkVersionRequiredToSetScroll) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
             event.setMaxScrollX(maxScrollXPix);
             event.setMaxScrollY(maxScrollYPix);
         }
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
index b77c88ce..b0ebf0c7 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/BrowserAccessibilityManager.java
@@ -4,6 +4,7 @@
 
 package org.chromium.content.browser.accessibility;
 
+import android.annotation.TargetApi;
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Build;
@@ -38,6 +39,7 @@
  * accessibility.
  */
 @JNINamespace("content")
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
 public class BrowserAccessibilityManager {
     private static final String TAG = "BrowserAccessibilityManager";
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java
index abdeae7..67b4dca 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.java
@@ -4,7 +4,9 @@
 
 package org.chromium.content.browser.accessibility;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -22,6 +24,7 @@
  * Handles injecting accessibility Javascript and related Javascript -> Java APIs for JB and newer
  * devices.
  */
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
 class JellyBeanAccessibilityInjector extends AccessibilityInjector {
     private CallbackHandler mCallback;
     private JSONObject mAccessibilityJSONObject;
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java
index 62185c2..98f8863 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content.browser.accessibility;
 
+import android.annotation.TargetApi;
+import android.os.Build;
 import android.os.Bundle;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
@@ -18,6 +20,7 @@
  * AccessibilityNodeProvider and delegates its implementation to this object.
  */
 @JNINamespace("content")
+@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
 public class JellyBeanBrowserAccessibilityManager extends BrowserAccessibilityManager {
     private AccessibilityNodeProvider mAccessibilityNodeProvider;
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java
index d61484fc..d7737eb5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.java
@@ -4,7 +4,9 @@
 
 package org.chromium.content.browser.accessibility;
 
+import android.annotation.TargetApi;
 import android.content.Context;
+import android.os.Build;
 import android.os.Bundle;
 import android.view.View;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -20,6 +22,7 @@
  * Handles injecting accessibility Javascript and related Javascript -> Java APIs for Lollipop and
  * newer devices.
  */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class LollipopAccessibilityInjector extends JellyBeanAccessibilityInjector {
     /**
      * Constructs an instance of the LollipopAccessibilityInjector.
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java
index a966ed6..f5c3af1 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content.browser.accessibility;
 
+import android.annotation.TargetApi;
+import android.os.Build;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -17,6 +19,7 @@
  * AccessibilityNodeProvider and delegates its implementation to this object.
  */
 @JNINamespace("content")
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
 public class LollipopBrowserAccessibilityManager extends JellyBeanBrowserAccessibilityManager {
     LollipopBrowserAccessibilityManager(long nativeBrowserAccessibilityManagerAndroid,
             ContentViewCore contentViewCore) {
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 3b7d13b58..8d9bd67 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -844,6 +844,9 @@
 // Use the new surfaces system to handle compositor delegation.
 const char kUseSurfaces[] = "use-surfaces";
 
+// Disable the use of the new surfaces system to handle compositor delegation.
+const char kDisableSurfaces[] = "disable-surfaces";
+
 // The contents of this flag are prepended to the utility process command line.
 // Useful values might be "valgrind" or "xterm -e gdb --args".
 const char kUtilityCmdPrefix[]              = "utility-cmd-prefix";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index f792770d..a248681 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -231,6 +231,7 @@
 CONTENT_EXPORT extern const char kUseMobileUserAgent[];
 CONTENT_EXPORT extern const char kUseNormalPriorityForTileTaskWorkerThreads[];
 extern const char kUseSurfaces[];
+CONTENT_EXPORT extern const char kDisableSurfaces[];
 extern const char kUtilityCmdPrefix[];
 CONTENT_EXPORT extern const char kUtilityProcess[];
 extern const char kUtilityProcessAllowedDir[];
diff --git a/content/public/test/test_web_contents_factory.h b/content/public/test/test_web_contents_factory.h
new file mode 100644
index 0000000..8b48f9ef
--- /dev/null
+++ b/content/public/test/test_web_contents_factory.h
@@ -0,0 +1,52 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_
+#define CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+
+namespace content {
+class BrowserContext;
+class RenderViewHostTestEnabler;
+class WebContents;
+
+// A helper class to create test web contents (tabs) for unit tests, without
+// inheriting from RenderViewTestHarness. Can create web contents, and will
+// clean up after itself upon destruction. Owns all created web contents.
+// A few notes:
+// - Works well allocated on the stack, because it should be destroyed before
+//   associated browser context.
+// - Doesn't play nice with web contents created any other way (because of
+//   the implementation of RenderViewHostTestEnabler). But if you are creating
+//   web contents already, what do you need this for? ;)
+// TODO(devlin): The API is currently a bit sparse; there may need to be methods
+// to, e.g., delete/close a web contents, access existing web contents, etc.
+// These can be added as-needed.
+class TestWebContentsFactory {
+ public:
+  TestWebContentsFactory();
+  ~TestWebContentsFactory();
+
+  // Creates a new WebContents with the given |context|, and returns it.
+  // Ownership remains with the TestWebContentsFactory.
+  WebContents* CreateWebContents(BrowserContext* context);
+
+ private:
+  // The test factory (and friends) for creating test web contents.
+  scoped_ptr<RenderViewHostTestEnabler> rvh_enabler_;
+
+  // The vector of web contents that this class created.
+  ScopedVector<WebContents> web_contents_;
+
+  // True if the factory initialized aura (and should thus tear it down).
+  bool tear_down_aura_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestWebContentsFactory);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_TEST_TEST_WEB_CONTENTS_FACTORY_H_
diff --git a/content/public/test/web_contents_observer_sanity_checker.cc b/content/public/test/web_contents_observer_sanity_checker.cc
index e59998b..9b0fdcc 100644
--- a/content/public/test/web_contents_observer_sanity_checker.cc
+++ b/content/public/test/web_contents_observer_sanity_checker.cc
@@ -4,7 +4,6 @@
 
 #include "content/public/test/web_contents_observer_sanity_checker.h"
 
-#include "base/debug/stack_trace.h"
 #include "base/strings/stringprintf.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/render_frame_host.h"
@@ -80,8 +79,27 @@
   CHECK(new_host);
   CHECK_NE(new_host, old_host);
 
-  // TODO(nasko): Implement consistency checking for RenderFrameHostChanged
-  // in follow up CL.
+  if (old_host) {
+    std::pair<int, int> routing_pair =
+        std::make_pair(old_host->GetProcess()->GetID(),
+                       old_host->GetRoutingID());
+    bool old_did_exist = !!current_hosts_.erase(routing_pair);
+    if (!old_did_exist) {
+      CHECK(false)
+          << "RenderFrameHostChanged called with old host that did not exist:"
+          << Format(old_host);
+    }
+  }
+
+  std::pair<int, int> routing_pair =
+      std::make_pair(new_host->GetProcess()->GetID(),
+                     new_host->GetRoutingID());
+  bool host_exists = !current_hosts_.insert(routing_pair).second;
+  if (host_exists) {
+    CHECK(false)
+        << "RenderFrameHostChanged called more than once for routing pair:"
+        << Format(new_host);
+  }
 }
 
 void WebContentsObserverSanityChecker::FrameDeleted(
diff --git a/content/public/test/web_contents_observer_sanity_checker.h b/content/public/test/web_contents_observer_sanity_checker.h
index b8c3b61..2fab3ab 100644
--- a/content/public/test/web_contents_observer_sanity_checker.h
+++ b/content/public/test/web_contents_observer_sanity_checker.h
@@ -87,6 +87,7 @@
   void AssertRenderFrameExists(RenderFrameHost* render_frame_host);
   void AssertMainFrameExists();
 
+  std::set<std::pair<int, int>> current_hosts_;
   std::set<std::pair<int, int>> live_routes_;
   std::set<std::pair<int, int>> deleted_routes_;
 
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index 68221886..1f2369d 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -14,6 +14,7 @@
 #include "cc/layers/layer.h"
 #include "content/common/input/synthetic_gesture_params.h"
 #include "content/common/input/synthetic_pinch_gesture_params.h"
+#include "content/common/input/synthetic_smooth_drag_gesture_params.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
 #include "content/common/input/synthetic_tap_gesture_params.h"
 #include "content/public/child/v8_value_converter.h"
@@ -381,6 +382,48 @@
   return true;
 }
 
+bool BeginSmoothDrag(v8::Isolate* isolate,
+                     float start_x,
+                     float start_y,
+                     float end_x,
+                     float end_y,
+                     v8::Handle<v8::Function> callback,
+                     int gesture_source_type,
+                     int speed_in_pixels_s) {
+  GpuBenchmarkingContext context;
+  if (!context.Init(false))
+    return false;
+  scoped_refptr<CallbackAndContext> callback_and_context =
+      new CallbackAndContext(isolate, callback,
+                             context.web_frame()->mainWorldScriptContext());
+
+  scoped_ptr<SyntheticSmoothDragGestureParams> gesture_params(
+      new SyntheticSmoothDragGestureParams);
+
+  // Convert coordinates from CSS pixels to density independent pixels (DIPs).
+  float page_scale_factor = context.web_view()->pageScaleFactor();
+
+  gesture_params->start_point.SetPoint(start_x * page_scale_factor,
+                                       start_y * page_scale_factor);
+  gfx::PointF end_point(end_x * page_scale_factor,
+                        end_y * page_scale_factor);
+  gfx::Vector2dF distance = gesture_params->start_point - end_point;
+  gesture_params->distances.push_back(distance);
+  gesture_params->speed_in_pixels_s = speed_in_pixels_s * page_scale_factor;
+  gesture_params->gesture_source_type =
+      static_cast<SyntheticGestureParams::GestureSourceType>(
+          gesture_source_type);
+
+  // TODO(nduca): If the render_view_impl is destroyed while the gesture is in
+  // progress, we will leak the callback and context. This needs to be fixed,
+  // somehow.
+  context.render_view_impl()->QueueSyntheticGesture(
+      gesture_params.Pass(),
+      base::Bind(&OnSyntheticGestureCompleted, callback_and_context));
+
+  return true;
+}
+
 }  // namespace
 
 gin::WrapperInfo GpuBenchmarking::kWrapperInfo = {gin::kEmbedderNativeGin};
@@ -425,6 +468,7 @@
       .SetMethod("gestureSourceTypeSupported",
                  &GpuBenchmarking::GestureSourceTypeSupported)
       .SetMethod("smoothScrollBy", &GpuBenchmarking::SmoothScrollBy)
+      .SetMethod("smoothDrag", &GpuBenchmarking::SmoothDrag)
       .SetMethod("swipe", &GpuBenchmarking::Swipe)
       .SetMethod("scrollBounce", &GpuBenchmarking::ScrollBounce)
       // TODO(dominikg): Remove once JS interface changes have rolled into
@@ -529,6 +573,39 @@
                            start_y);
 }
 
+bool GpuBenchmarking::SmoothDrag(gin::Arguments* args) {
+  GpuBenchmarkingContext context;
+  if (!context.Init(true))
+    return false;
+
+  float start_x;
+  float start_y;
+  float end_x;
+  float end_y;
+  v8::Handle<v8::Function> callback;
+  int gesture_source_type = SyntheticGestureParams::DEFAULT_INPUT;
+  int speed_in_pixels_s = 800;
+
+  if (!GetArg(args, &start_x) ||
+      !GetArg(args, &start_y) ||
+      !GetArg(args, &end_x) ||
+      !GetArg(args, &end_y) ||
+      !GetOptionalArg(args, &callback) ||
+      !GetOptionalArg(args, &gesture_source_type) ||
+      !GetOptionalArg(args, &speed_in_pixels_s)) {
+    return false;
+  }
+
+  return BeginSmoothDrag(args->isolate(),
+                         start_x,
+                         start_y,
+                         end_x,
+                         end_y,
+                         callback,
+                         gesture_source_type,
+                         speed_in_pixels_s);
+}
+
 bool GpuBenchmarking::Swipe(gin::Arguments* args) {
   GpuBenchmarkingContext context;
   if (!context.Init(true))
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.h b/content/renderer/gpu/gpu_benchmarking_extension.h
index 33e10ea..bbfb015b 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.h
+++ b/content/renderer/gpu/gpu_benchmarking_extension.h
@@ -45,6 +45,7 @@
   void PrintToSkPicture(v8::Isolate* isolate, const std::string& dirname);
   bool GestureSourceTypeSupported(int gesture_source_type);
   bool SmoothScrollBy(gin::Arguments* args);
+  bool SmoothDrag(gin::Arguments* args);
   bool Swipe(gin::Arguments* args);
   bool ScrollBounce(gin::Arguments* args);
   bool PinchBy(gin::Arguments* args);
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index a5bf0b61..25813a179 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -152,7 +152,8 @@
         encrypted_media_init_data_cb,
     const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
     const UpdateNetworkStateCB& update_network_state_cb,
-    const DurationChangeCB& duration_change_cb) {
+    const DurationChangeCB& duration_change_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
   DCHECK(!media_source_opened_cb.is_null());
   media_source_opened_cb_ = media_source_opened_cb;
@@ -160,6 +161,7 @@
   set_decryptor_ready_cb_ = media::BindToCurrentLoop(set_decryptor_ready_cb);
   update_network_state_cb_ = media::BindToCurrentLoop(update_network_state_cb);
   duration_change_cb_ = duration_change_cb;
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
   access_unit_size_ = kAccessUnitSizeForMediaSource;
 
   chunk_demuxer_.reset(new media::ChunkDemuxer(
@@ -521,7 +523,8 @@
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
   audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, set_decryptor_ready_cb_));
+      media_task_runner_, set_decryptor_ready_cb_,
+      waiting_for_decryption_key_cb_));
   audio_decrypting_demuxer_stream_->Initialize(
       audio_stream_,
       base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
@@ -534,7 +537,8 @@
   DCHECK(!set_decryptor_ready_cb_.is_null());
 
   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, set_decryptor_ready_cb_));
+      media_task_runner_, set_decryptor_ready_cb_,
+      waiting_for_decryption_key_cb_));
   video_decrypting_demuxer_stream_->Initialize(
       video_stream_,
       base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
diff --git a/content/renderer/media/android/media_source_delegate.h b/content/renderer/media/android/media_source_delegate.h
index c8eaade..666b380 100644
--- a/content/renderer/media/android/media_source_delegate.h
+++ b/content/renderer/media/android/media_source_delegate.h
@@ -62,7 +62,8 @@
           encrypted_media_init_data_cb,
       const media::SetDecryptorReadyCB& set_decryptor_ready_cb,
       const UpdateNetworkStateCB& update_network_state_cb,
-      const DurationChangeCB& duration_change_cb);
+      const DurationChangeCB& duration_change_cb,
+      const base::Closure& waiting_for_decryption_key_cb);
 
   blink::WebTimeRanges Buffered() const;
   size_t DecodedFrameCount() const;
@@ -198,6 +199,7 @@
 
   MediaSourceOpenedCB media_source_opened_cb_;
   media::Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // Temporary for EME v0.1. In the future the init data type should be passed
   // through GenerateKeyRequest() directly from WebKit.
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index fe32f058..d3b0dcb 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -313,6 +313,8 @@
           base::Bind(&WebMediaPlayerAndroid::UpdateNetworkState,
                      weak_factory_.GetWeakPtr()),
           base::Bind(&WebMediaPlayerAndroid::OnDurationChanged,
+                     weak_factory_.GetWeakPtr()),
+          base::Bind(&WebMediaPlayerAndroid::OnWaitingForDecryptionKey,
                      weak_factory_.GetWeakPtr()));
       InitializePlayer(url_, frame_->document().firstPartyForCookies(),
                        true, demuxer_client_id);
@@ -1759,6 +1761,15 @@
                      vector_as_array(&init_data), init_data.size());
 }
 
+void WebMediaPlayerAndroid::OnWaitingForDecryptionKey() {
+  client_->didBlockPlaybackWaitingForKey();
+
+  // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
+  // when a key has been successfully added (e.g. OnSessionKeysChange() with
+  // |has_additional_usable_key| = true). http://crbug.com/461903
+  client_->didResumePlaybackBlockedForKey();
+}
+
 void WebMediaPlayerAndroid::SetCdmInternal(
     const media::CdmAttachedCB& cdm_attached_cb) {
   DCHECK(cdm_context_ && is_player_initialized_);
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 314d7ee..8d18a26 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -258,6 +258,10 @@
   void OnEncryptedMediaInitData(const std::string& init_data_type,
                                 const std::vector<uint8>& init_data);
 
+  // Called when a decoder detects that the key needed to decrypt the stream
+  // is not available.
+  void OnWaitingForDecryptionKey();
+
  protected:
   // Helper method to update the playing state.
   void UpdatePlayingState(bool is_playing_);
diff --git a/content/renderer/media/peer_connection_tracker.cc b/content/renderer/media/peer_connection_tracker.cc
index 2075cdd0..dd970ba 100644
--- a/content/renderer/media/peer_connection_tracker.cc
+++ b/content/renderer/media/peer_connection_tracker.cc
@@ -217,7 +217,7 @@
 
   for (const auto& v : report.values()) {
     values->AppendString(v->display_name());
-    values->AppendString(v->value);
+    values->AppendString(v->ToString());
   }
 
   return dict;
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index da93384f..e758685 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -409,7 +409,7 @@
     for (const auto& value : report.values) {
       response->addStatistic(idx,
           blink::WebString::fromUTF8(value->display_name()),
-          blink::WebString::fromUTF8(value->value));
+          blink::WebString::fromUTF8(value->ToString()));
     }
   }
 
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 47e05b5b..1e3667f 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1093,22 +1093,8 @@
       CHECK(entry->root().urlString() != WebString::fromUTF8(kSwappedOutURL));
       render_view_->history_controller()->GoToEntry(entry.Pass(), cache_policy);
     }
-  } else if (!params.base_url_for_data_url.is_empty()) {
-    // A loadData request with a specified base URL.
-    std::string mime_type, charset, data;
-    if (net::DataURL::Parse(
-            params.common_params.url, &mime_type, &charset, &data)) {
-      frame->loadData(
-          WebData(data.c_str(), data.length()),
-          WebString::fromUTF8(mime_type),
-          WebString::fromUTF8(charset),
-          params.base_url_for_data_url,
-          params.history_url_for_data_url,
-          false);
-    } else {
-      CHECK(false) << "Invalid URL passed: "
-                   << params.common_params.url.possibly_invalid_spec();
-    }
+  } else if (!params.common_params.base_url_for_data_url.is_empty()) {
+    LoadDataURL(params.common_params, frame);
   } else {
     // Navigate to the given URL.
     WebURLRequest request =
@@ -3629,8 +3615,8 @@
   // VisibilityState remain a page-level concept or move to frames?
   // The semantics of 'Show' might have to change here.
   if (render_widget_) {
-    render_view()->webview()->setVisibilityState(
-        blink::WebPageVisibilityStateVisible, false);
+    static_cast<blink::WebFrameWidget*>(render_widget_->webwidget())->
+        setVisibilityState(blink::WebPageVisibilityStateVisible, false);
   }
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, WasShown());
 }
@@ -3884,6 +3870,12 @@
 
   GetContentClient()->SetActiveURL(common_params.url);
 
+  if (!common_params.base_url_for_data_url.is_empty() ||
+      common_params.url.SchemeIs(url::kDataScheme)) {
+    LoadDataURL(common_params, frame_);
+    return;
+  }
+
   // Create a WebURLRequest that blink can use to get access to the body of the
   // response through a stream in the browser. Blink will then commit the
   // navigation.
@@ -4379,6 +4371,26 @@
         GetRequestBodyForWebURLRequest(*request)));
 }
 
+void RenderFrameImpl::LoadDataURL(const CommonNavigationParams& params,
+                                  WebFrame* frame) {
+  // A loadData request with a specified base URL.
+  std::string mime_type, charset, data;
+  if (net::DataURL::Parse(params.url, &mime_type, &charset, &data)) {
+    const GURL base_url = params.base_url_for_data_url.is_empty() ?
+        params.url : params.base_url_for_data_url;
+    frame->loadData(
+        WebData(data.c_str(), data.length()),
+        WebString::fromUTF8(mime_type),
+        WebString::fromUTF8(charset),
+        base_url,
+        params.history_url_for_data_url,
+        false);
+  } else {
+    CHECK(false) << "Invalid URL passed: "
+                 << params.url.possibly_invalid_spec();
+  }
+}
+
 GURL RenderFrameImpl::GetLoadingUrl() const {
   WebDataSource* ds = frame_->dataSource();
   if (ds->hasUnreachableURL())
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 9512149..327d850 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -710,6 +710,10 @@
   // of the WebURLRequest.
   void BeginNavigation(blink::WebURLRequest* request);
 
+  // Loads a data url.
+  void LoadDataURL(const CommonNavigationParams& params,
+                   blink::WebFrame* frame);
+
   // Returns the URL being loaded by the |frame_|'s request.
   GURL GetLoadingUrl() const;
 
diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
index f2f6a569..4a97a045 100644
--- a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
+++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
@@ -338,9 +338,9 @@
   base::TimeTicks deadline_in_task;
   int run_count = 0;
 
-  default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
   idle_task_runner_->PostIdleTaskAfterWakeup(
       FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+  default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
 
   RunUntilIdle();
   EnableIdleTasks();  // Must start a new idle period before idle task runs.
diff --git a/content/renderer/scheduler/task_queue_manager.cc b/content/renderer/scheduler/task_queue_manager.cc
index f4f8fc5f..0b88d5a 100644
--- a/content/renderer/scheduler/task_queue_manager.cc
+++ b/content/renderer/scheduler/task_queue_manager.cc
@@ -43,7 +43,7 @@
   void PumpQueue();
 
   bool UpdateWorkQueue(base::TimeTicks* next_pending_delayed_task,
-                       TaskQueueManager::WorkQueueUpdateEventType event_type);
+                       const base::PendingTask* previous_task);
   base::PendingTask TakeTaskFromWorkQueue();
 
   void WillDeleteTaskQueueManager();
@@ -73,8 +73,8 @@
   void EnqueueTask(const base::PendingTask& pending_task);
 
   void PumpQueueLocked();
-  bool ShouldAutoPumpQueueLocked(
-      TaskQueueManager::WorkQueueUpdateEventType event_type);
+  bool TaskIsOlderThanQueuedTasks(const base::PendingTask* task);
+  bool ShouldAutoPumpQueueLocked(const base::PendingTask* previous_task);
   void EnqueueTaskLocked(const base::PendingTask& pending_task);
 
   void TraceQueueSize(bool is_locked) const;
@@ -153,13 +153,35 @@
   }
 }
 
+bool TaskQueue::TaskIsOlderThanQueuedTasks(const base::PendingTask* task) {
+  lock_.AssertAcquired();
+  // A null task is passed when UpdateQueue is called before any task is run.
+  // In this case we don't want to pump an after_wakeup queue, so return true
+  // here.
+  if (!task)
+    return true;
+
+  // Return false if there are no task in the incoming queue.
+  if (incoming_queue_.empty())
+    return false;
+
+  base::PendingTask oldest_queued_task = incoming_queue_.front();
+  DCHECK(oldest_queued_task.delayed_run_time.is_null());
+  DCHECK(task->delayed_run_time.is_null());
+
+  // Note: the comparison is correct due to the fact that the PendingTask
+  // operator inverts its comparison operation in order to work well in a heap
+  // based priority queue.
+  return oldest_queued_task < *task;
+}
+
 bool TaskQueue::ShouldAutoPumpQueueLocked(
-    TaskQueueManager::WorkQueueUpdateEventType event_type) {
+    const base::PendingTask* previous_task) {
   lock_.AssertAcquired();
   if (pump_policy_ == TaskQueueManager::PumpPolicy::MANUAL)
     return false;
   if (pump_policy_ == TaskQueueManager::PumpPolicy::AFTER_WAKEUP &&
-      event_type != TaskQueueManager::WorkQueueUpdateEventType::AFTER_WAKEUP)
+      TaskIsOlderThanQueuedTasks(previous_task))
     return false;
   if (incoming_queue_.empty())
     return false;
@@ -168,7 +190,7 @@
 
 bool TaskQueue::UpdateWorkQueue(
     base::TimeTicks* next_pending_delayed_task,
-    TaskQueueManager::WorkQueueUpdateEventType event_type) {
+    const base::PendingTask* previous_task) {
   if (!work_queue_.empty())
     return true;
 
@@ -178,7 +200,7 @@
       *next_pending_delayed_task =
           std::min(*next_pending_delayed_task, delayed_task_run_times_.top());
     }
-    if (!ShouldAutoPumpQueueLocked(event_type))
+    if (!ShouldAutoPumpQueueLocked(previous_task))
       return false;
     work_queue_.Swap(&incoming_queue_);
     TraceQueueSize(true);
@@ -383,14 +405,15 @@
 
 bool TaskQueueManager::UpdateWorkQueues(
     base::TimeTicks* next_pending_delayed_task,
-    WorkQueueUpdateEventType event_type) {
+    const base::PendingTask* previous_task) {
   // TODO(skyostil): This is not efficient when the number of queues grows very
   // large due to the number of locks taken. Consider optimizing when we get
   // there.
   DCHECK(main_thread_checker_.CalledOnValidThread());
   bool has_work = false;
   for (auto& queue : queues_) {
-    has_work |= queue->UpdateWorkQueue(next_pending_delayed_task, event_type);
+    has_work |= queue->UpdateWorkQueue(next_pending_delayed_task,
+                                       previous_task);
     if (!queue->work_queue().empty()) {
       // Currently we should not be getting tasks with delayed run times in any
       // of the work queues.
@@ -426,8 +449,9 @@
   base::TimeTicks next_pending_delayed_task(
       base::TimeTicks::FromInternalValue(kMaxTimeTicks));
 
-  if (!UpdateWorkQueues(&next_pending_delayed_task,
-                        WorkQueueUpdateEventType::BEFORE_WAKEUP))
+  // Pass nullptr to UpdateWorkQueues here to prevent waking up an
+  // pump-after-wakeup queue.
+  if (!UpdateWorkQueues(&next_pending_delayed_task, nullptr))
     return;
 
   base::PendingTask previous_task((tracked_objects::Location()),
@@ -446,8 +470,7 @@
     MaybePostDoWorkOnMainRunner();
     ProcessTaskFromWorkQueue(queue_index, i > 0, &previous_task);
 
-    if (!UpdateWorkQueues(&next_pending_delayed_task,
-                          WorkQueueUpdateEventType::AFTER_WAKEUP))
+    if (!UpdateWorkQueues(&next_pending_delayed_task, &previous_task))
       return;
   }
 }
diff --git a/content/renderer/scheduler/task_queue_manager.h b/content/renderer/scheduler/task_queue_manager.h
index 79df04d..8f32b93a 100644
--- a/content/renderer/scheduler/task_queue_manager.h
+++ b/content/renderer/scheduler/task_queue_manager.h
@@ -116,8 +116,6 @@
  private:
   friend class internal::TaskQueue;
 
-  enum class WorkQueueUpdateEventType { BEFORE_WAKEUP, AFTER_WAKEUP };
-
   // Called by the task queue to register a new pending task and allocate a
   // sequence number for it.
   void DidQueueTask(base::PendingTask* pending_task);
@@ -131,12 +129,13 @@
   void DoWork(bool posted_from_main_thread);
 
   // Reloads any empty work queues which have automatic pumping enabled and
-  // which are eligible to be auto pumped at the given |event_type|.
-  // Returns true if any work queue has tasks after doing this.
+  // which are eligible to be auto pumped based on the |previous_task| which was
+  // run. Call with an empty |previous_task| if no task was just run. Returns
+  // true if any work queue has tasks after doing this.
   // |next_pending_delayed_task| should be the time of the next known delayed
   // task. It is updated if any task is found which should run earlier.
   bool UpdateWorkQueues(base::TimeTicks* next_pending_delayed_task,
-                        WorkQueueUpdateEventType event_type);
+                        const base::PendingTask* previous_task);
 
   // Chooses the next work queue to service. Returns true if |out_queue_index|
   // indicates the queue from which the next task should be run, false to
diff --git a/content/renderer/scheduler/task_queue_manager_unittest.cc b/content/renderer/scheduler/task_queue_manager_unittest.cc
index 5c4e4eb8..0a1a2a7 100644
--- a/content/renderer/scheduler/task_queue_manager_unittest.cc
+++ b/content/renderer/scheduler/task_queue_manager_unittest.cc
@@ -58,6 +58,7 @@
     selector_ = make_scoped_ptr(new SelectorForTest);
     manager_ = make_scoped_ptr(
         new TaskQueueManager(num_queues, test_task_runner_, selector_.get()));
+    EXPECT_EQ(num_queues, selector_->work_queues().size());
   }
 
   void InitializeWithRealMessageLoop(size_t num_queues) {
@@ -65,6 +66,7 @@
     selector_ = make_scoped_ptr(new SelectorForTest);
     manager_ = make_scoped_ptr(new TaskQueueManager(
         num_queues, message_loop_->task_runner(), selector_.get()));
+    EXPECT_EQ(num_queues, selector_->work_queues().size());
   }
 
   scoped_refptr<base::TestSimpleTaskRunner> test_task_runner_;
@@ -93,7 +95,6 @@
 
 TEST_F(TaskQueueManagerTest, SingleQueuePosting) {
   Initialize(1u);
-  EXPECT_EQ(1u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runner =
@@ -113,7 +114,6 @@
 
 TEST_F(TaskQueueManagerTest, MultiQueuePosting) {
   Initialize(3u);
-  EXPECT_EQ(3u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runners[3] = {
@@ -141,7 +141,6 @@
 
 TEST_F(TaskQueueManagerTest, NonNestableTaskPosting) {
   InitializeWithRealMessageLoop(1u);
-  EXPECT_EQ(1u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runner =
@@ -157,7 +156,6 @@
 
 TEST_F(TaskQueueManagerTest, NonNestableTaskExecutesInExpectedOrder) {
   InitializeWithRealMessageLoop(1u);
-  EXPECT_EQ(1u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runner =
@@ -181,7 +179,6 @@
 
 TEST_F(TaskQueueManagerTest, NonNestableTaskDoesntExecuteInNestedLoop) {
   InitializeWithRealMessageLoop(1u);
-  EXPECT_EQ(1u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runner =
@@ -402,7 +399,6 @@
 
 TEST_F(TaskQueueManagerTest, ReentrantPosting) {
   Initialize(1u);
-  EXPECT_EQ(1u, selector_->work_queues().size());
 
   std::vector<int> run_order;
   scoped_refptr<base::SingleThreadTaskRunner> runner =
@@ -457,18 +453,22 @@
   EXPECT_THAT(run_order, ElementsAre(1));
 }
 
-void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
+                       int* run_count) {
+  (*run_count)++;
   runner->PostTask(
-      FROM_HERE, Bind(&RePostingTestTask, base::Unretained(runner.get())));
+      FROM_HERE,
+      Bind(&RePostingTestTask, base::Unretained(runner.get()), run_count));
 }
 
 TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) {
   Initialize(1u);
-
   scoped_refptr<base::SingleThreadTaskRunner> runner =
       manager_->TaskRunnerForQueue(0);
 
-  runner->PostTask(FROM_HERE, base::Bind(&RePostingTestTask, runner));
+  int run_count = 0;
+  runner->PostTask(FROM_HERE,
+                   base::Bind(&RePostingTestTask, runner, &run_count));
 
   selector_->AppendQueueToService(0);
   selector_->AppendQueueToService(0);
@@ -478,6 +478,7 @@
   // NOTE without the executing_task_ check in MaybePostDoWorkOnMainRunner there
   // will be two tasks here.
   EXPECT_EQ(1u, test_task_runner_->GetPendingTasks().size());
+  EXPECT_EQ(1, run_count);
 }
 
 TEST_F(TaskQueueManagerTest, PostFromNestedRunloop) {
@@ -583,9 +584,8 @@
   EXPECT_THAT(run_order, ElementsAre(2, 3, 1));
 }
 
-TEST_F(TaskQueueManagerTest, AutoPumpOnWakeup) {
+TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeup) {
   Initialize(2u);
-  EXPECT_EQ(2u, selector_->work_queues().size());
   manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
 
   std::vector<int> run_order;
@@ -610,9 +610,8 @@
   EXPECT_THAT(run_order, ElementsAre(3, 1, 2));
 }
 
-TEST_F(TaskQueueManagerTest, AutoPumpOnWakeupWhenAlreadyAwake) {
+TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupWhenAlreadyAwake) {
   Initialize(2u);
-  EXPECT_EQ(2u, selector_->work_queues().size());
   manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
 
   std::vector<int> run_order;
@@ -622,15 +621,15 @@
   selector_->AppendQueueToService(1);
   selector_->AppendQueueToService(0);
 
-  runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
-  runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
+  runners[0]->PostTask(FROM_HERE, base::Bind(&TestTask, 1, &run_order));
+  runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
   test_task_runner_->RunUntilIdle();
-  EXPECT_THAT(run_order, ElementsAre(1, 2));  // TQM was already awake.
+  EXPECT_THAT(run_order, ElementsAre(2, 1));  // TQM was already awake.
 }
 
-TEST_F(TaskQueueManagerTest, AutoPumpOnWakeupTriggeredByManuallyPumpedQueue) {
+TEST_F(TaskQueueManagerTest,
+       AutoPumpAfterWakeupTriggeredByManuallyPumpedQueue) {
   Initialize(2u);
-  EXPECT_EQ(2u, selector_->work_queues().size());
   manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
   manager_->SetPumpPolicy(1, TaskQueueManager::PumpPolicy::MANUAL);
 
@@ -656,6 +655,104 @@
   EXPECT_THAT(run_order, ElementsAre(2, 1));
 }
 
+void TestPostingTask(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                     base::Closure task) {
+  task_runner->PostTask(FROM_HERE, task);
+}
+
+TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromTask) {
+  Initialize(2u);
+  manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
+
+  std::vector<int> run_order;
+  scoped_refptr<base::SingleThreadTaskRunner> runners[2] = {
+      manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)};
+
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(0);
+
+  // Check that a task which posts a task to an auto pump after wakeup queue
+  // doesn't cause the queue to wake up.
+  base::Closure after_wakeup_task = base::Bind(&TestTask, 1, &run_order);
+  runners[1]->PostTask(
+      FROM_HERE,
+      base::Bind(&TestPostingTask, runners[0], after_wakeup_task));
+  test_task_runner_->RunUntilIdle();
+  EXPECT_TRUE(run_order.empty());
+
+  // Wake up the queue.
+  runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 2, &run_order));
+  test_task_runner_->RunUntilIdle();
+  EXPECT_THAT(run_order, ElementsAre(2, 1));
+}
+
+TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupFromMultipleTasks) {
+  Initialize(2u);
+  manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
+
+  std::vector<int> run_order;
+  scoped_refptr<base::SingleThreadTaskRunner> runners[2] = {
+      manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)};
+
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+
+  // Check that a task which posts a task to an auto pump after wakeup queue
+  // doesn't cause the queue to wake up.
+  base::Closure after_wakeup_task_1 = base::Bind(&TestTask, 1, &run_order);
+  base::Closure after_wakeup_task_2 = base::Bind(&TestTask, 2, &run_order);
+  runners[1]->PostTask(
+      FROM_HERE,
+      base::Bind(&TestPostingTask, runners[0], after_wakeup_task_1));
+  runners[1]->PostTask(
+      FROM_HERE,
+      base::Bind(&TestPostingTask, runners[0], after_wakeup_task_2));
+  test_task_runner_->RunUntilIdle();
+  EXPECT_TRUE(run_order.empty());
+
+  // Wake up the queue.
+  runners[1]->PostTask(FROM_HERE, base::Bind(&TestTask, 3, &run_order));
+  test_task_runner_->RunUntilIdle();
+  EXPECT_THAT(run_order, ElementsAre(3, 1, 2));
+}
+
+void NullTestTask() {
+}
+
+TEST_F(TaskQueueManagerTest, AutoPumpAfterWakeupBecomesQuiescent) {
+  Initialize(2u);
+  manager_->SetPumpPolicy(0, TaskQueueManager::PumpPolicy::AFTER_WAKEUP);
+
+  int run_count = 0;
+  scoped_refptr<base::SingleThreadTaskRunner> runners[2] = {
+      manager_->TaskRunnerForQueue(0), manager_->TaskRunnerForQueue(1)};
+
+  selector_->AppendQueueToService(1);
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+  // Append extra service queue '0' entries to the selector otherwise test will
+  // finish even if the RePostingTestTask woke each other up.
+  selector_->AppendQueueToService(0);
+  selector_->AppendQueueToService(0);
+
+  // Check that if multiple tasks reposts themselves onto a pump-after-wakeup
+  // queue they don't wake each other and will eventually stop when no other
+  // tasks execute.
+  runners[0]->PostTask(FROM_HERE,
+                       base::Bind(&RePostingTestTask, runners[0], &run_count));
+  runners[0]->PostTask(FROM_HERE,
+                       base::Bind(&RePostingTestTask, runners[0], &run_count));
+  runners[1]->PostTask(FROM_HERE, base::Bind(&NullTestTask));
+  test_task_runner_->RunUntilIdle();
+  // The reposting tasks posted to the after wakeup queue shouldn't have woken
+  // each other up.
+  EXPECT_EQ(2, run_count);
+}
+
 class MockTaskObserver : public base::MessageLoop::TaskObserver {
  public:
   MOCK_METHOD1(DidProcessTask, void(const base::PendingTask& task));
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 2bbac9b..56723e8a 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -482,7 +482,7 @@
 
 # TODO(GYP): Figure out what this should be on android
 # and make linking this work on the Mac.
-if (!is_android && !is_mac && (!is_win || link_chrome_on_windows)) {
+if (!is_android && !is_mac) {
   executable("content_shell") {
     testonly = true
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ec6efd3..18048efa9 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -247,7 +247,7 @@
 }  # !is_ios
 
 # TODO(GYP) enable content_browsertests on Mac when it links.
-if (!is_mac && (!is_win || link_chrome_on_windows)) {
+if (!is_mac) {
   test("content_browsertests") {
     sources =
         rebase_path(content_tests_gypi_values.content_browsertests_sources,
@@ -439,7 +439,7 @@
   }
 }
 
-if (!is_mac && (!is_win || link_chrome_on_windows)) {  # TODO(GYP) enable on Mac once it links.
+if (!is_mac) {  # TODO(GYP) enable on Mac once it links.
   test("content_unittests") {
     sources = rebase_path(content_tests_gypi_values.content_unittests_sources,
                           ".",
@@ -631,7 +631,7 @@
   }
 }
 
-if (!is_mac && (!is_win || link_chrome_on_windows)) {  # TODO(GYP) enable on Mac once it links.
+if (!is_mac) {  # TODO(GYP) enable on Mac once it links.
   test("content_perftests") {
     sources = [
       "../browser/net/sqlite_persistent_cookie_store_perftest.cc",
diff --git a/content/test/data/media/peerconnection-call.html b/content/test/data/media/peerconnection-call.html
index 1e6ff4b8..345d0ea 100644
--- a/content/test/data/media/peerconnection-call.html
+++ b/content/test/data/media/peerconnection-call.html
@@ -533,48 +533,48 @@
     setAllEventsOccuredHandler(function() {
       // Add an audio track to the local stream and remove the video track and
       // then renegotiate. But first - setup the expectations.
-      local_stream = gFirstConnection.getLocalStreams()[0];
+      var localStream = gFirstConnection.getLocalStreams()[0];
+      var remoteStream1 = gFirstConnection.getRemoteStreams()[0];
 
-      remote_stream_1 = gFirstConnection.getRemoteStreams()[0];
       // Add an expected event that onaddtrack will be called on the remote
       // mediastream received on gFirstConnection when the audio track is
       // received.
       addExpectedEvent();
-      remote_stream_1.onaddtrack = function(){
-        assertEquals(remote_stream_1.getAudioTracks()[0].id,
-                     local_stream.getAudioTracks()[0].id);
+      remoteStream1.onaddtrack = function(){
+        assertEquals(remoteStream1.getAudioTracks()[0].id,
+                     localStream.getAudioTracks()[0].id);
         eventOccured();
       }
 
       // Add an expectation that the received video track is removed from
       // gFirstConnection.
       addExpectedEvent();
-      remote_stream_1.onremovetrack = function() {
+      remoteStream1.onremovetrack = function() {
         eventOccured();
       }
 
       // Add an expected event that onaddtrack will be called on the remote
       // mediastream received on gSecondConnection when the audio track is
       // received.
-      remote_stream_2 = gSecondConnection.getRemoteStreams()[0];
+      remoteStream2 = gSecondConnection.getRemoteStreams()[0];
       addExpectedEvent();
-      remote_stream_2.onaddtrack = function() {
-        assertEquals(remote_stream_2.getAudioTracks()[0].id,
-                     local_stream.getAudioTracks()[0].id);
+      remoteStream2.onaddtrack = function() {
+        assertEquals(remoteStream2.getAudioTracks()[0].id,
+                     localStream.getAudioTracks()[0].id);
         eventOccured();
       }
 
       // Add an expectation that the received video track is removed from
       // gSecondConnection.
       addExpectedEvent();
-      remote_stream_2.onremovetrack = function() {
+      remoteStream2.onremovetrack = function() {
         eventOccured();
       }
       // When all the above events have occurred- the test pass.
       setAllEventsOccuredHandler(reportTestSuccess);
 
-      local_stream.addTrack(gLocalStream.getAudioTracks()[0]);
-      local_stream.removeTrack(local_stream.getVideoTracks()[0]);
+      localStream.addTrack(gLocalStream.getAudioTracks()[0]);
+      localStream.removeTrack(localStream.getVideoTracks()[0]);
       negotiate();
     });
   }
@@ -681,7 +681,7 @@
   function addTwoMediaStreamsToOneConnection() {
     createConnections(null);
     navigator.webkitGetUserMedia({audio: true, video: true},
-        CloneStreamAndAddTwoStreamstoOneConnection, printGetUserMediaError);
+        cloneStreamAndAddTwoStreamsToOneConnection, printGetUserMediaError);
   }
 
   function onToneChange(tone) {
@@ -743,7 +743,7 @@
 
   // Called if getUserMedia succeeds, then clone the stream, send two streams
   // from one peer connection.
-  function CloneStreamAndAddTwoStreamstoOneConnection(localStream) {
+  function cloneStreamAndAddTwoStreamsToOneConnection(localStream) {
     displayAndRemember(localStream);
 
     var clonedStream = null;
@@ -780,15 +780,14 @@
     negotiate();
   }
 
-  // Called if getUserMedia succeeds when we want to send a modified
-  // MediaStream. A new MediaStream is created and the video track from
-  // |localStream| is added.
+  // A new MediaStream is created with video track from |localStream| and is
+  // added to both peer connections.
   function createNewVideoStreamAndAddToBothConnections(localStream) {
     displayAndRemember(localStream);
-    var new_stream = new webkitMediaStream();
-    new_stream.addTrack(localStream.getVideoTracks()[0]);
-    gFirstConnection.addStream(new_stream);
-    gSecondConnection.addStream(new_stream);
+    var newStream = new webkitMediaStream();
+    newStream.addTrack(localStream.getVideoTracks()[0]);
+    gFirstConnection.addStream(newStream);
+    gSecondConnection.addStream(newStream);
     negotiate();
   }
 
diff --git a/content/test/test_web_contents_factory.cc b/content/test/test_web_contents_factory.cc
new file mode 100644
index 0000000..0bf7a01
--- /dev/null
+++ b/content/test/test_web_contents_factory.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/test/test_web_contents_factory.h"
+
+#include "base/run_loop.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+
+#if defined(USE_AURA)
+#include "ui/aura/env.h"
+#endif
+
+namespace content {
+
+TestWebContentsFactory::TestWebContentsFactory()
+    : rvh_enabler_(new content::RenderViewHostTestEnabler()),
+      tear_down_aura_(false) {
+#if defined(USE_AURA)
+  if (aura::Env::GetInstanceDontCreate() == nullptr) {
+    aura::Env::CreateInstance(true);
+    tear_down_aura_ = true;
+  }
+#endif
+}
+
+TestWebContentsFactory::~TestWebContentsFactory() {
+  // We explicitly clear the vector to force destruction of any created web
+  // contents so that we can properly handle their cleanup (running posted
+  // tasks, etc).
+  web_contents_.clear();
+  // Let any posted tasks for web contents deletion run.
+  base::RunLoop().RunUntilIdle();
+  rvh_enabler_.reset();
+  // Let any posted tasks for RenderProcess/ViewHost deletion run.
+  base::RunLoop().RunUntilIdle();
+#if defined(USE_AURA)
+  if (tear_down_aura_)
+    aura::Env::DeleteInstance();
+#endif
+}
+
+WebContents* TestWebContentsFactory::CreateWebContents(
+    BrowserContext* context) {
+  web_contents_.push_back(
+      WebContentsTester::CreateTestWebContents(context, nullptr));
+  DCHECK(web_contents_.back());
+  return web_contents_.back();
+}
+
+}  // namespace content
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
index efbfdb0..96fac21 100644
--- a/content/zygote/zygote_main_linux.cc
+++ b/content/zygote/zygote_main_linux.cc
@@ -67,6 +67,7 @@
 
 #if defined(SANITIZER_COVERAGE)
 #include <sanitizer/common_interface_defs.h>
+#include <sanitizer/coverage_interface.h>
 #endif
 
 namespace content {
diff --git a/courgette/disassembler_elf_32.cc b/courgette/disassembler_elf_32.cc
index ff2b9e03..02a31eb 100644
--- a/courgette/disassembler_elf_32.cc
+++ b/courgette/disassembler_elf_32.cc
@@ -262,6 +262,9 @@
 
     const Elf32_Shdr *section_header = SectionHeader(section_id);
 
+    if (section_header->sh_type == SHT_NOBITS)
+      continue;
+
     if (!ParseSimpleRegion(file_offset,
                            section_header->sh_offset,
                            program))
@@ -282,8 +285,6 @@
           return false;
         file_offset = section_header->sh_offset + section_header->sh_size;
         break;
-      case SHT_NOBITS:
-        // Fall through
       case SHT_INIT_ARRAY:
         // Fall through
       case SHT_FINI_ARRAY:
diff --git a/courgette/disassembler_elf_32_x86.cc b/courgette/disassembler_elf_32_x86.cc
index 74496d3..d2c1c86b44 100644
--- a/courgette/disassembler_elf_32_x86.cc
+++ b/courgette/disassembler_elf_32_x86.cc
@@ -91,6 +91,9 @@
   uint32 section_relocs_count = section_header->sh_size /
                                 section_header->sh_entsize;
 
+  if (abs32_locations_.empty())
+    match = false;
+
   if (abs32_locations_.size() > section_relocs_count)
     match = false;
 
diff --git a/courgette/encode_decode_unittest.cc b/courgette/encode_decode_unittest.cc
index 0e121d6..a3161ce 100644
--- a/courgette/encode_decode_unittest.cc
+++ b/courgette/encode_decode_unittest.cc
@@ -82,3 +82,8 @@
   std::string file = FileContents("elf-32-1");
   TestAssembleToStreamDisassemble(file, 135988);
 }
+
+TEST_F(EncodeDecodeTest, Elf_HighBSS) {
+  std::string file = FileContents("elf-32-high-bss");
+  TestAssembleToStreamDisassemble(file, 7308);
+}
diff --git a/courgette/testdata/elf-32-high-bss b/courgette/testdata/elf-32-high-bss
new file mode 100755
index 0000000..b9445c8
--- /dev/null
+++ b/courgette/testdata/elf-32-high-bss
Binary files differ
diff --git a/device/hid/BUILD.gn b/device/hid/BUILD.gn
index b0375731..4a6a1b2 100644
--- a/device/hid/BUILD.gn
+++ b/device/hid/BUILD.gn
@@ -6,6 +6,8 @@
   sources = [
     "device_monitor_linux.cc",
     "device_monitor_linux.h",
+    "fake_input_service_linux.cc",
+    "fake_input_service_linux.h",
     "hid_collection_info.cc",
     "hid_collection_info.h",
     "hid_connection.cc",
diff --git a/device/hid/fake_input_service_linux.cc b/device/hid/fake_input_service_linux.cc
new file mode 100644
index 0000000..ae3f085
--- /dev/null
+++ b/device/hid/fake_input_service_linux.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "device/hid/fake_input_service_linux.h"
+
+#include <string>
+#include <vector>
+
+namespace device {
+
+FakeInputServiceLinux::FakeInputServiceLinux() {
+}
+
+FakeInputServiceLinux::~FakeInputServiceLinux() {
+}
+
+void FakeInputServiceLinux::AddDeviceForTesting(const InputDeviceInfo& info) {
+  AddDevice(info);
+}
+
+void FakeInputServiceLinux::RemoveDeviceForTesting(const std::string& id) {
+  RemoveDevice(id);
+}
+
+void FakeInputServiceLinux::ClearDeviceList() {
+  devices_.clear();
+}
+
+}  // namespace device
\ No newline at end of file
diff --git a/device/hid/fake_input_service_linux.h b/device/hid/fake_input_service_linux.h
new file mode 100644
index 0000000..1b46d98
--- /dev/null
+++ b/device/hid/fake_input_service_linux.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+#define DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
+
+#include <string>
+
+#include "device/hid/input_service_linux.h"
+
+namespace device {
+
+class FakeInputServiceLinux : public InputServiceLinux {
+
+ public:
+  FakeInputServiceLinux();
+  ~FakeInputServiceLinux() override;
+
+  void AddDeviceForTesting(const InputDeviceInfo& info);
+  void RemoveDeviceForTesting(const std::string& id);
+  void ClearDeviceList();
+
+  DISALLOW_COPY_AND_ASSIGN(FakeInputServiceLinux);
+};
+
+}  // namespace device
+
+#endif  // DEVICE_HID_FAKE_INPUT_SERVICE_LINUX_H_
diff --git a/device/hid/hid.gyp b/device/hid/hid.gyp
index 42215d75..00b9a90 100644
--- a/device/hid/hid.gyp
+++ b/device/hid/hid.gyp
@@ -21,6 +21,8 @@
       'sources': [
         'device_monitor_linux.cc',
         'device_monitor_linux.h',
+        'fake_input_service_linux.cc',
+        'fake_input_service_linux.h',
         'hid_collection_info.cc',
         'hid_collection_info.h',
         'hid_connection.cc',
@@ -66,6 +68,8 @@
             'device_monitor_linux.h',
             'hid_service_linux.cc',
             'hid_service_linux.h',
+            'fake_input_service_linux.cc',
+            'fake_input_service_linux.h',
             'input_service_linux.cc',
             'input_service_linux.h',
           ],
diff --git a/device/hid/input_service_linux.cc b/device/hid/input_service_linux.cc
index f6fd0dce..81cac1a 100644
--- a/device/hid/input_service_linux.cc
+++ b/device/hid/input_service_linux.cc
@@ -90,6 +90,9 @@
 };
 
 InputServiceLinuxImpl::InputServiceLinuxImpl() {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::MessageLoop::current()->AddDestructionObserver(this);
+
   DeviceMonitorLinux::GetInstance()->AddObserver(this);
   DeviceMonitorLinux::GetInstance()->Enumerate(base::Bind(
       &InputServiceLinuxImpl::OnDeviceAdded, base::Unretained(this)));
@@ -98,6 +101,7 @@
 InputServiceLinuxImpl::~InputServiceLinuxImpl() {
   if (DeviceMonitorLinux::HasInstance())
     DeviceMonitorLinux::GetInstance()->RemoveObserver(this);
+  base::MessageLoop::current()->RemoveDestructionObserver(this);
 }
 
 void InputServiceLinuxImpl::OnDeviceAdded(udev_device* device) {
@@ -162,13 +166,10 @@
       is_touchscreen(false) {}
 
 InputServiceLinux::InputServiceLinux() {
-  base::ThreadRestrictions::AssertIOAllowed();
-  base::MessageLoop::current()->AddDestructionObserver(this);
 }
 
 InputServiceLinux::~InputServiceLinux() {
   DCHECK(CalledOnValidThread());
-  base::MessageLoop::current()->RemoveDestructionObserver(this);
 }
 
 // static
diff --git a/device/hid/input_service_linux.h b/device/hid/input_service_linux.h
index 55bf70c..7eda3bb81 100644
--- a/device/hid/input_service_linux.h
+++ b/device/hid/input_service_linux.h
@@ -45,6 +45,9 @@
     bool is_touchscreen : 1;
   };
 
+
+  using DeviceMap = base::hash_map<std::string, InputDeviceInfo>;
+
   class Observer {
    public:
     virtual ~Observer() {}
@@ -53,6 +56,7 @@
   };
 
   InputServiceLinux();
+  ~InputServiceLinux() override;
 
   static InputServiceLinux* GetInstance();
   static bool HasInstance();
@@ -73,21 +77,18 @@
   void WillDestroyCurrentMessageLoop() override;
 
  protected:
-  ~InputServiceLinux() override;
 
   void AddDevice(const InputDeviceInfo& info);
   void RemoveDevice(const std::string& id);
 
   bool CalledOnValidThread() const;
 
- private:
-  friend struct base::DefaultDeleter<InputServiceLinux>;
-
-  typedef base::hash_map<std::string, InputDeviceInfo> DeviceMap;
-
   DeviceMap devices_;
   ObserverList<Observer> observers_;
 
+ private:
+  friend struct base::DefaultDeleter<InputServiceLinux>;
+
   base::ThreadChecker thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(InputServiceLinux);
diff --git a/extensions/browser/api/power/power_api.cc b/extensions/browser/api/power/power_api.cc
index d731b9f..13dbbab1 100644
--- a/extensions/browser/api/power/power_api.cc
+++ b/extensions/browser/api/power/power_api.cc
@@ -4,24 +4,128 @@
 
 #include "extensions/browser/api/power/power_api.h"
 
-#include "extensions/browser/api/power/power_api_manager.h"
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/api/power.h"
+#include "extensions/common/extension.h"
 
 namespace extensions {
 
+namespace {
+
+const char kPowerSaveBlockerDescription[] = "extension";
+
+content::PowerSaveBlocker::PowerSaveBlockerType LevelToPowerSaveBlockerType(
+    core_api::power::Level level) {
+  switch (level) {
+    case core_api::power::LEVEL_SYSTEM:
+      return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
+    case core_api::power::LEVEL_DISPLAY:  // fallthrough
+    case core_api::power::LEVEL_NONE:
+      return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
+  }
+  NOTREACHED() << "Unhandled level " << level;
+  return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
+}
+
+base::LazyInstance<BrowserContextKeyedAPIFactory<PowerAPI>> g_factory =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 bool PowerRequestKeepAwakeFunction::RunSync() {
   scoped_ptr<core_api::power::RequestKeepAwake::Params> params(
       core_api::power::RequestKeepAwake::Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params);
   EXTENSION_FUNCTION_VALIDATE(params->level != core_api::power::LEVEL_NONE);
-  PowerApiManager::Get(browser_context())->AddRequest(
-      extension_id(), params->level);
+  PowerAPI::Get(browser_context())->AddRequest(extension_id(), params->level);
   return true;
 }
 
 bool PowerReleaseKeepAwakeFunction::RunSync() {
-  PowerApiManager::Get(browser_context())->RemoveRequest(extension_id());
+  PowerAPI::Get(browser_context())->RemoveRequest(extension_id());
   return true;
 }
 
+// static
+PowerAPI* PowerAPI::Get(content::BrowserContext* context) {
+  return BrowserContextKeyedAPIFactory<PowerAPI>::Get(context);
+}
+
+// static
+BrowserContextKeyedAPIFactory<PowerAPI>* PowerAPI::GetFactoryInstance() {
+  return g_factory.Pointer();
+}
+
+void PowerAPI::AddRequest(const std::string& extension_id,
+                          core_api::power::Level level) {
+  extension_levels_[extension_id] = level;
+  UpdatePowerSaveBlocker();
+}
+
+void PowerAPI::RemoveRequest(const std::string& extension_id) {
+  extension_levels_.erase(extension_id);
+  UpdatePowerSaveBlocker();
+}
+
+void PowerAPI::SetCreateBlockerFunctionForTesting(
+    CreateBlockerFunction function) {
+  create_blocker_function_ =
+      !function.is_null() ? function
+                          : base::Bind(&content::PowerSaveBlocker::Create);
+}
+
+void PowerAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
+                                   const Extension* extension,
+                                   UnloadedExtensionInfo::Reason reason) {
+  RemoveRequest(extension->id());
+  UpdatePowerSaveBlocker();
+}
+
+PowerAPI::PowerAPI(content::BrowserContext* context)
+    : browser_context_(context),
+      create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)),
+      current_level_(core_api::power::LEVEL_SYSTEM) {
+  ExtensionRegistry::Get(browser_context_)->AddObserver(this);
+}
+
+PowerAPI::~PowerAPI() {
+}
+
+void PowerAPI::UpdatePowerSaveBlocker() {
+  if (extension_levels_.empty()) {
+    power_save_blocker_.reset();
+    return;
+  }
+
+  core_api::power::Level new_level = core_api::power::LEVEL_SYSTEM;
+  for (ExtensionLevelMap::const_iterator it = extension_levels_.begin();
+       it != extension_levels_.end(); ++it) {
+    if (it->second == core_api::power::LEVEL_DISPLAY)
+      new_level = it->second;
+  }
+
+  // If the level changed and we need to create a new blocker, do a swap
+  // to ensure that there isn't a brief period where power management is
+  // unblocked.
+  if (!power_save_blocker_ || new_level != current_level_) {
+    content::PowerSaveBlocker::PowerSaveBlockerType type =
+        LevelToPowerSaveBlockerType(new_level);
+    scoped_ptr<content::PowerSaveBlocker> new_blocker(
+        create_blocker_function_.Run(type,
+                                     content::PowerSaveBlocker::kReasonOther,
+                                     kPowerSaveBlockerDescription));
+    power_save_blocker_.swap(new_blocker);
+    current_level_ = new_level;
+  }
+}
+
+void PowerAPI::Shutdown() {
+  // Unregister here rather than in the d'tor; otherwise this call will recreate
+  // the already-deleted ExtensionRegistry.
+  ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
+  power_save_blocker_.reset();
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/api/power/power_api.h b/extensions/browser/api/power/power_api.h
index 228e517b..7a4a752d 100644
--- a/extensions/browser/api/power/power_api.h
+++ b/extensions/browser/api/power/power_api.h
@@ -5,7 +5,20 @@
 #ifndef EXTENSIONS_BROWSER_API_POWER_POWER_API_H_
 #define EXTENSIONS_BROWSER_API_POWER_POWER_API_H_
 
+#include <map>
+#include <string>
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/power_save_blocker.h"
+#include "extensions/browser/browser_context_keyed_api_factory.h"
 #include "extensions/browser/extension_function.h"
+#include "extensions/browser/extension_registry_observer.h"
+#include "extensions/common/api/power.h"
+
+namespace content {
+class BrowserContext;
+}
 
 namespace extensions {
 
@@ -33,6 +46,77 @@
   bool RunSync() override;
 };
 
+// Handles calls made via the chrome.power API. There is a separate instance of
+// this class for each profile, as requests are tracked by extension ID, but a
+// regular and incognito profile will share the same instance.
+class PowerAPI : public BrowserContextKeyedAPI,
+                 public extensions::ExtensionRegistryObserver {
+ public:
+  typedef base::Callback<scoped_ptr<content::PowerSaveBlocker>(
+      content::PowerSaveBlocker::PowerSaveBlockerType,
+      content::PowerSaveBlocker::Reason,
+      const std::string&)> CreateBlockerFunction;
+
+  static PowerAPI* Get(content::BrowserContext* context);
+
+  // BrowserContextKeyedAPI implementation.
+  static BrowserContextKeyedAPIFactory<PowerAPI>* GetFactoryInstance();
+
+  // Adds an extension lock at |level| for |extension_id|, replacing the
+  // extension's existing lock, if any.
+  void AddRequest(const std::string& extension_id,
+                  core_api::power::Level level);
+
+  // Removes an extension lock for an extension. Calling this for an
+  // extension id without a lock will do nothing.
+  void RemoveRequest(const std::string& extension_id);
+
+  // Replaces the function that will be called to create PowerSaveBlocker
+  // objects.  Passing an empty callback will revert to the default.
+  void SetCreateBlockerFunctionForTesting(CreateBlockerFunction function);
+
+  // Overridden from extensions::ExtensionRegistryObserver.
+  void OnExtensionUnloaded(content::BrowserContext* browser_context,
+                           const Extension* extension,
+                           UnloadedExtensionInfo::Reason reason) override;
+
+ private:
+  friend class BrowserContextKeyedAPIFactory<PowerAPI>;
+
+  explicit PowerAPI(content::BrowserContext* context);
+  ~PowerAPI() override;
+
+  // Updates |power_save_blocker_| and |current_level_| after iterating
+  // over |extension_levels_|.
+  void UpdatePowerSaveBlocker();
+
+  // BrowserContextKeyedAPI implementation.
+  static const char* service_name() { return "PowerAPI"; }
+  static const bool kServiceRedirectedInIncognito = true;
+  static const bool kServiceIsCreatedWithBrowserContext = false;
+  void Shutdown() override;
+
+  content::BrowserContext* browser_context_;
+
+  // Function that should be called to create PowerSaveBlocker objects.
+  // Tests can change this to record what would've been done instead of
+  // actually changing the system power-saving settings.
+  CreateBlockerFunction create_blocker_function_;
+
+  scoped_ptr<content::PowerSaveBlocker> power_save_blocker_;
+
+  // Current level used by |power_save_blocker_|.  Meaningless if
+  // |power_save_blocker_| is NULL.
+  core_api::power::Level current_level_;
+
+  // Map from extension ID to the corresponding level for each extension
+  // that has an outstanding request.
+  typedef std::map<std::string, core_api::power::Level> ExtensionLevelMap;
+  ExtensionLevelMap extension_levels_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerAPI);
+};
+
 }  // namespace extensions
 
 #endif  // EXTENSIONS_BROWSER_API_POWER_POWER_API_H_
diff --git a/extensions/browser/api/power/power_api_manager.cc b/extensions/browser/api/power/power_api_manager.cc
deleted file mode 100644
index 642e794..0000000
--- a/extensions/browser/api/power/power_api_manager.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/browser/api/power/power_api_manager.h"
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "extensions/browser/extension_registry.h"
-#include "extensions/common/extension.h"
-
-namespace extensions {
-
-namespace {
-
-const char kPowerSaveBlockerDescription[] = "extension";
-
-content::PowerSaveBlocker::PowerSaveBlockerType
-LevelToPowerSaveBlockerType(core_api::power::Level level) {
-  switch (level) {
-    case core_api::power::LEVEL_SYSTEM:
-      return content::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension;
-    case core_api::power::LEVEL_DISPLAY:  // fallthrough
-    case core_api::power::LEVEL_NONE:
-      return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
-  }
-  NOTREACHED() << "Unhandled level " << level;
-  return content::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep;
-}
-
-base::LazyInstance<BrowserContextKeyedAPIFactory<PowerApiManager> > g_factory =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-// static
-PowerApiManager* PowerApiManager::Get(content::BrowserContext* context) {
-  return BrowserContextKeyedAPIFactory<PowerApiManager>::Get(context);
-}
-
-// static
-BrowserContextKeyedAPIFactory<PowerApiManager>*
-PowerApiManager::GetFactoryInstance() {
-  return g_factory.Pointer();
-}
-
-void PowerApiManager::AddRequest(const std::string& extension_id,
-                                 core_api::power::Level level) {
-  extension_levels_[extension_id] = level;
-  UpdatePowerSaveBlocker();
-}
-
-void PowerApiManager::RemoveRequest(const std::string& extension_id) {
-  extension_levels_.erase(extension_id);
-  UpdatePowerSaveBlocker();
-}
-
-void PowerApiManager::SetCreateBlockerFunctionForTesting(
-    CreateBlockerFunction function) {
-  create_blocker_function_ = !function.is_null() ? function :
-      base::Bind(&content::PowerSaveBlocker::Create);
-}
-
-void PowerApiManager::OnExtensionUnloaded(
-    content::BrowserContext* browser_context,
-    const Extension* extension,
-    UnloadedExtensionInfo::Reason reason) {
-  RemoveRequest(extension->id());
-  UpdatePowerSaveBlocker();
-}
-
-PowerApiManager::PowerApiManager(content::BrowserContext* context)
-    : browser_context_(context),
-      create_blocker_function_(base::Bind(&content::PowerSaveBlocker::Create)),
-      current_level_(core_api::power::LEVEL_SYSTEM) {
-  ExtensionRegistry::Get(browser_context_)->AddObserver(this);
-}
-
-PowerApiManager::~PowerApiManager() {}
-
-void PowerApiManager::UpdatePowerSaveBlocker() {
-  if (extension_levels_.empty()) {
-    power_save_blocker_.reset();
-    return;
-  }
-
-  core_api::power::Level new_level = core_api::power::LEVEL_SYSTEM;
-  for (ExtensionLevelMap::const_iterator it = extension_levels_.begin();
-       it != extension_levels_.end(); ++it) {
-    if (it->second == core_api::power::LEVEL_DISPLAY)
-      new_level = it->second;
-  }
-
-  // If the level changed and we need to create a new blocker, do a swap
-  // to ensure that there isn't a brief period where power management is
-  // unblocked.
-  if (!power_save_blocker_ || new_level != current_level_) {
-    content::PowerSaveBlocker::PowerSaveBlockerType type =
-        LevelToPowerSaveBlockerType(new_level);
-    scoped_ptr<content::PowerSaveBlocker> new_blocker(
-        create_blocker_function_.Run(type,
-                                     content::PowerSaveBlocker::kReasonOther,
-                                     kPowerSaveBlockerDescription));
-    power_save_blocker_.swap(new_blocker);
-    current_level_ = new_level;
-  }
-}
-
-void PowerApiManager::Shutdown() {
-  // Unregister here rather than in the d'tor; otherwise this call will recreate
-  // the already-deleted ExtensionRegistry.
-  ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
-  power_save_blocker_.reset();
-}
-
-}  // namespace extensions
diff --git a/extensions/browser/api/power/power_api_manager.h b/extensions/browser/api/power/power_api_manager.h
deleted file mode 100644
index 4037811..0000000
--- a/extensions/browser/api/power/power_api_manager.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_
-#define EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_
-
-#include <map>
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/public/browser/power_save_blocker.h"
-#include "extensions/browser/browser_context_keyed_api_factory.h"
-#include "extensions/browser/extension_registry_observer.h"
-#include "extensions/common/api/power.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace extensions {
-
-// Handles calls made via the chrome.power API. There is a separate instance of
-// this class for each profile, as requests are tracked by extension ID, but a
-// regular and incognito profile will share the same instance.
-// TODO(derat): Move this to power_api.h and rename it to PowerApi.
-class PowerApiManager : public BrowserContextKeyedAPI,
-                        public extensions::ExtensionRegistryObserver {
- public:
-  typedef base::Callback<scoped_ptr<content::PowerSaveBlocker>(
-      content::PowerSaveBlocker::PowerSaveBlockerType,
-      content::PowerSaveBlocker::Reason,
-      const std::string&)> CreateBlockerFunction;
-
-  static PowerApiManager* Get(content::BrowserContext* context);
-
-  // BrowserContextKeyedAPI implementation.
-  static BrowserContextKeyedAPIFactory<PowerApiManager>* GetFactoryInstance();
-
-  // Adds an extension lock at |level| for |extension_id|, replacing the
-  // extension's existing lock, if any.
-  void AddRequest(const std::string& extension_id,
-                  core_api::power::Level level);
-
-  // Removes an extension lock for an extension. Calling this for an
-  // extension id without a lock will do nothing.
-  void RemoveRequest(const std::string& extension_id);
-
-  // Replaces the function that will be called to create PowerSaveBlocker
-  // objects.  Passing an empty callback will revert to the default.
-  void SetCreateBlockerFunctionForTesting(CreateBlockerFunction function);
-
-  // Overridden from extensions::ExtensionRegistryObserver.
-  void OnExtensionUnloaded(content::BrowserContext* browser_context,
-                           const Extension* extension,
-                           UnloadedExtensionInfo::Reason reason) override;
-
- private:
-  friend class BrowserContextKeyedAPIFactory<PowerApiManager>;
-
-  explicit PowerApiManager(content::BrowserContext* context);
-  ~PowerApiManager() override;
-
-  // Updates |power_save_blocker_| and |current_level_| after iterating
-  // over |extension_levels_|.
-  void UpdatePowerSaveBlocker();
-
-  // BrowserContextKeyedAPI implementation.
-  static const char* service_name() { return "PowerApiManager"; }
-  static const bool kServiceRedirectedInIncognito = true;
-  static const bool kServiceIsCreatedWithBrowserContext = false;
-  void Shutdown() override;
-
-  content::BrowserContext* browser_context_;
-
-  // Function that should be called to create PowerSaveBlocker objects.
-  // Tests can change this to record what would've been done instead of
-  // actually changing the system power-saving settings.
-  CreateBlockerFunction create_blocker_function_;
-
-  scoped_ptr<content::PowerSaveBlocker> power_save_blocker_;
-
-  // Current level used by |power_save_blocker_|.  Meaningless if
-  // |power_save_blocker_| is NULL.
-  core_api::power::Level current_level_;
-
-  // Map from extension ID to the corresponding level for each extension
-  // that has an outstanding request.
-  typedef std::map<std::string, core_api::power::Level> ExtensionLevelMap;
-  ExtensionLevelMap extension_levels_;
-
-  DISALLOW_COPY_AND_ASSIGN(PowerApiManager);
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_POWER_POWER_API_MANAGER_H_
diff --git a/extensions/browser/api/power/power_api_unittest.cc b/extensions/browser/api/power/power_api_unittest.cc
index e4e0a07..eb6c6a2 100644
--- a/extensions/browser/api/power/power_api_unittest.cc
+++ b/extensions/browser/api/power/power_api_unittest.cc
@@ -12,7 +12,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/power_save_blocker.h"
-#include "extensions/browser/api/power/power_api_manager.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/browser/api_unittest.h"
 #include "extensions/common/extension.h"
@@ -56,7 +55,7 @@
 };
 
 // Manages PowerSaveBlockerStub objects.  Tests can instantiate this class
-// to make PowerApiManager's calls to create PowerSaveBlockers record the
+// to make PowerAPI's calls to create PowerSaveBlockers record the
 // actions that would've been performed instead of actually blocking and
 // unblocking power management.
 class PowerSaveBlockerStubManager {
@@ -66,14 +65,14 @@
         weak_ptr_factory_(this) {
     // Use base::Unretained since callbacks with return values can't use
     // weak pointers.
-    PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
-        base::Bind(&PowerSaveBlockerStubManager::CreateStub,
-                   base::Unretained(this)));
+    PowerAPI::Get(browser_context_)
+        ->SetCreateBlockerFunctionForTesting(base::Bind(
+            &PowerSaveBlockerStubManager::CreateStub, base::Unretained(this)));
   }
 
   ~PowerSaveBlockerStubManager() {
-    PowerApiManager::Get(browser_context_)->SetCreateBlockerFunctionForTesting(
-        PowerApiManager::CreateBlockerFunction());
+    PowerAPI::Get(browser_context_)
+        ->SetCreateBlockerFunctionForTesting(PowerAPI::CreateBlockerFunction());
   }
 
   // Removes and returns the first item from |requests_|.  Returns NONE if
@@ -127,7 +126,7 @@
 
 }  // namespace
 
-class PowerApiTest : public ApiUnitTest {
+class PowerAPITest : public ApiUnitTest {
  public:
   void SetUp() override {
     ApiUnitTest::SetUp();
@@ -162,17 +161,18 @@
     return api_test_utils::RunFunction(function.get(), args, browser_context());
   }
 
-  // Send a notification to PowerApiManager saying that |extension| has
+  // Send a notification to PowerAPI saying that |extension| has
   // been unloaded.
   void UnloadExtension(const extensions::Extension* extension) {
-    PowerApiManager::Get(browser_context())->OnExtensionUnloaded(
-        browser_context(), extension, UnloadedExtensionInfo::REASON_UNINSTALL);
+    PowerAPI::Get(browser_context())
+        ->OnExtensionUnloaded(browser_context(), extension,
+                              UnloadedExtensionInfo::REASON_UNINSTALL);
   }
 
   scoped_ptr<PowerSaveBlockerStubManager> manager_;
 };
 
-TEST_F(PowerApiTest, RequestAndRelease) {
+TEST_F(PowerAPITest, RequestAndRelease) {
   // Simulate an extension making and releasing a "display" request and a
   // "system" request.
   ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension()));
@@ -190,7 +190,7 @@
   EXPECT_EQ(NONE, manager_->PopFirstRequest());
 }
 
-TEST_F(PowerApiTest, RequestWithoutRelease) {
+TEST_F(PowerAPITest, RequestWithoutRelease) {
   // Simulate an extension calling requestKeepAwake() without calling
   // releaseKeepAwake().  The override should be automatically removed when
   // the extension is unloaded.
@@ -203,14 +203,14 @@
   EXPECT_EQ(NONE, manager_->PopFirstRequest());
 }
 
-TEST_F(PowerApiTest, ReleaseWithoutRequest) {
+TEST_F(PowerAPITest, ReleaseWithoutRequest) {
   // Simulate an extension calling releaseKeepAwake() without having
   // calling requestKeepAwake() earlier.  The call should be ignored.
   ASSERT_TRUE(CallFunction(RELEASE, kEmptyArgs, extension()));
   EXPECT_EQ(NONE, manager_->PopFirstRequest());
 }
 
-TEST_F(PowerApiTest, UpgradeRequest) {
+TEST_F(PowerAPITest, UpgradeRequest) {
   // Simulate an extension calling requestKeepAwake("system") and then
   // requestKeepAwake("display").  When the second call is made, a
   // display-sleep-blocking request should be made before the initial
@@ -229,7 +229,7 @@
   EXPECT_EQ(NONE, manager_->PopFirstRequest());
 }
 
-TEST_F(PowerApiTest, DowngradeRequest) {
+TEST_F(PowerAPITest, DowngradeRequest) {
   // Simulate an extension calling requestKeepAwake("display") and then
   // requestKeepAwake("system").  When the second call is made, an
   // app-suspension-blocking request should be made before the initial
@@ -248,7 +248,7 @@
   EXPECT_EQ(NONE, manager_->PopFirstRequest());
 }
 
-TEST_F(PowerApiTest, MultipleExtensions) {
+TEST_F(PowerAPITest, MultipleExtensions) {
   // Simulate an extension blocking the display from sleeping.
   ASSERT_TRUE(CallFunction(REQUEST, kDisplayArgs, extension()));
   EXPECT_EQ(BLOCK_DISPLAY_SLEEP, manager_->PopFirstRequest());
diff --git a/extensions/browser/app_window/app_window.cc b/extensions/browser/app_window/app_window.cc
index a508074..7d0e7c3 100644
--- a/extensions/browser/app_window/app_window.cc
+++ b/extensions/browser/app_window/app_window.cc
@@ -238,6 +238,7 @@
       is_hidden_(false),
       cached_always_on_top_(false),
       requested_alpha_enabled_(false),
+      is_ime_window_(false),
       image_loader_ptr_factory_(this) {
   ExtensionsBrowserClient* client = ExtensionsBrowserClient::Get();
   CHECK(!client->IsGuestSession(context) || context->IsOffTheRecord())
@@ -273,6 +274,8 @@
 
   requested_alpha_enabled_ = new_params.alpha_enabled;
 
+  is_ime_window_ = params.is_ime_window;
+
   AppWindowClient* app_window_client = AppWindowClient::Get();
   native_app_window_.reset(
       app_window_client->CreateNativeAppWindow(this, &new_params));
diff --git a/extensions/browser/app_window/app_window.h b/extensions/browser/app_window/app_window.h
index c7abf3d9..6c0e135 100644
--- a/extensions/browser/app_window/app_window.h
+++ b/extensions/browser/app_window/app_window.h
@@ -351,6 +351,12 @@
   // Whether the app window wants to be alpha enabled.
   bool requested_alpha_enabled() const { return requested_alpha_enabled_; }
 
+  // Whether the app window is created by IME extensions.
+  // TODO(bshe): rename to hide_app_window_in_launcher if it is not used
+  // anywhere other than app_window_launcher_controller after M45. Otherwise,
+  // remove this TODO.
+  bool is_ime_window() const { return is_ime_window_; }
+
   void SetAppWindowContentsForTesting(scoped_ptr<AppWindowContents> contents) {
     app_window_contents_ = contents.Pass();
   }
@@ -559,6 +565,9 @@
   // Whether |alpha_enabled| was set in the CreateParams.
   bool requested_alpha_enabled_;
 
+  // Whether |is_ime_window| was set in the CreateParams.
+  bool is_ime_window_;
+
   base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AppWindow);
diff --git a/extensions/browser/extension_function.cc b/extensions/browser/extension_function.cc
index b970fe3..6a136b2c 100644
--- a/extensions/browser/extension_function.cc
+++ b/extensions/browser/extension_function.cc
@@ -404,7 +404,7 @@
   if (!results_)
     results_.reset(new base::ListValue());
 
-  response_callback_.Run(type, *results_, GetError());
+  response_callback_.Run(type, *results_, GetError(), histogram_value());
 }
 
 void ExtensionFunction::OnRespondingLater(ResponseValue value) {
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 9385719..f9a2a79d 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -100,9 +100,11 @@
     BAD_MESSAGE
   };
 
-  typedef base::Callback<void(ResponseType type,
-                              const base::ListValue& results,
-                              const std::string& error)> ResponseCallback;
+  using ResponseCallback = base::Callback<void(
+      ResponseType type,
+      const base::ListValue& results,
+      const std::string& error,
+      extensions::functions::HistogramValue histogram_value)>;
 
   ExtensionFunction();
 
diff --git a/extensions/browser/extension_function_dispatcher.cc b/extensions/browser/extension_function_dispatcher.cc
index cbc08cca..fcf4ab4 100644
--- a/extensions/browser/extension_function_dispatcher.cc
+++ b/extensions/browser/extension_function_dispatcher.cc
@@ -9,6 +9,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/process/process.h"
 #include "base/profiler/scoped_profile.h"
@@ -81,9 +82,14 @@
 base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER;
 
 // Kills the specified process because it sends us a malformed message.
-void KillBadMessageSender(base::ProcessHandle process) {
+// Track the specific function's |histogram_value|, as this may indicate a bug
+// in that API's implementation on the renderer.
+void KillBadMessageSender(base::ProcessHandle process,
+                          functions::HistogramValue histogram_value) {
   NOTREACHED();
   content::RecordAction(base::UserMetricsAction("BadMessageTerminate_EFD"));
+  UMA_HISTOGRAM_ENUMERATION("Extensions.BadMessageFunctionName",
+                            histogram_value, functions::ENUM_BOUNDARY);
   if (process)
     base::KillProcess(process, content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
 }
@@ -94,7 +100,8 @@
                             int request_id,
                             ExtensionFunction::ResponseType type,
                             const base::ListValue& results,
-                            const std::string& error) {
+                            const std::string& error,
+                            functions::HistogramValue histogram_value) {
   DCHECK(ipc_sender);
 
   if (type == ExtensionFunction::BAD_MESSAGE) {
@@ -108,9 +115,8 @@
       // In single process mode it is better if we don't suicide but just crash.
       CHECK(false);
     } else {
-      KillBadMessageSender(peer_process);
+      KillBadMessageSender(peer_process, histogram_value);
     }
-
     return;
   }
 
@@ -125,17 +131,13 @@
     int request_id,
     ExtensionFunction::ResponseType type,
     const base::ListValue& results,
-    const std::string& error) {
+    const std::string& error,
+    functions::HistogramValue histogram_value) {
   if (!ipc_sender.get())
     return;
 
-  CommonResponseCallback(ipc_sender.get(),
-                         routing_id,
-                         ipc_sender->PeerHandle(),
-                         request_id,
-                         type,
-                         results,
-                         error);
+  CommonResponseCallback(ipc_sender.get(), routing_id, ipc_sender->PeerHandle(),
+                         request_id, type, results, error, histogram_value);
 }
 
 }  // namespace
@@ -180,11 +182,11 @@
   void OnExtensionFunctionCompleted(int request_id,
                                     ExtensionFunction::ResponseType type,
                                     const base::ListValue& results,
-                                    const std::string& error) {
-    CommonResponseCallback(
-        render_view_host_, render_view_host_->GetRoutingID(),
-        render_view_host_->GetProcess()->GetHandle(), request_id, type,
-        results, error);
+                                    const std::string& error,
+                                    functions::HistogramValue histogram_value) {
+    CommonResponseCallback(render_view_host_, render_view_host_->GetRoutingID(),
+                           render_view_host_->GetProcess()->GetHandle(),
+                           request_id, type, results, error, histogram_value);
   }
 
   base::WeakPtr<ExtensionFunctionDispatcher> dispatcher_;
@@ -438,7 +440,7 @@
     const ExtensionFunction::ResponseCallback& callback) {
   if (!function->HasPermission()) {
     LOG(ERROR) << "Permission denied for " << params.name;
-    SendAccessDenied(callback);
+    SendAccessDenied(callback, function->histogram_value());
     return false;
   }
   return true;
@@ -457,7 +459,7 @@
       ExtensionFunctionRegistry::GetInstance()->NewFunction(params.name);
   if (!function) {
     LOG(ERROR) << "Unknown Extension API - " << params.name;
-    SendAccessDenied(callback);
+    SendAccessDenied(callback, function->histogram_value());
     return NULL;
   }
 
@@ -478,10 +480,11 @@
 
 // static
 void ExtensionFunctionDispatcher::SendAccessDenied(
-    const ExtensionFunction::ResponseCallback& callback) {
+    const ExtensionFunction::ResponseCallback& callback,
+    functions::HistogramValue histogram_value) {
   base::ListValue empty_list;
   callback.Run(ExtensionFunction::FAILED, empty_list,
-               "Access to extension API denied.");
+               "Access to extension API denied.", histogram_value);
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/extension_function_dispatcher.h b/extensions/browser/extension_function_dispatcher.h
index 0ae80dc..9224bbde 100644
--- a/extensions/browser/extension_function_dispatcher.h
+++ b/extensions/browser/extension_function_dispatcher.h
@@ -146,7 +146,8 @@
   // Helper to run the response callback with an access denied error. Can be
   // called on any thread.
   static void SendAccessDenied(
-      const ExtensionFunction::ResponseCallback& callback);
+      const ExtensionFunction::ResponseCallback& callback,
+      functions::HistogramValue histogram_value);
 
   void DispatchWithCallbackInternal(
       const ExtensionHostMsg_Request_Params& params,
diff --git a/extensions/browser/extension_host.cc b/extensions/browser/extension_host.cc
index 973c1a49..61d0626d 100644
--- a/extensions/browser/extension_host.cc
+++ b/extensions/browser/extension_host.cc
@@ -13,8 +13,6 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -25,6 +23,7 @@
 #include "extensions/browser/extension_host_delegate.h"
 #include "extensions/browser/extension_host_observer.h"
 #include "extensions/browser/extension_host_queue.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/browser/extensions_browser_client.h"
 #include "extensions/browser/load_monitoring_extension_host_queue.h"
@@ -77,15 +76,15 @@
 
   // Listen for when an extension is unloaded from the same profile, as it may
   // be the same extension that this points to.
-  registrar_.Add(this,
-                 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
-                 content::Source<BrowserContext>(browser_context_));
+  ExtensionRegistry::Get(browser_context_)->AddObserver(this);
 
   // Set up web contents observers and pref observers.
   delegate_->OnExtensionHostCreated(host_contents());
 }
 
 ExtensionHost::~ExtensionHost() {
+  ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
+
   if (extension_host_type_ == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE &&
       extension_ && BackgroundInfo::HasLazyBackgroundPage(extension_) &&
       load_start_.get()) {
@@ -210,23 +209,15 @@
   return true;
 }
 
-void ExtensionHost::Observe(int type,
-                            const content::NotificationSource& source,
-                            const content::NotificationDetails& details) {
-  switch (type) {
-    case extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED:
-      // The extension object will be deleted after this notification has been
-      // sent. Null it out so that dirty pointer issues don't arise in cases
-      // when multiple ExtensionHost objects pointing to the same Extension are
-      // present.
-      if (extension_ == content::Details<UnloadedExtensionInfo>(details)->
-          extension) {
-        extension_ = nullptr;
-      }
-      break;
-    default:
-      NOTREACHED() << "Unexpected notification sent.";
-      break;
+void ExtensionHost::OnExtensionUnloaded(
+    content::BrowserContext* browser_context,
+    const Extension* extension,
+    UnloadedExtensionInfo::Reason reason) {
+  // The extension object will be deleted after this notification has been sent.
+  // Null it out so that dirty pointer issues don't arise in cases when multiple
+  // ExtensionHost objects pointing to the same Extension are present.
+  if (extension_ == extension) {
+    extension_ = nullptr;
   }
 }
 
diff --git a/extensions/browser/extension_host.h b/extensions/browser/extension_host.h
index 953dc99..c308874 100644
--- a/extensions/browser/extension_host.h
+++ b/extensions/browser/extension_host.h
@@ -7,18 +7,16 @@
 
 #include <set>
 #include <string>
-#include <vector>
 
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "base/timer/elapsed_timer.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "extensions/browser/deferred_start_render_host.h"
 #include "extensions/browser/extension_function_dispatcher.h"
+#include "extensions/browser/extension_registry_observer.h"
 #include "extensions/common/stack_frame.h"
 #include "extensions/common/view_type.h"
 
@@ -49,7 +47,7 @@
                       public content::WebContentsDelegate,
                       public content::WebContentsObserver,
                       public ExtensionFunctionDispatcher::Delegate,
-                      public content::NotificationObserver {
+                      public ExtensionRegistryObserver {
  public:
   ExtensionHost(const Extension* extension,
                 content::SiteInstance* site_instance,
@@ -127,14 +125,12 @@
                                   content::MediaStreamType type) override;
   bool IsNeverVisible(content::WebContents* web_contents) override;
 
-  // content::NotificationObserver:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
+  // ExtensionRegistryObserver:
+  void OnExtensionUnloaded(content::BrowserContext* browser_context,
+                           const Extension* extension,
+                           UnloadedExtensionInfo::Reason reason) override;
 
  protected:
-  content::NotificationRegistrar* registrar() { return &registrar_; }
-
   // Called after the extension page finishes loading but before the
   // EXTENSION_HOST_DID_STOP_LOADING notification is sent.
   virtual void OnDidStopLoading();
@@ -191,8 +187,6 @@
   // Messages sent out to the renderer that have not been acknowledged yet.
   std::set<int> unacked_messages_;
 
-  content::NotificationRegistrar registrar_;
-
   ExtensionFunctionDispatcher extension_function_dispatcher_;
 
   // The type of view being hosted.
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index bc780bab..4c2e6cd 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -383,8 +383,6 @@
       'browser/api/networking_private/networking_private_event_router_factory.h',
       'browser/api/power/power_api.cc',
       'browser/api/power/power_api.h',
-      'browser/api/power/power_api_manager.cc',
-      'browser/api/power/power_api_manager.h',
       'browser/api/printer_provider/printer_provider_api.cc',
       'browser/api/printer_provider/printer_provider_api.h',
       'browser/api/printer_provider/printer_provider_api_factory.cc',
diff --git a/extensions/renderer/resources/binding.js b/extensions/renderer/resources/binding.js
index b1a3efca..22ccb7bd 100644
--- a/extensions/renderer/resources/binding.js
+++ b/extensions/renderer/resources/binding.js
@@ -275,13 +275,35 @@
       mod = mod[name];
     }
 
-    // Add types to global schemaValidator, the types we depend on from other
-    // namespaces will be added as needed.
     if (schema.types) {
       $Array.forEach(schema.types, function(t) {
         if (!isSchemaNodeSupported(t, platform, manifestVersion))
           return;
+
+        // Add types to global schemaValidator; the types we depend on from
+        // other namespaces will be added as needed.
         schemaUtils.schemaValidator.addTypes(t);
+
+        // Generate symbols for enums.
+        var enumValues = t['enum'];
+        if (enumValues) {
+          // Type IDs are qualified with the namespace during compilation,
+          // unfortunately, so remove it here.
+          logging.DCHECK(
+              t.id.substr(0, schema.namespace.length) == schema.namespace);
+          // Note: + 1 because it ends in a '.', e.g., 'fooApi.Type'.
+          var id = t.id.substr(schema.namespace.length + 1);
+          mod[id] = {};
+          $Array.forEach(enumValues, function(enumValue) {
+            // Note: enums can be declared either as a list of strings
+            // ['foo', 'bar'] or as a list of objects
+            // [{'name': 'foo'}, {'name': 'bar'}].
+            enumValue =
+                enumValue.hasOwnProperty('name') ? enumValue.name : enumValue;
+            if (enumValue)  // Avoid setting any empty enums.
+              mod[id][enumValue] = enumValue;
+          });
+        }
       }, this);
     }
 
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index 70aef276..2e12978 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -127,7 +127,7 @@
   }
 }
 
-if (!(is_chromeos && !use_ozone) && (!is_win || link_chrome_on_windows)) {
+if (!(is_chromeos && !use_ozone)) {
   executable("app_shell") {
     # testonly because :app_shell_lib is testonly. See :app_shell_lib comment.
     testonly = true
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index 1eae08f..b8ab4b6 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -198,45 +198,43 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("google_apis_unittests") {
-    sources = [
-      "gaia/gaia_auth_fetcher_unittest.cc",
-      "gaia/gaia_auth_util_unittest.cc",
-      "gaia/gaia_oauth_client_unittest.cc",
-      "gaia/google_service_auth_error_unittest.cc",
-      "gaia/merge_session_helper_unittest.cc",
-      "gaia/oauth2_access_token_fetcher_impl_unittest.cc",
-      "gaia/oauth2_api_call_flow_unittest.cc",
-      "gaia/oauth2_mint_token_flow_unittest.cc",
-      "gaia/oauth2_token_service_unittest.cc",
-      "gaia/oauth_request_signer_unittest.cc",
-      "gaia/ubertoken_fetcher_unittest.cc",
-      "google_api_keys_unittest.cc",
+test("google_apis_unittests") {
+  sources = [
+    "gaia/gaia_auth_fetcher_unittest.cc",
+    "gaia/gaia_auth_util_unittest.cc",
+    "gaia/gaia_oauth_client_unittest.cc",
+    "gaia/google_service_auth_error_unittest.cc",
+    "gaia/merge_session_helper_unittest.cc",
+    "gaia/oauth2_access_token_fetcher_impl_unittest.cc",
+    "gaia/oauth2_api_call_flow_unittest.cc",
+    "gaia/oauth2_mint_token_flow_unittest.cc",
+    "gaia/oauth2_token_service_unittest.cc",
+    "gaia/oauth_request_signer_unittest.cc",
+    "gaia/ubertoken_fetcher_unittest.cc",
+    "google_api_keys_unittest.cc",
+  ]
+
+  configs += [ ":key_defines" ]
+
+  deps = [
+    ":google_apis",
+    ":test_support",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (enable_extensions) {
+    sources += [
+      "drive/base_requests_server_unittest.cc",
+      "drive/base_requests_unittest.cc",
+      "drive/drive_api_parser_unittest.cc",
+      "drive/drive_api_requests_unittest.cc",
+      "drive/drive_api_url_generator_unittest.cc",
+      "drive/request_sender_unittest.cc",
+      "drive/request_util_unittest.cc",
+      "drive/time_util_unittest.cc",
     ]
-
-    configs += [ ":key_defines" ]
-
-    deps = [
-      ":google_apis",
-      ":test_support",
-      "//base",
-      "//base/test:run_all_unittests",
-      "//testing/gmock",
-      "//testing/gtest",
-    ]
-
-    if (enable_extensions) {
-      sources += [
-        "drive/base_requests_server_unittest.cc",
-        "drive/base_requests_unittest.cc",
-        "drive/drive_api_parser_unittest.cc",
-        "drive/drive_api_requests_unittest.cc",
-        "drive/drive_api_url_generator_unittest.cc",
-        "drive/request_sender_unittest.cc",
-        "drive/request_util_unittest.cc",
-        "drive/time_util_unittest.cc",
-      ]
-    }
   }
 }
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 86888bd..830464e9 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -66,221 +66,219 @@
   ]
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("gl_tests") {
-    sources = [
-      "command_buffer/tests/compressed_texture_test.cc",
-      "command_buffer/tests/gl_bind_uniform_location_unittest.cc",
-      "command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc",
-      "command_buffer/tests/gl_chromium_path_rendering_unittest.cc",
-      "command_buffer/tests/gl_clear_framebuffer_unittest.cc",
-      "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc",
-      "command_buffer/tests/gl_depth_texture_unittest.cc",
-      "command_buffer/tests/gl_gpu_memory_buffer_unittest.cc",
-      "command_buffer/tests/gl_lose_context_chromium_unittest.cc",
-      "command_buffer/tests/gl_manager.cc",
-      "command_buffer/tests/gl_manager.h",
-      "command_buffer/tests/gl_pointcoord_unittest.cc",
-      "command_buffer/tests/gl_program_unittest.cc",
-      "command_buffer/tests/gl_query_unittest.cc",
-      "command_buffer/tests/gl_readback_unittest.cc",
-      "command_buffer/tests/gl_shared_resources_unittest.cc",
-      "command_buffer/tests/gl_stream_draw_unittest.cc",
-      "command_buffer/tests/gl_test_utils.cc",
-      "command_buffer/tests/gl_test_utils.h",
-      "command_buffer/tests/gl_tests_main.cc",
-      "command_buffer/tests/gl_texture_mailbox_unittest.cc",
-      "command_buffer/tests/gl_texture_storage_unittest.cc",
-      "command_buffer/tests/gl_unittest.cc",
-      "command_buffer/tests/gl_unittests_android.cc",
-      "command_buffer/tests/gl_virtual_contexts_unittest.cc",
-      "command_buffer/tests/occlusion_query_unittest.cc",
-    ]
+test("gl_tests") {
+  sources = [
+    "command_buffer/tests/compressed_texture_test.cc",
+    "command_buffer/tests/gl_bind_uniform_location_unittest.cc",
+    "command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc",
+    "command_buffer/tests/gl_chromium_path_rendering_unittest.cc",
+    "command_buffer/tests/gl_clear_framebuffer_unittest.cc",
+    "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc",
+    "command_buffer/tests/gl_depth_texture_unittest.cc",
+    "command_buffer/tests/gl_gpu_memory_buffer_unittest.cc",
+    "command_buffer/tests/gl_lose_context_chromium_unittest.cc",
+    "command_buffer/tests/gl_manager.cc",
+    "command_buffer/tests/gl_manager.h",
+    "command_buffer/tests/gl_pointcoord_unittest.cc",
+    "command_buffer/tests/gl_program_unittest.cc",
+    "command_buffer/tests/gl_query_unittest.cc",
+    "command_buffer/tests/gl_readback_unittest.cc",
+    "command_buffer/tests/gl_shared_resources_unittest.cc",
+    "command_buffer/tests/gl_stream_draw_unittest.cc",
+    "command_buffer/tests/gl_test_utils.cc",
+    "command_buffer/tests/gl_test_utils.h",
+    "command_buffer/tests/gl_tests_main.cc",
+    "command_buffer/tests/gl_texture_mailbox_unittest.cc",
+    "command_buffer/tests/gl_texture_storage_unittest.cc",
+    "command_buffer/tests/gl_unittest.cc",
+    "command_buffer/tests/gl_unittests_android.cc",
+    "command_buffer/tests/gl_virtual_contexts_unittest.cc",
+    "command_buffer/tests/occlusion_query_unittest.cc",
+  ]
 
-    defines = [ "GL_GLEXT_PROTOTYPES" ]
+  defines = [ "GL_GLEXT_PROTOTYPES" ]
 
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
-    deps = [
-      ":gpu",
-      ":test_support",
-      "//base",
-      "//base/test:test_support",
-      "//base/third_party/dynamic_annotations",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//third_party/angle:translator",
-      "//ui/gfx",
-      "//ui/gfx:test_support",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-      "//gpu/command_buffer/common:gles2_utils",
-      "//gpu/command_buffer/client:gles2_c_lib",
-      "//gpu/command_buffer/client:gles2_implementation",
-    ]
+  deps = [
+    ":gpu",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/angle:translator",
+    "//ui/gfx",
+    "//ui/gfx:test_support",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//gpu/command_buffer/common:gles2_utils",
+    "//gpu/command_buffer/client:gles2_c_lib",
+    "//gpu/command_buffer/client:gles2_implementation",
+  ]
 
-    libs = []
+  libs = []
 
-    if (is_android) {
-      deps += [ "//testing/android:native_test_native_code" ]
-      libs += [ "android" ]
-    }
-
-    # TODO(GYP)
-    #     ['OS == "win"', {
-    #       'dependencies': [
-    #         '../third_party/angle/src/build_angle.gyp:libEGL',
-    #         '../third_party/angle/src/build_angle.gyp:libGLESv2',
-    #       ],
-    #     }],
+  if (is_android) {
+    deps += [ "//testing/android:native_test_native_code" ]
+    libs += [ "android" ]
   }
 
-  test("gpu_unittests") {
-    sources = [
-      "command_buffer/client/buffer_tracker_unittest.cc",
-      "command_buffer/client/client_test_helper.cc",
-      "command_buffer/client/client_test_helper.h",
-      "command_buffer/client/cmd_buffer_helper_test.cc",
-      "command_buffer/client/fenced_allocator_test.cc",
-      "command_buffer/client/gles2_implementation_unittest.cc",
-      "command_buffer/client/mapped_memory_unittest.cc",
-      "command_buffer/client/program_info_manager_unittest.cc",
-      "command_buffer/client/query_tracker_unittest.cc",
-      "command_buffer/client/ring_buffer_test.cc",
-      "command_buffer/client/transfer_buffer_unittest.cc",
-      "command_buffer/client/vertex_array_object_manager_unittest.cc",
-      "command_buffer/common/bitfield_helpers_test.cc",
-      "command_buffer/common/command_buffer_mock.cc",
-      "command_buffer/common/command_buffer_mock.h",
-      "command_buffer/common/command_buffer_shared_test.cc",
-      "command_buffer/common/debug_marker_manager_unittest.cc",
-      "command_buffer/common/gles2_cmd_format_test.cc",
-      "command_buffer/common/gles2_cmd_format_test_autogen.h",
-      "command_buffer/common/gles2_cmd_utils_unittest.cc",
-      "command_buffer/common/id_allocator_test.cc",
-      "command_buffer/common/trace_event.h",
-      "command_buffer/common/unittest_main.cc",
-      "command_buffer/service/async_pixel_transfer_delegate_mock.cc",
-      "command_buffer/service/async_pixel_transfer_delegate_mock.h",
-      "command_buffer/service/async_pixel_transfer_manager_mock.cc",
-      "command_buffer/service/async_pixel_transfer_manager_mock.h",
-      "command_buffer/service/buffer_manager_unittest.cc",
-      "command_buffer/service/cmd_parser_test.cc",
-      "command_buffer/service/command_buffer_service_unittest.cc",
-      "command_buffer/service/common_decoder_unittest.cc",
-      "command_buffer/service/context_group_unittest.cc",
-      "command_buffer/service/feature_info_unittest.cc",
-      "command_buffer/service/framebuffer_manager_unittest.cc",
-      "command_buffer/service/gl_surface_mock.cc",
-      "command_buffer/service/gl_surface_mock.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_1.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_2.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_3.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_base.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_base.h",
-      "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc",
-      "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc",
-      "command_buffer/service/gpu_scheduler_unittest.cc",
-      "command_buffer/service/gpu_service_test.cc",
-      "command_buffer/service/gpu_service_test.h",
-      "command_buffer/service/gpu_tracer_unittest.cc",
-      "command_buffer/service/id_manager_unittest.cc",
-      "command_buffer/service/mailbox_manager_unittest.cc",
-      "command_buffer/service/memory_program_cache_unittest.cc",
-      "command_buffer/service/mocks.cc",
-      "command_buffer/service/mocks.h",
-      "command_buffer/service/program_cache_unittest.cc",
-      "command_buffer/service/program_manager_unittest.cc",
-      "command_buffer/service/query_manager_unittest.cc",
-      "command_buffer/service/renderbuffer_manager_unittest.cc",
-      "command_buffer/service/shader_manager_unittest.cc",
-      "command_buffer/service/shader_translator_cache_unittest.cc",
-      "command_buffer/service/shader_translator_unittest.cc",
-      "command_buffer/service/test_helper.cc",
-      "command_buffer/service/test_helper.h",
-      "command_buffer/service/texture_manager_unittest.cc",
-      "command_buffer/service/transfer_buffer_manager_unittest.cc",
-      "command_buffer/service/valuebuffer_manager_unittest.cc",
-      "command_buffer/service/vertex_array_manager_unittest.cc",
-      "command_buffer/service/vertex_attrib_manager_unittest.cc",
-      "config/gpu_blacklist_unittest.cc",
-      "config/gpu_control_list_entry_unittest.cc",
-      "config/gpu_control_list_number_info_unittest.cc",
-      "config/gpu_control_list_os_info_unittest.cc",
-      "config/gpu_control_list_unittest.cc",
-      "config/gpu_control_list_version_info_unittest.cc",
-      "config/gpu_driver_bug_list_unittest.cc",
-      "config/gpu_info_collector_unittest.cc",
-      "config/gpu_info_unittest.cc",
-      "config/gpu_test_config_unittest.cc",
-      "config/gpu_test_expectations_parser_unittest.cc",
-      "config/gpu_util_unittest.cc",
-    ]
+  # TODO(GYP)
+  #     ['OS == "win"', {
+  #       'dependencies': [
+  #         '../third_party/angle/src/build_angle.gyp:libEGL',
+  #         '../third_party/angle/src/build_angle.gyp:libGLESv2',
+  #       ],
+  #     }],
+}
 
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+test("gpu_unittests") {
+  sources = [
+    "command_buffer/client/buffer_tracker_unittest.cc",
+    "command_buffer/client/client_test_helper.cc",
+    "command_buffer/client/client_test_helper.h",
+    "command_buffer/client/cmd_buffer_helper_test.cc",
+    "command_buffer/client/fenced_allocator_test.cc",
+    "command_buffer/client/gles2_implementation_unittest.cc",
+    "command_buffer/client/mapped_memory_unittest.cc",
+    "command_buffer/client/program_info_manager_unittest.cc",
+    "command_buffer/client/query_tracker_unittest.cc",
+    "command_buffer/client/ring_buffer_test.cc",
+    "command_buffer/client/transfer_buffer_unittest.cc",
+    "command_buffer/client/vertex_array_object_manager_unittest.cc",
+    "command_buffer/common/bitfield_helpers_test.cc",
+    "command_buffer/common/command_buffer_mock.cc",
+    "command_buffer/common/command_buffer_mock.h",
+    "command_buffer/common/command_buffer_shared_test.cc",
+    "command_buffer/common/debug_marker_manager_unittest.cc",
+    "command_buffer/common/gles2_cmd_format_test.cc",
+    "command_buffer/common/gles2_cmd_format_test_autogen.h",
+    "command_buffer/common/gles2_cmd_utils_unittest.cc",
+    "command_buffer/common/id_allocator_test.cc",
+    "command_buffer/common/trace_event.h",
+    "command_buffer/common/unittest_main.cc",
+    "command_buffer/service/async_pixel_transfer_delegate_mock.cc",
+    "command_buffer/service/async_pixel_transfer_delegate_mock.h",
+    "command_buffer/service/async_pixel_transfer_manager_mock.cc",
+    "command_buffer/service/async_pixel_transfer_manager_mock.h",
+    "command_buffer/service/buffer_manager_unittest.cc",
+    "command_buffer/service/cmd_parser_test.cc",
+    "command_buffer/service/command_buffer_service_unittest.cc",
+    "command_buffer/service/common_decoder_unittest.cc",
+    "command_buffer/service/context_group_unittest.cc",
+    "command_buffer/service/feature_info_unittest.cc",
+    "command_buffer/service/framebuffer_manager_unittest.cc",
+    "command_buffer/service/gl_surface_mock.cc",
+    "command_buffer/service/gl_surface_mock.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_1.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_2.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_3.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_async_pixel.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_base.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_base.h",
+    "command_buffer/service/gles2_cmd_decoder_unittest_context_state.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_drawing.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_programs.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_textures.cc",
+    "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc",
+    "command_buffer/service/gpu_scheduler_unittest.cc",
+    "command_buffer/service/gpu_service_test.cc",
+    "command_buffer/service/gpu_service_test.h",
+    "command_buffer/service/gpu_tracer_unittest.cc",
+    "command_buffer/service/id_manager_unittest.cc",
+    "command_buffer/service/mailbox_manager_unittest.cc",
+    "command_buffer/service/memory_program_cache_unittest.cc",
+    "command_buffer/service/mocks.cc",
+    "command_buffer/service/mocks.h",
+    "command_buffer/service/program_cache_unittest.cc",
+    "command_buffer/service/program_manager_unittest.cc",
+    "command_buffer/service/query_manager_unittest.cc",
+    "command_buffer/service/renderbuffer_manager_unittest.cc",
+    "command_buffer/service/shader_manager_unittest.cc",
+    "command_buffer/service/shader_translator_cache_unittest.cc",
+    "command_buffer/service/shader_translator_unittest.cc",
+    "command_buffer/service/test_helper.cc",
+    "command_buffer/service/test_helper.h",
+    "command_buffer/service/texture_manager_unittest.cc",
+    "command_buffer/service/transfer_buffer_manager_unittest.cc",
+    "command_buffer/service/valuebuffer_manager_unittest.cc",
+    "command_buffer/service/vertex_array_manager_unittest.cc",
+    "command_buffer/service/vertex_attrib_manager_unittest.cc",
+    "config/gpu_blacklist_unittest.cc",
+    "config/gpu_control_list_entry_unittest.cc",
+    "config/gpu_control_list_number_info_unittest.cc",
+    "config/gpu_control_list_os_info_unittest.cc",
+    "config/gpu_control_list_unittest.cc",
+    "config/gpu_control_list_version_info_unittest.cc",
+    "config/gpu_driver_bug_list_unittest.cc",
+    "config/gpu_info_collector_unittest.cc",
+    "config/gpu_info_unittest.cc",
+    "config/gpu_test_config_unittest.cc",
+    "config/gpu_test_expectations_parser_unittest.cc",
+    "config/gpu_util_unittest.cc",
+  ]
 
-    deps = [
-      ":gpu",
-      ":test_support",
-      "//base",
-      "//base/test:test_support",
-      "//base/third_party/dynamic_annotations",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//third_party/angle:translator",
-      "//ui/gfx",
-      "//ui/gfx:test_support",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-      "//gpu/command_buffer/common:gles2_utils",
-      "//gpu/command_buffer/client:gles2_c_lib",
-      "//gpu/command_buffer/client:gles2_implementation",
-    ]
-  }
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
-  test("gpu_perftests") {
-    sources = [
-      "perftests/measurements.cc",
-      "perftests/run_all_tests.cc",
-      "perftests/texture_upload_perftest.cc",
-    ]
+  deps = [
+    ":gpu",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/angle:translator",
+    "//ui/gfx",
+    "//ui/gfx:test_support",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//gpu/command_buffer/common:gles2_utils",
+    "//gpu/command_buffer/client:gles2_c_lib",
+    "//gpu/command_buffer/client:gles2_implementation",
+  ]
+}
 
-    deps = [
-      "//base",
-      "//base/test:test_support",
-      "//gpu/command_buffer/service",
-      "//testing/gtest",
-      "//testing/perf",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-    ]
-  }
+test("gpu_perftests") {
+  sources = [
+    "perftests/measurements.cc",
+    "perftests/run_all_tests.cc",
+    "perftests/texture_upload_perftest.cc",
+  ]
 
-  test("angle_unittests") {
-    sources = [
-      "angle_unittest_main.cc",
-    ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//gpu/command_buffer/service",
+    "//testing/gtest",
+    "//testing/perf",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+  ]
+}
 
-    deps = [
-      "//base",
-      "//base/test:test_support",
-      "//base/third_party/dynamic_annotations",
-      "//testing/gmock",
-      "//testing/gtest",
-      "//third_party/angle:translator_static",
-    ]
-  }
+test("angle_unittests") {
+  sources = [
+    "angle_unittest_main.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/angle:translator_static",
+  ]
 }
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 2acbc635..3af9413 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -381,8 +381,7 @@
   static const GLuint kMaxTransformFeedbackSeparateAttribs = 4;
   static const GLuint kMaxUniformBufferBindings = 36;
   static const GLuint kStartId = 1024;
-  static const GLuint kBuffersStartId =
-      GLES2Implementation::kClientSideArrayId + 2 * kNumTestContexts;
+  static const GLuint kBuffersStartId = 1;
   static const GLuint kFramebuffersStartId = 1;
   static const GLuint kProgramsAndShadersStartId = 1;
   static const GLuint kRenderbuffersStartId = 1;
diff --git a/gpu/command_buffer/common/id_allocator.cc b/gpu/command_buffer/common/id_allocator.cc
index 507b14e..eccb468 100644
--- a/gpu/command_buffer/common/id_allocator.cc
+++ b/gpu/command_buffer/common/id_allocator.cc
@@ -6,84 +6,200 @@
 
 #include "gpu/command_buffer/common/id_allocator.h"
 
+#include <limits>
 #include "base/logging.h"
 
 namespace gpu {
 
-IdAllocator::IdAllocator() {}
+IdAllocator::IdAllocator() {
+  COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero);
+  // Simplify the code by making sure that lower_bound(id) never
+  // returns the beginning of the map, if id is valid (eg !=
+  // kInvalidResource).
+  used_ids_.insert(std::make_pair(0u, 0u));
+}
 
 IdAllocator::~IdAllocator() {}
 
 ResourceId IdAllocator::AllocateID() {
-  ResourceId id;
-  ResourceIdSet::iterator iter = free_ids_.begin();
-  if (iter != free_ids_.end()) {
-    id = *iter;
-  } else {
-    id = LastUsedId() + 1;
-    if (!id) {
-      // We wrapped around to 0.
-      id = FindFirstUnusedId();
-    }
-  }
-  MarkAsUsed(id);
-  return id;
+  return AllocateIDRange(1u);
 }
 
 ResourceId IdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) {
-  ResourceId id;
-  ResourceIdSet::iterator iter = free_ids_.lower_bound(desired_id);
-  if (iter != free_ids_.end()) {
-    id = *iter;
-  } else if (LastUsedId() < desired_id) {
-    id = desired_id;
-  } else {
-    id = LastUsedId() + 1;
-    if (!id) {
-      // We wrapped around to 0.
-      id = FindFirstUnusedId();
-    }
+  if (desired_id == 0u || desired_id == 1u) {
+    return AllocateIDRange(1u);
   }
-  MarkAsUsed(id);
-  return id;
+
+  ResourceIdRangeMap::iterator current = used_ids_.lower_bound(desired_id);
+  ResourceIdRangeMap::iterator next = current;
+  if (current == used_ids_.end() || current->first > desired_id) {
+    current--;
+  } else {
+    next++;
+  }
+
+  ResourceId first_id = current->first;
+  ResourceId last_id = current->second;
+
+  DCHECK(desired_id >= first_id);
+
+  if (desired_id - 1u <= last_id) {
+    // Append to current range.
+    last_id++;
+    if (last_id == 0) {
+      // The increment overflowed.
+      return AllocateIDRange(1u);
+    }
+
+    current->second = last_id;
+
+    if (next != used_ids_.end() && next->first - 1u == last_id) {
+      // Merge with next range.
+      current->second = next->second;
+      used_ids_.erase(next);
+    }
+    return last_id;
+  } else if (next != used_ids_.end() && next->first - 1u == desired_id) {
+    // Prepend to next range.
+    ResourceId last_existing_id = next->second;
+    used_ids_.erase(next);
+    used_ids_.insert(std::make_pair(desired_id, last_existing_id));
+    return desired_id;
+  }
+  used_ids_.insert(std::make_pair(desired_id, desired_id));
+  return desired_id;
+}
+
+ResourceId IdAllocator::AllocateIDRange(uint32_t range) {
+  DCHECK(range > 0u);
+
+  ResourceIdRangeMap::iterator current = used_ids_.begin();
+  ResourceIdRangeMap::iterator next = current;
+
+  while (++next != used_ids_.end()) {
+    if (next->first - current->second > range) {
+      break;
+    }
+    current = next;
+  }
+
+  ResourceId first_id = current->second + 1u;
+  ResourceId last_id = first_id + range - 1u;
+
+  if (first_id == 0u || last_id < first_id) {
+    return kInvalidResource;
+  }
+
+  current->second = last_id;
+
+  if (next != used_ids_.end() && next->first - 1u == last_id) {
+    // Merge with next range.
+    current->second = next->second;
+    used_ids_.erase(next);
+  }
+
+  return first_id;
 }
 
 bool IdAllocator::MarkAsUsed(ResourceId id) {
   DCHECK(id);
-  free_ids_.erase(id);
-  std::pair<ResourceIdSet::iterator, bool> result = used_ids_.insert(id);
-  return result.second;
+  ResourceIdRangeMap::iterator current = used_ids_.lower_bound(id);
+  if (current != used_ids_.end() && current->first == id) {
+    return false;
+  }
+
+  ResourceIdRangeMap::iterator next = current;
+  --current;
+
+  if (current->second >= id) {
+    return false;
+  }
+
+  DCHECK(current->first < id && current->second < id);
+
+  if (current->second + 1u == id) {
+    // Append to current range.
+    current->second = id;
+    if (next != used_ids_.end() && next->first - 1u == id) {
+      // Merge with next range.
+      current->second = next->second;
+      used_ids_.erase(next);
+    }
+    return true;
+  } else if (next != used_ids_.end() && next->first - 1u == id) {
+    // Prepend to next range.
+    ResourceId last_existing_id = next->second;
+    used_ids_.erase(next);
+    used_ids_.insert(std::make_pair(id, last_existing_id));
+    return true;
+  }
+
+  used_ids_.insert(std::make_pair(id, id));
+  return true;
 }
 
 void IdAllocator::FreeID(ResourceId id) {
-  if (id) {
-    used_ids_.erase(id);
-    free_ids_.insert(id);
+  FreeIDRange(id, 1u);
+}
+
+void IdAllocator::FreeIDRange(ResourceId first_id, uint32 range) {
+  COMPILE_ASSERT(kInvalidResource == 0u, invalid_resource_is_not_zero);
+
+  if (range == 0u || (first_id == 0u && range == 1u)) {
+    return;
+  }
+
+  if (first_id == 0u) {
+    first_id++;
+    range--;
+  }
+
+  ResourceId last_id = first_id + range - 1u;
+  if (last_id < first_id) {
+    last_id = std::numeric_limits<ResourceId>::max();
+  }
+
+  while (true) {
+    ResourceIdRangeMap::iterator current = used_ids_.lower_bound(last_id);
+    if (current == used_ids_.end() || current->first > last_id) {
+      --current;
+    }
+
+    if (current->second < first_id) {
+      return;
+    }
+
+    if (current->first >= first_id) {
+      ResourceId last_existing_id = current->second;
+      used_ids_.erase(current);
+      if (last_id < last_existing_id) {
+        used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id));
+      }
+    } else if (current->second <= last_id) {
+      current->second = first_id - 1u;
+    } else {
+      DCHECK(current->first < first_id && current->second > last_id);
+      ResourceId last_existing_id = current->second;
+      current->second = first_id - 1u;
+      used_ids_.insert(std::make_pair(last_id + 1u, last_existing_id));
+    }
   }
 }
 
 bool IdAllocator::InUse(ResourceId id) const {
-  return id == kInvalidResource || used_ids_.find(id) != used_ids_.end();
-}
-
-ResourceId IdAllocator::LastUsedId() const {
-  if (used_ids_.empty()) {
-    return 0u;
-  } else {
-    return *used_ids_.rbegin();
+  if (id == kInvalidResource) {
+    return false;
   }
-}
 
-ResourceId IdAllocator::FindFirstUnusedId() const {
-  ResourceId id = 1;
-  for (ResourceIdSet::const_iterator it = used_ids_.begin();
-       it != used_ids_.end(); ++it) {
-    if ((*it) != id) {
-      return id;
+  ResourceIdRangeMap::const_iterator current = used_ids_.lower_bound(id);
+  if (current != used_ids_.end()) {
+    if (current->first == id) {
+      return true;
     }
-    ++id;
   }
-  return id;
+
+  --current;
+  return current->second >= id;
 }
 
 }  // namespace gpu
diff --git a/gpu/command_buffer/common/id_allocator.h b/gpu/command_buffer/common/id_allocator.h
index b8770830..118424f 100644
--- a/gpu/command_buffer/common/id_allocator.h
+++ b/gpu/command_buffer/common/id_allocator.h
@@ -9,7 +9,7 @@
 
 #include <stdint.h>
 
-#include <set>
+#include <map>
 #include <utility>
 
 #include "base/compiler_specific.h"
@@ -36,27 +36,28 @@
   // Note: may wrap if it starts near limit.
   ResourceId AllocateIDAtOrAbove(ResourceId desired_id);
 
+  // Allocates |range| amount of contiguous ids.
+  // Returns the first id to |first_id| or |kInvalidResource| if
+  // allocation failed.
+  ResourceId AllocateIDRange(uint32_t range);
+
   // Marks an id as used. Returns false if id was already used.
   bool MarkAsUsed(ResourceId id);
 
   // Frees a resource ID.
   void FreeID(ResourceId id);
 
+  // Frees a |range| amount of contiguous ids, starting from |first_id|.
+  void FreeIDRange(ResourceId first_id, uint32_t range);
+
   // Checks whether or not a resource ID is in use.
   bool InUse(ResourceId id) const;
 
  private:
-  // TODO(gman): This would work much better with ranges or a hash table.
-  typedef std::set<ResourceId> ResourceIdSet;
+  // first_id -> last_id mapping.
+  typedef std::map<ResourceId, ResourceId> ResourceIdRangeMap;
 
-  // The highest ID on the used list.
-  ResourceId LastUsedId() const;
-
-  // Lowest ID that isn't on the used list. This is slow, use as a last resort.
-  ResourceId FindFirstUnusedId() const;
-
-  ResourceIdSet used_ids_;
-  ResourceIdSet free_ids_;
+  ResourceIdRangeMap used_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(IdAllocator);
 };
diff --git a/gpu/command_buffer/common/id_allocator_test.cc b/gpu/command_buffer/common/id_allocator_test.cc
index adeed5b0..7d93906 100644
--- a/gpu/command_buffer/common/id_allocator_test.cc
+++ b/gpu/command_buffer/common/id_allocator_test.cc
@@ -125,4 +125,123 @@
   EXPECT_NE(kInvalidResource, id3);
 }
 
+TEST_F(IdAllocatorTest, AllocateIDRange) {
+  const ResourceId kMaxPossibleOffset = std::numeric_limits<ResourceId>::max();
+
+  IdAllocator* allocator = id_allocator();
+
+  ResourceId id1 = allocator->AllocateIDRange(1);
+  EXPECT_EQ(1u, id1);
+  ResourceId id2 = allocator->AllocateIDRange(2);
+  EXPECT_EQ(2u, id2);
+  ResourceId id3 = allocator->AllocateIDRange(3);
+  EXPECT_EQ(4u, id3);
+  ResourceId id4 = allocator->AllocateID();
+  EXPECT_EQ(7u, id4);
+  allocator->FreeID(3);
+  ResourceId id5 = allocator->AllocateIDRange(1);
+  EXPECT_EQ(3u, id5);
+  allocator->FreeID(5);
+  allocator->FreeID(2);
+  allocator->FreeID(4);
+  ResourceId id6 = allocator->AllocateIDRange(2);
+  EXPECT_EQ(4u, id6);
+  ResourceId id7 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset);
+  EXPECT_EQ(kMaxPossibleOffset, id7);
+  ResourceId id8 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset);
+  EXPECT_EQ(2u, id8);
+  ResourceId id9 = allocator->AllocateIDRange(50);
+  EXPECT_EQ(8u, id9);
+  ResourceId id10 = allocator->AllocateIDRange(50);
+  EXPECT_EQ(58u, id10);
+  // Remove all the low-numbered ids.
+  allocator->FreeID(1);
+  allocator->FreeID(15);
+  allocator->FreeIDRange(2, 107);
+  ResourceId id11 = allocator->AllocateIDRange(100);
+  EXPECT_EQ(1u, id11);
+  allocator->FreeID(kMaxPossibleOffset);
+  ResourceId id12 = allocator->AllocateIDRange(100);
+  EXPECT_EQ(101u, id12);
+
+  ResourceId id13 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset - 2u);
+  EXPECT_EQ(kMaxPossibleOffset - 2u, id13);
+  ResourceId id14 = allocator->AllocateIDRange(3);
+  EXPECT_EQ(201u, id14);
+}
+
+TEST_F(IdAllocatorTest, AllocateIDRangeEndNoEffect) {
+  const ResourceId kMaxPossibleOffset = std::numeric_limits<ResourceId>::max();
+
+  IdAllocator* allocator = id_allocator();
+  ResourceId id1 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset - 2u);
+  EXPECT_EQ(kMaxPossibleOffset - 2u, id1);
+  ResourceId id3 = allocator->AllocateIDRange(3);
+  EXPECT_EQ(1u, id3);
+  ResourceId id2 = allocator->AllocateIDRange(2);
+  EXPECT_EQ(4u, id2);
+}
+
+TEST_F(IdAllocatorTest, AllocateFullIDRange) {
+  const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
+  const ResourceId kFreedId = 555u;
+  IdAllocator* allocator = id_allocator();
+
+  ResourceId id1 = allocator->AllocateIDRange(kMaxPossibleRange);
+  EXPECT_EQ(1u, id1);
+  ResourceId id2 = allocator->AllocateID();
+  EXPECT_EQ(0u, id2);
+  allocator->FreeID(kFreedId);
+  ResourceId id3 = allocator->AllocateID();
+  EXPECT_EQ(kFreedId, id3);
+  ResourceId id4 = allocator->AllocateID();
+  EXPECT_EQ(0u, id4);
+  allocator->FreeID(kFreedId + 1u);
+  allocator->FreeID(kFreedId + 4u);
+  allocator->FreeID(kFreedId + 3u);
+  allocator->FreeID(kFreedId + 5u);
+  allocator->FreeID(kFreedId + 2u);
+  ResourceId id5 = allocator->AllocateIDRange(5);
+  EXPECT_EQ(kFreedId + 1u, id5);
+}
+
+TEST_F(IdAllocatorTest, AllocateIDRangeNoWrapInRange) {
+  const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
+  const ResourceId kAllocId = 10u;
+  IdAllocator* allocator = id_allocator();
+
+  ResourceId id1 = allocator->AllocateIDAtOrAbove(kAllocId);
+  EXPECT_EQ(kAllocId, id1);
+  ResourceId id2 = allocator->AllocateIDRange(kMaxPossibleRange - 5u);
+  EXPECT_EQ(0u, id2);
+  ResourceId id3 = allocator->AllocateIDRange(kMaxPossibleRange - kAllocId);
+  EXPECT_EQ(kAllocId + 1u, id3);
+}
+
+TEST_F(IdAllocatorTest, AllocateIdMax) {
+  const uint32_t kMaxPossibleRange = std::numeric_limits<uint32_t>::max();
+
+  IdAllocator* allocator = id_allocator();
+  ResourceId id = allocator->AllocateIDRange(kMaxPossibleRange);
+  EXPECT_EQ(1u, id);
+  allocator->FreeIDRange(id, kMaxPossibleRange - 1u);
+  ResourceId id2 = allocator->AllocateIDRange(kMaxPossibleRange);
+  EXPECT_EQ(0u, id2);
+  allocator->FreeIDRange(id, kMaxPossibleRange);
+  ResourceId id3 = allocator->AllocateIDRange(kMaxPossibleRange);
+  EXPECT_EQ(1u, id3);
+}
+
+TEST_F(IdAllocatorTest, ZeroIdCases) {
+  IdAllocator* allocator = id_allocator();
+  EXPECT_FALSE(allocator->InUse(0));
+  ResourceId id1 = allocator->AllocateIDAtOrAbove(0);
+  EXPECT_NE(0u, id1);
+  EXPECT_FALSE(allocator->InUse(0));
+  allocator->FreeID(0);
+  EXPECT_FALSE(allocator->InUse(0));
+  EXPECT_TRUE(allocator->InUse(id1));
+  allocator->FreeID(id1);
+  EXPECT_FALSE(allocator->InUse(id1));
+}
 }  // namespace gpu
diff --git a/ios/chrome/DEPS b/ios/chrome/DEPS
index 32c8bbd..e568d4e2 100644
--- a/ios/chrome/DEPS
+++ b/ios/chrome/DEPS
@@ -4,6 +4,8 @@
   "-ios/chrome",
   "+ios/chrome/grit",
 
+  "+components/dom_distiller/core",
+  "+components/dom_distiller/ios",
   "+components/infobars/core",
   "+components/keyed_service/core",
   "+components/keyed_service/ios",
diff --git a/ios/chrome/browser/dom_distiller/OWNER b/ios/chrome/browser/dom_distiller/OWNER
new file mode 100644
index 0000000..bf1620f
--- /dev/null
+++ b/ios/chrome/browser/dom_distiller/OWNER
@@ -0,0 +1 @@
+noyau@chromium.org
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.cc b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
new file mode 100644
index 0000000..bf30950
--- /dev/null
+++ b/ios/chrome/browser/dom_distiller/distiller_viewer.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/dom_distiller/distiller_viewer.h"
+
+#include <string>
+
+#include "components/dom_distiller/core/distilled_page_prefs.h"
+#include "components/dom_distiller/core/dom_distiller_service.h"
+#include "components/dom_distiller/core/proto/distilled_article.pb.h"
+#include "components/dom_distiller/core/task_tracker.h"
+#include "components/dom_distiller/core/viewer.h"
+#include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h"
+#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace dom_distiller {
+
+DistillerViewer::DistillerViewer(ios::ChromeBrowserState* browser_state,
+                                 const GURL& url,
+                                 const DistillationFinishedCallback& callback)
+    : url_(url),
+      callback_(callback),
+      distilled_page_prefs_(new DistilledPagePrefs(browser_state->GetPrefs())) {
+  DCHECK(browser_state);
+  DCHECK(url.is_valid());
+  dom_distiller::DomDistillerService* distillerService =
+      dom_distiller::DomDistillerServiceFactory::GetForBrowserState(
+          browser_state);
+
+  viewer_handle_ = distillerService->ViewUrl(
+      this, distillerService->CreateDefaultDistillerPage(gfx::Size()), url);
+}
+
+DistillerViewer::~DistillerViewer() {
+}
+
+void DistillerViewer::OnArticleReady(
+    const DistilledArticleProto* article_proto) {
+  const std::string html = viewer::GetUnsafeArticleHtml(
+      article_proto, distilled_page_prefs_->GetTheme(),
+      distilled_page_prefs_->GetFontFamily());
+
+  callback_.Run(url_, html);
+
+  // No need to hold on to the ViewerHandle now that distillation is complete.
+  viewer_handle_.reset();
+}
+
+}  // namespace dom_distiller
diff --git a/ios/chrome/browser/dom_distiller/distiller_viewer.h b/ios/chrome/browser/dom_distiller/distiller_viewer.h
new file mode 100644
index 0000000..d822755
--- /dev/null
+++ b/ios/chrome/browser/dom_distiller/distiller_viewer.h
@@ -0,0 +1,54 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_
+#define IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "components/dom_distiller/core/task_tracker.h"
+
+class GURL;
+
+namespace ios {
+class ChromeBrowserState;
+}
+
+namespace dom_distiller {
+
+class DistilledPagePrefs;
+
+// A very simple and naive implementation of the dom_distiller
+// ViewRequestDelegate: From an URL it builds an HTML string and notifies when
+// finished.
+class DistillerViewer : public dom_distiller::ViewRequestDelegate {
+ public:
+  typedef base::Callback<void(const GURL&, const std::string&)>
+      DistillationFinishedCallback;
+
+  DistillerViewer(ios::ChromeBrowserState* browser_state,
+                  const GURL& url,
+                  const DistillationFinishedCallback& callback);
+  ~DistillerViewer() override;
+
+  // ViewRequestDelegate.
+  void OnArticleUpdated(
+      dom_distiller::ArticleDistillationUpdate article_update) override {}
+  void OnArticleReady(const DistilledArticleProto* article_proto) override;
+
+ private:
+  // The url of the distilled page.
+  const GURL url_;
+  // Callback to invoke when the page is finished.
+  DistillationFinishedCallback callback_;
+  // Interface for accessing preferences for distilled pages.
+  scoped_ptr<DistilledPagePrefs> distilled_page_prefs_;
+  // Keeps the distiller going until the view is released.
+  scoped_ptr<dom_distiller::ViewerHandle> viewer_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(DistillerViewer);
+};
+
+}  // namespace dom_distiller
+
+#endif  // IOS_CHROME_BROWSER_DOM_DISTILLER_DISTILLER_VIEWER_H_
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
new file mode 100644
index 0000000..0adbfa7
--- /dev/null
+++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -0,0 +1,113 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h"
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "components/dom_distiller/core/article_entry.h"
+#include "components/dom_distiller/core/distiller.h"
+#include "components/dom_distiller/core/dom_distiller_service.h"
+#include "components/dom_distiller/core/dom_distiller_store.h"
+#include "components/dom_distiller/ios/distiller_page_factory_ios.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/leveldb_proto/proto_database.h"
+#include "components/leveldb_proto/proto_database_impl.h"
+#include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
+#include "ios/public/provider/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/web/public/browser_state.h"
+#include "ios/web/public/web_thread.h"
+
+namespace {
+// A simple wrapper for DomDistillerService to expose it as a
+// KeyedService.
+class DomDistillerKeyedService
+    : public KeyedService,
+      public dom_distiller::DomDistillerService {
+ public:
+  DomDistillerKeyedService(
+      scoped_ptr<dom_distiller::DomDistillerStoreInterface> store,
+      scoped_ptr<dom_distiller::DistillerFactory> distiller_factory,
+      scoped_ptr<dom_distiller::DistillerPageFactory> distiller_page_factory,
+      scoped_ptr<dom_distiller::DistilledPagePrefs> distilled_page_prefs)
+      : DomDistillerService(store.Pass(),
+                            distiller_factory.Pass(),
+                            distiller_page_factory.Pass(),
+                            distilled_page_prefs.Pass()) {}
+
+  ~DomDistillerKeyedService() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DomDistillerKeyedService);
+};
+}  // namespace
+
+namespace dom_distiller {
+
+// static
+DomDistillerServiceFactory* DomDistillerServiceFactory::GetInstance() {
+  return Singleton<DomDistillerServiceFactory>::get();
+}
+
+// static
+DomDistillerService* DomDistillerServiceFactory::GetForBrowserState(
+    web::BrowserState* browser_state) {
+  return static_cast<DomDistillerKeyedService*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+DomDistillerServiceFactory::DomDistillerServiceFactory()
+    : BrowserStateKeyedServiceFactory(
+          "DomDistillerService",
+          BrowserStateDependencyManager::GetInstance()) {
+}
+
+DomDistillerServiceFactory::~DomDistillerServiceFactory() {
+}
+
+KeyedService* DomDistillerServiceFactory::BuildServiceInstanceFor(
+    web::BrowserState* browser_state) const {
+  scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+      web::WebThread::GetBlockingPool()->GetSequencedTaskRunner(
+          web::WebThread::GetBlockingPool()->GetSequenceToken());
+
+  scoped_ptr<leveldb_proto::ProtoDatabaseImpl<ArticleEntry>> db(
+      new leveldb_proto::ProtoDatabaseImpl<ArticleEntry>(
+          background_task_runner));
+
+  base::FilePath database_dir(
+      browser_state->GetStatePath().Append(FILE_PATH_LITERAL("Articles")));
+
+  scoped_ptr<DomDistillerStore> dom_distiller_store(
+      new DomDistillerStore(db.Pass(), database_dir));
+
+  scoped_ptr<DistillerPageFactory> distiller_page_factory(
+      new DistillerPageFactoryIOS(browser_state));
+  scoped_ptr<DistillerURLFetcherFactory> distiller_url_fetcher_factory(
+      new DistillerURLFetcherFactory(browser_state->GetRequestContext()));
+
+  dom_distiller::proto::DomDistillerOptions options;
+  scoped_ptr<DistillerFactory> distiller_factory(
+      new DistillerFactoryImpl(distiller_url_fetcher_factory.Pass(), options));
+  scoped_ptr<DistilledPagePrefs> distilled_page_prefs(new DistilledPagePrefs(
+      ios::ChromeBrowserState::FromBrowserState(browser_state)->GetPrefs()));
+
+  DomDistillerKeyedService* service =
+      new DomDistillerKeyedService(
+          dom_distiller_store.Pass(), distiller_factory.Pass(),
+          distiller_page_factory.Pass(), distilled_page_prefs.Pass());
+
+  return service;
+}
+
+web::BrowserState* DomDistillerServiceFactory::GetBrowserStateToUse(
+    web::BrowserState* browser_state) const {
+  // Makes normal profile and off-the-record profile use same service instance.
+  return GetBrowserStateRedirectedInIncognito(browser_state);
+}
+
+}  // namespace dom_distiller
diff --git a/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h
new file mode 100644
index 0000000..802e0fe
--- /dev/null
+++ b/ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_
+#define IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_
+
+#include "components/dom_distiller/core/distilled_page_prefs.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+class KeyedService;
+
+namespace dom_distiller {
+class DomDistillerService;
+}
+
+namespace web {
+class BrowserState;
+}
+
+namespace dom_distiller {
+
+class DomDistillerServiceFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static DomDistillerServiceFactory* GetInstance();
+  static DomDistillerService* GetForBrowserState(
+      web::BrowserState* browser_state);
+
+ private:
+  friend struct DefaultSingletonTraits<DomDistillerServiceFactory>;
+
+  DomDistillerServiceFactory();
+  ~DomDistillerServiceFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  KeyedService* BuildServiceInstanceFor(
+      web::BrowserState* browser_state) const override;
+  web::BrowserState* GetBrowserStateToUse(
+      web::BrowserState* browser_state) const override;
+};
+
+}  // namespace dom_distiller
+
+#endif  // IOS_CHROME_BROWSER_DOM_DISTILLER_DOM_DISTILLER_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/suggestions/suggestions_service_factory.mm b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
index efd35e5..400ff13 100644
--- a/ios/chrome/browser/suggestions/suggestions_service_factory.mm
+++ b/ios/chrome/browser/suggestions/suggestions_service_factory.mm
@@ -59,7 +59,7 @@
   ios::ChromeBrowserState* chrome_browser_state =
       ios::ChromeBrowserState::FromBrowserState(browser_state);
   base::FilePath database_dir(
-      chrome_browser_state->GetPath().Append(kThumbnailDirectory));
+      chrome_browser_state->GetStatePath().Append(kThumbnailDirectory));
   scoped_ptr<SuggestionsStore> suggestions_store(
       new SuggestionsStore(chrome_browser_state->GetPrefs()));
   scoped_ptr<BlacklistStore> blacklist_store(
diff --git a/ios/chrome/ios_chrome.gyp b/ios/chrome/ios_chrome.gyp
index 5e68dea..4c2de56 100644
--- a/ios/chrome/ios_chrome.gyp
+++ b/ios/chrome/ios_chrome.gyp
@@ -15,6 +15,8 @@
       ],
       'dependencies': [
         '../../base/base.gyp:base',
+        '../../components/components.gyp:dom_distiller_core',
+        '../../components/components.gyp:dom_distiller_ios',
         '../../components/components.gyp:infobars_core',
         '../../components/components.gyp:keyed_service_core',
         '../../components/components.gyp:keyed_service_ios',
@@ -54,6 +56,10 @@
         'browser/browser_state/browser_state_otr_helper.h',
         'browser/chrome_url_constants.cc',
         'browser/chrome_url_constants.h',
+        'browser/dom_distiller/distiller_viewer.cc',
+        'browser/dom_distiller/distiller_viewer.h',
+        'browser/dom_distiller/dom_distiller_service_factory.cc',
+        'browser/dom_distiller/dom_distiller_service_factory.h',
         'browser/infobars/confirm_infobar_controller.h',
         'browser/infobars/confirm_infobar_controller.mm',
         'browser/infobars/infobar.h',
@@ -101,12 +107,12 @@
         'browser/translate/translate_service_ios.h',
         'browser/ui/animation_util.h',
         'browser/ui/animation_util.mm',
-        'browser/ui/commands/UIKit+ChromeExecuteCommand.h',
-        'browser/ui/commands/UIKit+ChromeExecuteCommand.mm',
         'browser/ui/commands/generic_chrome_command.h',
         'browser/ui/commands/generic_chrome_command.mm',
         'browser/ui/commands/open_url_command.h',
         'browser/ui/commands/open_url_command.mm',
+        'browser/ui/commands/UIKit+ChromeExecuteCommand.h',
+        'browser/ui/commands/UIKit+ChromeExecuteCommand.mm',
         'browser/ui/image_util.h',
         'browser/ui/image_util.mm',
         'browser/ui/reversed_animation.h',
diff --git a/ios/web/public/browser_state.h b/ios/web/public/browser_state.h
index 0a3c131..b4f2ade 100644
--- a/ios/web/public/browser_state.h
+++ b/ios/web/public/browser_state.h
@@ -28,7 +28,9 @@
   virtual bool IsOffTheRecord() const = 0;
 
   // Returns the path where the BrowserState data is stored.
-  virtual base::FilePath GetPath() const = 0;
+  // Unlike Profile::GetPath(), incognito BrowserState do not share their path
+  // with their original BrowserState.
+  virtual base::FilePath GetStatePath() const = 0;
 
   // Returns the request context information associated with this
   // BrowserState.
diff --git a/ios/web/public/test/test_browser_state.cc b/ios/web/public/test/test_browser_state.cc
index f9d428c..a5af592 100644
--- a/ios/web/public/test/test_browser_state.cc
+++ b/ios/web/public/test/test_browser_state.cc
@@ -17,7 +17,7 @@
   return false;
 }
 
-base::FilePath TestBrowserState::GetPath() const {
+base::FilePath TestBrowserState::GetStatePath() const {
   return base::FilePath();
 }
 
diff --git a/ios/web/public/test/test_browser_state.h b/ios/web/public/test/test_browser_state.h
index 320ba00..7544548 100644
--- a/ios/web/public/test/test_browser_state.h
+++ b/ios/web/public/test/test_browser_state.h
@@ -15,7 +15,7 @@
 
   // BrowserState:
   bool IsOffTheRecord() const override;
-  base::FilePath GetPath() const override;
+  base::FilePath GetStatePath() const override;
   net::URLRequestContextGetter* GetRequestContext() override;
 };
 }  // namespace web
diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc
index 954ba96c..eb52e3a5 100644
--- a/media/base/android/media_player_android.cc
+++ b/media/base/android/media_player_android.cc
@@ -21,6 +21,7 @@
       player_id_(player_id),
       manager_(manager),
       frame_url_(frame_url),
+      is_audible_(false),
       weak_factory_(this) {
   listener_.reset(new MediaPlayerListener(base::MessageLoopProxy::current(),
                                           weak_factory_.GetWeakPtr()));
@@ -79,5 +80,11 @@
   listener_->ReleaseMediaPlayerListenerResources();
 }
 
+void MediaPlayerAndroid::SetAudible(bool is_audible) {
+  if (is_audible_ != is_audible) {
+    is_audible_ = is_audible;
+    manager_->OnAudibleStateChanged(player_id(), is_audible_);
+  }
+}
 
 }  // namespace media
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h
index cd5a92f1..d9091d4 100644
--- a/media/base/android/media_player_android.h
+++ b/media/base/android/media_player_android.h
@@ -102,6 +102,7 @@
   // events. Otherwise, it also listens to the events from |j_media_player|.
   void AttachListener(jobject j_media_player);
   void DetachListener();
+  void SetAudible(bool is_audible);
 
   MediaPlayerManager* manager() { return manager_; }
 
@@ -122,6 +123,9 @@
   // Listener object that listens to all the media player events.
   scoped_ptr<MediaPlayerListener> listener_;
 
+  // Maintains the audible state of the player, true if it is playing sound.
+  bool is_audible_;
+
   // Weak pointer passed to |listener_| for callbacks.
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<MediaPlayerAndroid> weak_factory_;
diff --git a/media/base/android/media_player_bridge.cc b/media/base/android/media_player_bridge.cc
index a9bf7e4..ed8854f 100644
--- a/media/base/android/media_player_bridge.cc
+++ b/media/base/android/media_player_bridge.cc
@@ -355,6 +355,8 @@
   if (j_media_player_bridge_.is_null())
     return;
 
+  SetAudible(false);
+
   time_update_timer_.Stop();
   if (prepared_) {
     pending_seek_ = GetCurrentTime();
@@ -371,15 +373,22 @@
 }
 
 void MediaPlayerBridge::SetVolume(double volume) {
-  if (j_media_player_bridge_.is_null()) {
-    volume_ = volume;
+  volume_ = volume;
+
+  if (j_media_player_bridge_.is_null())
     return;
-  }
 
   JNIEnv* env = base::android::AttachCurrentThread();
   CHECK(env);
+
+  // Update the audible state if we are playing.
+  jboolean is_playing = Java_MediaPlayerBridge_isPlaying(
+      env, j_media_player_bridge_.obj());
+  if (is_playing)
+    SetAudible(volume_ > 0);
+
   Java_MediaPlayerBridge_setVolume(
-      env, j_media_player_bridge_.obj(), volume);
+      env, j_media_player_bridge_.obj(), volume_);
 }
 
 void MediaPlayerBridge::OnVideoSizeChanged(int width, int height) {
@@ -389,11 +398,13 @@
 }
 
 void MediaPlayerBridge::OnPlaybackComplete() {
+  SetAudible(false);
   time_update_timer_.Stop();
   MediaPlayerAndroid::OnPlaybackComplete();
 }
 
 void MediaPlayerBridge::OnMediaInterrupted() {
+  SetAudible(false);
   time_update_timer_.Stop();
   MediaPlayerAndroid::OnMediaInterrupted();
 }
@@ -453,9 +464,13 @@
         base::TimeDelta::FromMilliseconds(kTimeUpdateInterval),
         this, &MediaPlayerBridge::OnTimeUpdateTimerFired);
   }
+
+  SetAudible(volume_ > 0);
 }
 
 void MediaPlayerBridge::PauseInternal() {
+  SetAudible(false);
+
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_MediaPlayerBridge_pause(env, j_media_player_bridge_.obj());
   time_update_timer_.Stop();
diff --git a/media/base/android/media_player_manager.h b/media/base/android/media_player_manager.h
index 58a712f..de23d4f 100644
--- a/media/base/android/media_player_manager.h
+++ b/media/base/android/media_player_manager.h
@@ -63,6 +63,9 @@
   // Called when video size has changed. Args: player ID, width, height.
   virtual void OnVideoSizeChanged(int player_id, int width, int height) = 0;
 
+  // Called when the player thinks it stopped or started making sound.
+  virtual void OnAudibleStateChanged(int player_id, bool is_audible_now) = 0;
+
   // Returns the player that's in the fullscreen mode currently.
   virtual MediaPlayerAndroid* GetFullscreenPlayer() = 0;
 
diff --git a/media/base/android/media_source_player_unittest.cc b/media/base/android/media_source_player_unittest.cc
index 9ac934e..6750537 100644
--- a/media/base/android/media_source_player_unittest.cc
+++ b/media/base/android/media_source_player_unittest.cc
@@ -75,6 +75,7 @@
                       const base::TimeDelta& current_time) override {}
   void OnError(int player_id, int error) override {}
   void OnVideoSizeChanged(int player_id, int width, int height) override {}
+  void OnAudibleStateChanged(int player_id, bool is_audible_now) override {}
   MediaPlayerAndroid* GetFullscreenPlayer() override { return NULL; }
   MediaPlayerAndroid* GetPlayer(int player_id) override { return NULL; }
   void RequestFullScreen(int player_id) override {}
diff --git a/media/base/audio_renderer.h b/media/base/audio_renderer.h
index 7d0e3d76..586936a 100644
--- a/media/base/audio_renderer.h
+++ b/media/base/audio_renderer.h
@@ -39,13 +39,18 @@
   // |ended_cb| is executed when audio rendering has reached the end of stream.
   //
   // |error_cb| is executed if an error was encountered after initialization.
-  virtual void Initialize(DemuxerStream* stream,
-                          const PipelineStatusCB& init_cb,
-                          const SetDecryptorReadyCB& set_decryptor_ready_cb,
-                          const StatisticsCB& statistics_cb,
-                          const BufferingStateCB& buffering_state_cb,
-                          const base::Closure& ended_cb,
-                          const PipelineStatusCB& error_cb) = 0;
+  //
+  // |waiting_for_decryption_key_cb| is called whenever the key needed to
+  // decrypt the stream is not available.
+  virtual void Initialize(
+      DemuxerStream* stream,
+      const PipelineStatusCB& init_cb,
+      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const StatisticsCB& statistics_cb,
+      const BufferingStateCB& buffering_state_cb,
+      const base::Closure& ended_cb,
+      const PipelineStatusCB& error_cb,
+      const base::Closure& waiting_for_decryption_key_cb) = 0;
 
   // Returns the TimeSource associated with audio rendering.
   virtual TimeSource* GetTimeSource() = 0;
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index c8d1c822..9731fd0f 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -121,16 +121,17 @@
   virtual ~MockVideoRenderer();
 
   // VideoRenderer implementation.
-  MOCK_METHOD9(Initialize,
-               void(DemuxerStream* stream,
-                    const PipelineStatusCB& init_cb,
-                    const SetDecryptorReadyCB& set_decryptor_ready_cb,
-                    const StatisticsCB& statistics_cb,
-                    const BufferingStateCB& buffering_state_cb,
-                    const PaintCB& paint_cb,
-                    const base::Closure& ended_cb,
-                    const PipelineStatusCB& error_cb,
-                    const TimeDeltaCB& get_time_cb));
+  MOCK_METHOD10(Initialize,
+                void(DemuxerStream* stream,
+                     const PipelineStatusCB& init_cb,
+                     const SetDecryptorReadyCB& set_decryptor_ready_cb,
+                     const StatisticsCB& statistics_cb,
+                     const BufferingStateCB& buffering_state_cb,
+                     const PaintCB& paint_cb,
+                     const base::Closure& ended_cb,
+                     const PipelineStatusCB& error_cb,
+                     const TimeDeltaCB& get_time_cb,
+                     const base::Closure& waiting_for_decryption_key_cb));
   MOCK_METHOD1(Flush, void(const base::Closure& callback));
   MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta));
 
@@ -144,14 +145,15 @@
   virtual ~MockAudioRenderer();
 
   // AudioRenderer implementation.
-  MOCK_METHOD7(Initialize,
+  MOCK_METHOD8(Initialize,
                void(DemuxerStream* stream,
                     const PipelineStatusCB& init_cb,
                     const SetDecryptorReadyCB& set_decryptor_ready_cb,
                     const StatisticsCB& statistics_cb,
                     const BufferingStateCB& buffering_state_cb,
                     const base::Closure& ended_cb,
-                    const PipelineStatusCB& error_cb));
+                    const PipelineStatusCB& error_cb,
+                    const base::Closure& waiting_for_decryption_key_cb));
   MOCK_METHOD0(GetTimeSource, TimeSource*());
   MOCK_METHOD1(Flush, void(const base::Closure& callback));
   MOCK_METHOD0(StartPlaying, void());
@@ -167,13 +169,15 @@
   virtual ~MockRenderer();
 
   // Renderer implementation.
-  MOCK_METHOD7(Initialize, void(DemuxerStreamProvider* demuxer_stream_provider,
-                                const PipelineStatusCB& init_cb,
-                                const StatisticsCB& statistics_cb,
-                                const BufferingStateCB& buffering_state_cb,
-                                const PaintCB& paint_cb,
-                                const base::Closure& ended_cb,
-                                const PipelineStatusCB& error_cb));
+  MOCK_METHOD8(Initialize,
+               void(DemuxerStreamProvider* demuxer_stream_provider,
+                    const PipelineStatusCB& init_cb,
+                    const StatisticsCB& statistics_cb,
+                    const BufferingStateCB& buffering_state_cb,
+                    const PaintCB& paint_cb,
+                    const base::Closure& ended_cb,
+                    const PipelineStatusCB& error_cb,
+                    const base::Closure& waiting_for_decryption_key_cb));
   MOCK_METHOD1(Flush, void(const base::Closure& flush_cb));
   MOCK_METHOD1(StartPlayingFrom, void(base::TimeDelta timestamp));
   MOCK_METHOD1(SetPlaybackRate, void(float playback_rate));
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index e9c52d66..d1fae01 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -70,7 +70,8 @@
                      const BufferingStateCB& buffering_state_cb,
                      const PaintCB& paint_cb,
                      const base::Closure& duration_change_cb,
-                     const AddTextTrackCB& add_text_track_cb) {
+                     const AddTextTrackCB& add_text_track_cb,
+                     const base::Closure& waiting_for_decryption_key_cb) {
   DCHECK(!ended_cb.is_null());
   DCHECK(!error_cb.is_null());
   DCHECK(!seek_cb.is_null());
@@ -92,6 +93,7 @@
   paint_cb_ = paint_cb;
   duration_change_cb_ = duration_change_cb;
   add_text_track_cb_ = add_text_track_cb;
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
   task_runner_->PostTask(
       FROM_HERE, base::Bind(&Pipeline::StartTask, weak_factory_.GetWeakPtr()));
@@ -724,7 +726,8 @@
       base::Bind(&Pipeline::BufferingStateChanged, weak_this),
       base::ResetAndReturn(&paint_cb_),
       base::Bind(&Pipeline::OnRendererEnded, weak_this),
-      base::Bind(&Pipeline::OnError, weak_this));
+      base::Bind(&Pipeline::OnError, weak_this),
+      waiting_for_decryption_key_cb_);
 }
 
 void Pipeline::ReportMetadata() {
diff --git a/media/base/pipeline.h b/media/base/pipeline.h
index 6bca477..30707b3 100644
--- a/media/base/pipeline.h
+++ b/media/base/pipeline.h
@@ -105,6 +105,8 @@
   //   |duration_change_cb| optional callback that will be executed whenever the
   //                        presentation duration changes.
   //   |add_text_track_cb| will be executed whenever a text track is added.
+  //   |waiting_for_decryption_key_cb| will be executed whenever the key needed
+  //                                   to decrypt the stream is not available.
   // It is an error to call this method after the pipeline has already started.
   void Start(Demuxer* demuxer,
              scoped_ptr<Renderer> renderer,
@@ -115,7 +117,8 @@
              const BufferingStateCB& buffering_state_cb,
              const PaintCB& paint_cb,
              const base::Closure& duration_change_cb,
-             const AddTextTrackCB& add_text_track_cb);
+             const AddTextTrackCB& add_text_track_cb,
+             const base::Closure& waiting_for_decryption_key_cb);
 
   // Asynchronously stops the pipeline, executing |stop_cb| when the pipeline
   // teardown has completed.
@@ -360,6 +363,7 @@
   PaintCB paint_cb_;
   base::Closure duration_change_cb_;
   AddTextTrackCB add_text_track_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // Holds the initialized demuxer. Used for seeking. Owned by client.
   Demuxer* demuxer_;
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc
index affb643..147e744 100644
--- a/media/base/pipeline_unittest.cc
+++ b/media/base/pipeline_unittest.cc
@@ -170,7 +170,7 @@
 
   // Sets up expectations to allow the video renderer to initialize.
   void SetRendererExpectations() {
-    EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
+    EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
         .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
                         SaveArg<5>(&ended_cb_),
                         PostCallback<1>(PIPELINE_OK)));
@@ -187,6 +187,7 @@
   }
 
   void StartPipeline() {
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     pipeline_->Start(
         demuxer_.get(), scoped_renderer_.Pass(),
         base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
@@ -199,7 +200,9 @@
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnDurationChange,
                    base::Unretained(&callbacks_)),
-        base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)));
+        base::Bind(&PipelineTest::OnAddTextTrack, base::Unretained(this)),
+        base::Bind(&PipelineTest::OnWaitingForDecryptionKey,
+                   base::Unretained(this)));
   }
 
   // Sets up expectations on the callback and initializes the pipeline. Called
@@ -296,6 +299,7 @@
 
   MOCK_METHOD2(OnAddTextTrack, void(const TextTrackConfig&,
                                     const AddTextTrackDoneCB&));
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   void DoOnAddTextTrack(const TextTrackConfig& config,
                         const AddTextTrackDoneCB& done_cb) {
@@ -857,13 +861,13 @@
 
     if (state == kInitRenderer) {
       if (stop_or_error == kStop) {
-        EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
+        EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
             .WillOnce(DoAll(Stop(pipeline_.get(), stop_cb),
                             PostCallback<1>(PIPELINE_OK)));
         ExpectPipelineStopAndDestroyPipeline();
       } else {
         status = PIPELINE_ERROR_INITIALIZATION_FAILED;
-        EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
+        EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
             .WillOnce(PostCallback<1>(status));
       }
 
@@ -872,7 +876,7 @@
       return status;
     }
 
-    EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _))
+    EXPECT_CALL(*renderer_, Initialize(_, _, _, _, _, _, _, _))
         .WillOnce(DoAll(SaveArg<3>(&buffering_state_cb_),
                         PostCallback<1>(PIPELINE_OK)));
 
diff --git a/media/base/renderer.h b/media/base/renderer.h
index 1c7afbd98..e3647f7 100644
--- a/media/base/renderer.h
+++ b/media/base/renderer.h
@@ -43,13 +43,17 @@
   //               be called from any thread.
   // - |ended_cb|: Executed when rendering has reached the end of stream.
   // - |error_cb|: Executed if any error was encountered after initialization.
-  virtual void Initialize(DemuxerStreamProvider* demuxer_stream_provider,
-                          const PipelineStatusCB& init_cb,
-                          const StatisticsCB& statistics_cb,
-                          const BufferingStateCB& buffering_state_cb,
-                          const PaintCB& paint_cb,
-                          const base::Closure& ended_cb,
-                          const PipelineStatusCB& error_cb) = 0;
+  // - |waiting_for_decryption_key_cb|: Executed whenever the key needed to
+  //                                    decrypt the stream is not available.
+  virtual void Initialize(
+      DemuxerStreamProvider* demuxer_stream_provider,
+      const PipelineStatusCB& init_cb,
+      const StatisticsCB& statistics_cb,
+      const BufferingStateCB& buffering_state_cb,
+      const PaintCB& paint_cb,
+      const base::Closure& ended_cb,
+      const PipelineStatusCB& error_cb,
+      const base::Closure& waiting_for_decryption_key_cb) = 0;
 
   // Associates the |cdm_context| with this Renderer for decryption (and
   // decoding) of media data, then fires |cdm_attached_cb| with the result.
diff --git a/media/base/video_renderer.h b/media/base/video_renderer.h
index 1e44333..7a764b3 100644
--- a/media/base/video_renderer.h
+++ b/media/base/video_renderer.h
@@ -53,15 +53,20 @@
   // |error_cb| is executed if an error was encountered after initialization.
   //
   // |get_time_cb| is used to query the current media playback time.
-  virtual void Initialize(DemuxerStream* stream,
-                          const PipelineStatusCB& init_cb,
-                          const SetDecryptorReadyCB& set_decryptor_ready_cb,
-                          const StatisticsCB& statistics_cb,
-                          const BufferingStateCB& buffering_state_cb,
-                          const PaintCB& paint_cb,
-                          const base::Closure& ended_cb,
-                          const PipelineStatusCB& error_cb,
-                          const TimeDeltaCB& get_time_cb) = 0;
+  //
+  // |waiting_for_decryption_key_cb| is executed whenever the key needed to
+  // decrypt the stream is not available.
+  virtual void Initialize(
+      DemuxerStream* stream,
+      const PipelineStatusCB& init_cb,
+      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const StatisticsCB& statistics_cb,
+      const BufferingStateCB& buffering_state_cb,
+      const PaintCB& paint_cb,
+      const base::Closure& ended_cb,
+      const PipelineStatusCB& error_cb,
+      const TimeDeltaCB& get_time_cb,
+      const base::Closure& waiting_for_decryption_key_cb) = 0;
 
   // Discards any video data and stops reading from |stream|, executing
   // |callback| when completed.
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index bb52f5e..33d26d5 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -83,7 +83,7 @@
   }
 }
 
-if (!is_mac && (!is_win || link_chrome_on_windows)) {
+if (!is_mac) {
   # TODO(GYP): Make linking this work on the mac.
   test("media_blink_unittests") {
     deps = [
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index a7a7201..148daf61 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -692,6 +692,15 @@
                      base::saturated_cast<unsigned int>(init_data.size()));
 }
 
+void WebMediaPlayerImpl::OnWaitingForDecryptionKey() {
+  client_->didBlockPlaybackWaitingForKey();
+
+  // TODO(jrummell): didResumePlaybackBlockedForKey() should only be called
+  // when a key has been successfully added (e.g. OnSessionKeysChange() with
+  // |has_additional_usable_key| = true). http://crbug.com/461903
+  client_->didResumePlaybackBlockedForKey();
+}
+
 void WebMediaPlayerImpl::SetCdm(CdmContext* cdm_context,
                                 const CdmAttachedCB& cdm_attached_cb) {
   pipeline_.SetCdm(cdm_context, cdm_attached_cb);
@@ -903,7 +912,8 @@
       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged),
       base::Bind(&WebMediaPlayerImpl::FrameReady, base::Unretained(this)),
       BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnDurationChanged),
-      BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack));
+      BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnAddTextTrack),
+      BIND_TO_RENDER_LOOP(&WebMediaPlayerImpl::OnWaitingForDecryptionKey));
 }
 
 void WebMediaPlayerImpl::SetNetworkState(WebMediaPlayer::NetworkState state) {
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
index acfdf97..0dc60db 100644
--- a/media/blink/webmediaplayer_impl.h
+++ b/media/blink/webmediaplayer_impl.h
@@ -212,6 +212,10 @@
   void OnEncryptedMediaInitData(const std::string& init_data_type,
                                 const std::vector<uint8>& init_data);
 
+  // Called when a decoder detects that the key needed to decrypt the stream
+  // is not available.
+  void OnWaitingForDecryptionKey();
+
   void SetCdm(CdmContext* cdm_context, const CdmAttachedCB& cdm_attached_cb);
 
   // Called when a CDM has been attached to the |pipeline_|.
diff --git a/media/cast/sender/vp8_encoder.cc b/media/cast/sender/vp8_encoder.cc
index fae960e..4d397b6 100644
--- a/media/cast/sender/vp8_encoder.cc
+++ b/media/cast/sender/vp8_encoder.cc
@@ -80,9 +80,10 @@
                << frame_size.ToString();
       config_.g_w = frame_size.width();
       config_.g_h = frame_size.height();
-      CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK)
-          << "Failed to update frame size in encoder config.";
-      return;
+      if (vpx_codec_enc_config_set(&encoder_, &config_) == VPX_CODEC_OK)
+        return;
+      DVLOG(1) << "libvpx rejected the attempt to use a smaller frame size in "
+                  "the current instance.";
     }
 
     DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: "
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 36f7ca64..2bb1f6d2 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -135,7 +135,8 @@
                    base::Unretained(this)),
         base::Bind(&AudioDecoderSelectorTest::MockOnDecoderSelected,
                    base::Unretained(this)),
-        base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput));
+        base::Bind(&AudioDecoderSelectorTest::OnDecoderOutput),
+        base::Bind(&AudioDecoderSelectorTest::OnWaitingForDecryptionKey));
     message_loop_.RunUntilIdle();
   }
 
@@ -151,6 +152,10 @@
     NOTREACHED();
   }
 
+  static void OnWaitingForDecryptionKey() {
+    NOTREACHED();
+  }
+
   // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since
   // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|.
   scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index f026acd..555a411 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -75,13 +75,15 @@
     DemuxerStream* stream,
     const SetDecryptorReadyCB& set_decryptor_ready_cb,
     const SelectDecoderCB& select_decoder_cb,
-    const typename Decoder::OutputCB& output_cb) {
+    const typename Decoder::OutputCB& output_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(stream);
   DCHECK(select_decoder_cb_.is_null());
 
   set_decryptor_ready_cb_ = set_decryptor_ready_cb;
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
   // Make sure |select_decoder_cb| runs on a different execution stack.
   select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb);
@@ -107,7 +109,7 @@
   }
 
   decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
-      task_runner_, set_decryptor_ready_cb_));
+      task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_));
 
   DecoderStreamTraits<StreamType>::InitializeDecoder(
       decoder_.get(), input_stream_,
@@ -130,8 +132,8 @@
 
   decoder_.reset();
 
-  decrypted_stream_.reset(
-      new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_));
+  decrypted_stream_.reset(new DecryptingDemuxerStream(
+      task_runner_, set_decryptor_ready_cb_, waiting_for_decryption_key_cb_));
 
   decrypted_stream_->Initialize(
       input_stream_,
diff --git a/media/filters/decoder_selector.h b/media/filters/decoder_selector.h
index d13eb9b..59c90f57 100644
--- a/media/filters/decoder_selector.h
+++ b/media/filters/decoder_selector.h
@@ -70,7 +70,8 @@
   void SelectDecoder(DemuxerStream* stream,
                      const SetDecryptorReadyCB& set_decryptor_ready_cb,
                      const SelectDecoderCB& select_decoder_cb,
-                     const typename Decoder::OutputCB& output_cb);
+                     const typename Decoder::OutputCB& output_cb,
+                     const base::Closure& waiting_for_decryption_key_cb);
 
  private:
   void DecryptingDecoderInitDone(PipelineStatus status);
@@ -86,6 +87,7 @@
   SetDecryptorReadyCB set_decryptor_ready_cb_;
   SelectDecoderCB select_decoder_cb_;
   typename Decoder::OutputCB output_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   scoped_ptr<Decoder> decoder_;
   scoped_ptr<DecryptingDemuxerStream> decrypted_stream_;
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index f9fa8b2..3a366d8 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -83,7 +83,8 @@
     DemuxerStream* stream,
     const InitCB& init_cb,
     const SetDecryptorReadyCB& set_decryptor_ready_cb,
-    const StatisticsCB& statistics_cb) {
+    const StatisticsCB& statistics_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   FUNCTION_DVLOG(2);
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -92,6 +93,7 @@
 
   statistics_cb_ = statistics_cb;
   init_cb_ = init_cb;
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
   stream_ = stream;
 
   state_ = STATE_INITIALIZING;
@@ -212,7 +214,8 @@
       base::Bind(&DecoderStream<StreamType>::OnDecoderSelected,
                  weak_factory_.GetWeakPtr()),
       base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
-                 weak_factory_.GetWeakPtr()));
+                 weak_factory_.GetWeakPtr()),
+      waiting_for_decryption_key_cb_);
 }
 
 template <DemuxerStream::Type StreamType>
diff --git a/media/filters/decoder_stream.h b/media/filters/decoder_stream.h
index b8a0d04..3c0e23ef 100644
--- a/media/filters/decoder_stream.h
+++ b/media/filters/decoder_stream.h
@@ -61,7 +61,8 @@
   void Initialize(DemuxerStream* stream,
                   const InitCB& init_cb,
                   const SetDecryptorReadyCB& set_decryptor_ready_cb,
-                  const StatisticsCB& statistics_cb);
+                  const StatisticsCB& statistics_cb,
+                  const base::Closure& waiting_for_decryption_key_cb);
 
   // Reads a decoded Output and returns it via the |read_cb|. Note that
   // |read_cb| is always called asynchronously. This method should only be
@@ -170,6 +171,7 @@
 
   StatisticsCB statistics_cb_;
   InitCB init_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   ReadCB read_cb_;
   base::Closure reset_cb_;
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 0ca20f7..3425d0c2 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -34,13 +34,16 @@
 
 DecryptingAudioDecoder::DecryptingAudioDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb)
+    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       state_(kUninitialized),
+      waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       set_decryptor_ready_cb_(set_decryptor_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+}
 
 std::string DecryptingAudioDecoder::GetDisplayName() const {
   return "DecryptingAudioDecoder";
@@ -288,6 +291,7 @@
     }
 
     state_ = kWaitingForKey;
+    waiting_for_decryption_key_cb_.Run();
     return;
   }
 
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h
index 67da6c0..30b0a63 100644
--- a/media/filters/decrypting_audio_decoder.h
+++ b/media/filters/decrypting_audio_decoder.h
@@ -32,7 +32,8 @@
  public:
   DecryptingAudioDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb);
+      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingAudioDecoder() override;
 
   // AudioDecoder implementation.
@@ -96,6 +97,7 @@
   OutputCB output_cb_;
   DecodeCB decode_cb_;
   base::Closure reset_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // The current decoder configuration.
   AudioDecoderConfig config_;
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index 49df3ce..1f8395bf 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -63,7 +63,9 @@
             message_loop_.message_loop_proxy(),
             base::Bind(
                 &DecryptingAudioDecoderTest::RequestDecryptorNotification,
-                base::Unretained(this)))),
+                base::Unretained(this)),
+            base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey,
+                       base::Unretained(this)))),
         decryptor_(new StrictMock<MockDecryptor>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
@@ -204,6 +206,7 @@
     EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
         .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey,
                                        Decryptor::AudioFrames()));
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey());
     decoder_->Decode(encrypted_buffer_,
                      base::Bind(&DecryptingAudioDecoderTest::DecodeDone,
                                 base::Unretained(this)));
@@ -252,6 +255,8 @@
 
   MOCK_METHOD1(DecryptorSet, void(bool));
 
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingAudioDecoder> decoder_;
   scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 601fd46..7a6f43c 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -30,14 +30,17 @@
 
 DecryptingDemuxerStream::DecryptingDemuxerStream(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb)
+    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       state_(kUninitialized),
+      waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       demuxer_stream_(NULL),
       set_decryptor_ready_cb_(set_decryptor_ready_cb),
       decryptor_(NULL),
       key_added_while_decrypt_pending_(false),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+}
 
 void DecryptingDemuxerStream::Initialize(DemuxerStream* stream,
                                          const PipelineStatusCB& status_cb) {
@@ -311,6 +314,7 @@
     }
 
     state_ = kWaitingForKey;
+    waiting_for_decryption_key_cb_.Run();
     return;
   }
 
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index f66f9ab7..e8d82224 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -30,7 +30,8 @@
  public:
   DecryptingDemuxerStream(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb);
+      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const base::Closure& waiting_for_decryption_key_cb);
 
   // Cancels all pending operations immediately and fires all pending callbacks.
   ~DecryptingDemuxerStream() override;
@@ -104,6 +105,7 @@
   PipelineStatusCB init_cb_;
   ReadCB read_cb_;
   base::Closure reset_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // Pointer to the input demuxer stream that will feed us encrypted buffers.
   DemuxerStream* demuxer_stream_;
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index fa2a36c..3cba1f7 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -77,7 +77,9 @@
             message_loop_.message_loop_proxy(),
             base::Bind(
                 &DecryptingDemuxerStreamTest::RequestDecryptorNotification,
-                base::Unretained(this)))),
+                base::Unretained(this)),
+            base::Bind(&DecryptingDemuxerStreamTest::OnWaitingForDecryptionKey,
+                       base::Unretained(this)))),
         decryptor_(new StrictMock<MockDecryptor>()),
         is_decryptor_set_(false),
         input_audio_stream_(
@@ -225,6 +227,7 @@
     EXPECT_CALL(*decryptor_, Decrypt(_, encrypted_buffer_, _))
         .WillRepeatedly(RunCallback<2>(Decryptor::kNoKey,
                                        scoped_refptr<DecoderBuffer>()));
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey());
     demuxer_stream_->Read(base::Bind(&DecryptingDemuxerStreamTest::BufferReady,
                                      base::Unretained(this)));
     message_loop_.RunUntilIdle();
@@ -260,6 +263,8 @@
 
   MOCK_METHOD1(DecryptorSet, void(bool));
 
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingDemuxerStream> demuxer_stream_;
   scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index f4aa375..d9bba50 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -23,14 +23,17 @@
 
 DecryptingVideoDecoder::DecryptingVideoDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-    const SetDecryptorReadyCB& set_decryptor_ready_cb)
+    const SetDecryptorReadyCB& set_decryptor_ready_cb,
+    const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       state_(kUninitialized),
+      waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       set_decryptor_ready_cb_(set_decryptor_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
       trace_id_(0),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+}
 
 std::string DecryptingVideoDecoder::GetDisplayName() const {
   return kDecoderName;
@@ -270,6 +273,7 @@
     }
 
     state_ = kWaitingForKey;
+    waiting_for_decryption_key_cb_.Run();
     return;
   }
 
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index 8e40502..a2a9528 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -28,7 +28,8 @@
  public:
   DecryptingVideoDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
-      const SetDecryptorReadyCB& set_decryptor_ready_cb);
+      const SetDecryptorReadyCB& set_decryptor_ready_cb,
+      const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingVideoDecoder() override;
 
   // VideoDecoder implementation.
@@ -88,6 +89,7 @@
   OutputCB output_cb_;
   DecodeCB decode_cb_;
   base::Closure reset_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   VideoDecoderConfig config_;
 
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index 11dc52a..285bab67 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -57,7 +57,9 @@
             message_loop_.message_loop_proxy(),
             base::Bind(
                 &DecryptingVideoDecoderTest::RequestDecryptorNotification,
-                base::Unretained(this)))),
+                base::Unretained(this)),
+            base::Bind(&DecryptingVideoDecoderTest::OnWaitingForDecryptionKey,
+                       base::Unretained(this)))),
         decryptor_(new StrictMock<MockDecryptor>()),
         num_decrypt_and_decode_calls_(0),
         num_frames_in_decryptor_(0),
@@ -179,6 +181,7 @@
   void EnterWaitingForKeyState() {
     EXPECT_CALL(*decryptor_, DecryptAndDecodeVideo(_, _))
         .WillRepeatedly(RunCallback<1>(Decryptor::kNoKey, null_video_frame_));
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey());
     decoder_->Decode(encrypted_buffer_,
                      base::Bind(&DecryptingVideoDecoderTest::DecodeDone,
                                 base::Unretained(this)));
@@ -227,6 +230,8 @@
 
   MOCK_METHOD1(DecryptorSet, void(bool));
 
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+
   base::MessageLoop message_loop_;
   scoped_ptr<DecryptingVideoDecoder> decoder_;
   scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
@@ -263,6 +268,7 @@
       .WillRepeatedly(RunCallback<1>(false));
   EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kVideo, _))
       .WillRepeatedly(SaveArg<1>(&key_added_cb_));
+  EXPECT_CALL(*this, RequestDecryptorNotification(_)).Times(2);
 
   InitializeAndExpectStatus(TestVideoConfig::NormalEncrypted(),
                             DECODER_ERROR_NOT_SUPPORTED);
@@ -333,7 +339,7 @@
 
 // Test the case where the a key is added when the decryptor is in
 // kPendingDecode state.
-TEST_F(DecryptingVideoDecoderTest, KeyAdded_DruingPendingDecode) {
+TEST_F(DecryptingVideoDecoderTest, KeyAdded_DuringPendingDecode) {
   Initialize();
   EnterPendingDecodeState();
 
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index f2dabdf..86f4c0ec 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -131,6 +131,8 @@
         base::Bind(&VideoDecoderSelectorTest::MockOnDecoderSelected,
                    base::Unretained(this)),
         base::Bind(&VideoDecoderSelectorTest::FrameReady,
+                   base::Unretained(this)),
+        base::Bind(&VideoDecoderSelectorTest::OnWaitingForDecryptionKey,
                    base::Unretained(this)));
     message_loop_.RunUntilIdle();
   }
@@ -147,6 +149,10 @@
     NOTREACHED();
   }
 
+  void OnWaitingForDecryptionKey() {
+    NOTREACHED();
+  }
+
   // Declare |decoder_selector_| after |demuxer_stream_| and |decryptor_| since
   // |demuxer_stream_| and |decryptor_| should outlive |decoder_selector_|.
   scoped_ptr<StrictMock<MockDemuxerStream> > demuxer_stream_;
diff --git a/media/filters/video_frame_stream_unittest.cc b/media/filters/video_frame_stream_unittest.cc
index f71c07f..a9f3b60 100644
--- a/media/filters/video_frame_stream_unittest.cc
+++ b/media/filters/video_frame_stream_unittest.cc
@@ -125,6 +125,7 @@
   MOCK_METHOD1(OnNewSpliceBuffer, void(base::TimeDelta));
   MOCK_METHOD1(SetDecryptorReadyCallback, void(const media::DecryptorReadyCB&));
   MOCK_METHOD1(DecryptorSet, void(bool));
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   void OnStatistics(const PipelineStatistics& statistics) {
     num_decoded_bytes_unreported_ -= statistics.video_bytes_decoded;
@@ -155,7 +156,8 @@
                                           base::Unretained(this)),
         base::Bind(&VideoFrameStreamTest::SetDecryptorReadyCallback,
                    base::Unretained(this)),
-        base::Bind(&VideoFrameStreamTest::OnStatistics,
+        base::Bind(&VideoFrameStreamTest::OnStatistics, base::Unretained(this)),
+        base::Bind(&VideoFrameStreamTest::OnWaitingForDecryptionKey,
                    base::Unretained(this)));
     message_loop_.RunUntilIdle();
   }
@@ -276,6 +278,8 @@
         break;
 
       case DECRYPTOR_NO_KEY:
+        if (GetParam().is_encrypted)
+          EXPECT_CALL(*this, OnWaitingForDecryptionKey());
         ExpectDecryptorNotification();
         has_no_key_ = true;
         ReadOneFrame();
diff --git a/media/mojo/services/mojo_renderer_impl.cc b/media/mojo/services/mojo_renderer_impl.cc
index 3bde3b25..e4a13326 100644
--- a/media/mojo/services/mojo_renderer_impl.cc
+++ b/media/mojo/services/mojo_renderer_impl.cc
@@ -33,7 +33,8 @@
   // Connection to |remote_media_renderer_| will error-out here.
 }
 
-// TODO(xhwang): Support |paint_cb| if needed.
+// TODO(xhwang): Support |paint_cb| and |waiting_for_decryption_key_cb|,
+// if needed.
 void MojoRendererImpl::Initialize(
     DemuxerStreamProvider* demuxer_stream_provider,
     const PipelineStatusCB& init_cb,
@@ -41,7 +42,8 @@
     const BufferingStateCB& buffering_state_cb,
     const PaintCB& /* paint_cb */,
     const base::Closure& ended_cb,
-    const PipelineStatusCB& error_cb) {
+    const PipelineStatusCB& error_cb,
+    const base::Closure& /* waiting_for_decryption_key_cb */) {
   DVLOG(1) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(demuxer_stream_provider);
diff --git a/media/mojo/services/mojo_renderer_impl.h b/media/mojo/services/mojo_renderer_impl.h
index d1ddc31..338bcb8 100644
--- a/media/mojo/services/mojo_renderer_impl.h
+++ b/media/mojo/services/mojo_renderer_impl.h
@@ -39,7 +39,8 @@
                   const BufferingStateCB& buffering_state_cb,
                   const PaintCB& paint_cb,
                   const base::Closure& ended_cb,
-                  const PipelineStatusCB& error_cb) override;
+                  const PipelineStatusCB& error_cb,
+                  const base::Closure& waiting_for_decryption_key_cb) override;
   void SetCdm(CdmContext* cdm_context,
               const CdmAttachedCB& cdm_attached_cb) override;
   void Flush(const base::Closure& flush_cb) override;
diff --git a/media/mojo/services/mojo_renderer_service.cc b/media/mojo/services/mojo_renderer_service.cc
index a737aa32..d4d2c9a 100644
--- a/media/mojo/services/mojo_renderer_service.cc
+++ b/media/mojo/services/mojo_renderer_service.cc
@@ -120,7 +120,8 @@
       base::Bind(&MojoRendererService::OnBufferingStateChanged, weak_this_),
       base::Bind(&PaintNothing),
       base::Bind(&MojoRendererService::OnRendererEnded, weak_this_),
-      base::Bind(&MojoRendererService::OnError, weak_this_));
+      base::Bind(&MojoRendererService::OnError, weak_this_),
+      base::Bind(base::DoNothing));
 }
 
 void MojoRendererService::OnRendererInitializeDone(
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index 56f3da7..74ef1d2 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -257,7 +257,8 @@
     const StatisticsCB& statistics_cb,
     const BufferingStateCB& buffering_state_cb,
     const base::Closure& ended_cb,
-    const PipelineStatusCB& error_cb) {
+    const PipelineStatusCB& error_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   DVLOG(1) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(stream);
@@ -317,7 +318,7 @@
   audio_buffer_stream_->Initialize(
       stream, base::Bind(&AudioRendererImpl::OnAudioBufferStreamInitialized,
                          weak_factory_.GetWeakPtr()),
-      set_decryptor_ready_cb, statistics_cb);
+      set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
 }
 
 void AudioRendererImpl::OnAudioBufferStreamInitialized(bool success) {
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index af7251a..1972c872 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -80,7 +80,8 @@
                   const StatisticsCB& statistics_cb,
                   const BufferingStateCB& buffering_state_cb,
                   const base::Closure& ended_cb,
-                  const PipelineStatusCB& error_cb) override;
+                  const PipelineStatusCB& error_cb,
+                  const base::Closure& waiting_for_decryption_key_cb) override;
   TimeSource* GetTimeSource() override;
   void Flush(const base::Closure& callback) override;
   void StartPlaying() override;
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index b5035c6..98782c93 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -113,8 +113,10 @@
   MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&));
   MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
   MOCK_METHOD1(OnError, void(PipelineStatus));
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 
   void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) {
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
         &demuxer_stream_, pipeline_status_cb, SetDecryptorReadyCB(),
         base::Bind(&AudioRendererImplTest::OnStatistics,
@@ -122,7 +124,9 @@
         base::Bind(&AudioRendererImplTest::OnBufferingStateChange,
                    base::Unretained(this)),
         base::Bind(&AudioRendererImplTest::OnEnded, base::Unretained(this)),
-        base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this)));
+        base::Bind(&AudioRendererImplTest::OnError, base::Unretained(this)),
+        base::Bind(&AudioRendererImplTest::OnWaitingForDecryptionKey,
+                   base::Unretained(this)));
   }
 
   void Initialize() {
diff --git a/media/renderers/renderer_impl.cc b/media/renderers/renderer_impl.cc
index 74e09d7..93671851 100644
--- a/media/renderers/renderer_impl.cc
+++ b/media/renderers/renderer_impl.cc
@@ -56,13 +56,15 @@
     base::ResetAndReturn(&flush_cb_).Run();
 }
 
-void RendererImpl::Initialize(DemuxerStreamProvider* demuxer_stream_provider,
-                              const PipelineStatusCB& init_cb,
-                              const StatisticsCB& statistics_cb,
-                              const BufferingStateCB& buffering_state_cb,
-                              const PaintCB& paint_cb,
-                              const base::Closure& ended_cb,
-                              const PipelineStatusCB& error_cb) {
+void RendererImpl::Initialize(
+    DemuxerStreamProvider* demuxer_stream_provider,
+    const PipelineStatusCB& init_cb,
+    const StatisticsCB& statistics_cb,
+    const BufferingStateCB& buffering_state_cb,
+    const PaintCB& paint_cb,
+    const base::Closure& ended_cb,
+    const PipelineStatusCB& error_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   DVLOG(1) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, STATE_UNINITIALIZED);
@@ -82,6 +84,7 @@
   ended_cb_ = ended_cb;
   error_cb_ = error_cb;
   init_cb_ = init_cb;
+  waiting_for_decryption_key_cb_ = waiting_for_decryption_key_cb;
 
   state_ = STATE_INITIALIZING;
   InitializeAudioRenderer();
@@ -258,7 +261,8 @@
       base::Bind(&RendererImpl::OnBufferingStateChanged, weak_this_,
                  &audio_buffering_state_),
       base::Bind(&RendererImpl::OnAudioRendererEnded, weak_this_),
-      base::Bind(&RendererImpl::OnError, weak_this_));
+      base::Bind(&RendererImpl::OnError, weak_this_),
+      waiting_for_decryption_key_cb_);
 }
 
 void RendererImpl::OnAudioRendererInitializeDone(PipelineStatus status) {
@@ -307,7 +311,8 @@
       base::Bind(&RendererImpl::OnVideoRendererEnded, weak_this_),
       base::Bind(&RendererImpl::OnError, weak_this_),
       base::Bind(&RendererImpl::GetMediaTimeForSyncingVideo,
-                 base::Unretained(this)));
+                 base::Unretained(this)),
+      waiting_for_decryption_key_cb_);
 }
 
 void RendererImpl::OnVideoRendererInitializeDone(PipelineStatus status) {
diff --git a/media/renderers/renderer_impl.h b/media/renderers/renderer_impl.h
index 68a2f7e0..befa95c1 100644
--- a/media/renderers/renderer_impl.h
+++ b/media/renderers/renderer_impl.h
@@ -49,7 +49,8 @@
                   const BufferingStateCB& buffering_state_cb,
                   const PaintCB& paint_cb,
                   const base::Closure& ended_cb,
-                  const PipelineStatusCB& error_cb) final;
+                  const PipelineStatusCB& error_cb,
+                  const base::Closure& waiting_for_decryption_key_cb) final;
   void SetCdm(CdmContext* cdm_context,
               const CdmAttachedCB& cdm_attached_cb) final;
   void Flush(const base::Closure& flush_cb) final;
@@ -133,6 +134,7 @@
   PipelineStatusCB error_cb_;
   BufferingStateCB buffering_state_cb_;
   PaintCB paint_cb_;
+  base::Closure waiting_for_decryption_key_cb_;
 
   // Temporary callback used for Initialize() and Flush().
   PipelineStatusCB init_cb_;
diff --git a/media/renderers/renderer_impl_unittest.cc b/media/renderers/renderer_impl_unittest.cc
index 8f738b0..30bad2fe 100644
--- a/media/renderers/renderer_impl_unittest.cc
+++ b/media/renderers/renderer_impl_unittest.cc
@@ -50,6 +50,7 @@
     MOCK_METHOD1(OnUpdateStatistics, void(const PipelineStatistics&));
     MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
     MOCK_METHOD1(OnVideoFramePaint, void(const scoped_refptr<VideoFrame>&));
+    MOCK_METHOD0(OnWaitingForDecryptionKey, void());
 
    private:
     DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
@@ -88,7 +89,7 @@
   // Sets up expectations to allow the audio renderer to initialize.
   void SetAudioRendererInitializeExpectations(PipelineStatus status) {
     EXPECT_CALL(*audio_renderer_,
-                Initialize(audio_stream_.get(), _, _, _, _, _, _))
+                Initialize(audio_stream_.get(), _, _, _, _, _, _, _))
         .WillOnce(DoAll(SaveArg<4>(&audio_buffering_state_cb_),
                         SaveArg<5>(&audio_ended_cb_),
                         SaveArg<6>(&audio_error_cb_), RunCallback<1>(status)));
@@ -97,13 +98,14 @@
   // Sets up expectations to allow the video renderer to initialize.
   void SetVideoRendererInitializeExpectations(PipelineStatus status) {
     EXPECT_CALL(*video_renderer_,
-                Initialize(video_stream_.get(), _, _, _, _, _, _, _, _))
+                Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _))
         .WillOnce(DoAll(SaveArg<4>(&video_buffering_state_cb_),
                         SaveArg<6>(&video_ended_cb_), RunCallback<1>(status)));
   }
 
   void InitializeAndExpect(PipelineStatus start_status) {
     EXPECT_CALL(callbacks_, OnInitialize(start_status));
+    EXPECT_CALL(callbacks_, OnWaitingForDecryptionKey()).Times(0);
 
     if (start_status == PIPELINE_OK && audio_stream_) {
       EXPECT_CALL(*audio_renderer_, GetTimeSource())
@@ -121,7 +123,9 @@
         base::Bind(&CallbackHelper::OnVideoFramePaint,
                    base::Unretained(&callbacks_)),
         base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
-        base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)));
+        base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
+        base::Bind(&CallbackHelper::OnWaitingForDecryptionKey,
+                   base::Unretained(&callbacks_)));
     base::RunLoop().RunUntilIdle();
   }
 
@@ -433,7 +437,7 @@
 
   // Force an audio error to occur during video renderer initialization.
   EXPECT_CALL(*video_renderer_,
-              Initialize(video_stream_.get(), _, _, _, _, _, _, _, _))
+              Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _))
       .WillOnce(DoAll(AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE),
                       SaveArg<4>(&video_buffering_state_cb_),
                       SaveArg<6>(&video_ended_cb_),
diff --git a/media/renderers/video_renderer_impl.cc b/media/renderers/video_renderer_impl.cc
index 5e2819d..0ad19e4 100644
--- a/media/renderers/video_renderer_impl.cc
+++ b/media/renderers/video_renderer_impl.cc
@@ -109,7 +109,8 @@
     const PaintCB& paint_cb,
     const base::Closure& ended_cb,
     const PipelineStatusCB& error_cb,
-    const TimeDeltaCB& get_time_cb) {
+    const TimeDeltaCB& get_time_cb,
+    const base::Closure& waiting_for_decryption_key_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   base::AutoLock auto_lock(lock_);
   DCHECK(stream);
@@ -139,7 +140,7 @@
   video_frame_stream_->Initialize(
       stream, base::Bind(&VideoRendererImpl::OnVideoFrameStreamInitialized,
                          weak_factory_.GetWeakPtr()),
-      set_decryptor_ready_cb, statistics_cb);
+      set_decryptor_ready_cb, statistics_cb, waiting_for_decryption_key_cb);
 }
 
 void VideoRendererImpl::CreateVideoThread() {
diff --git a/media/renderers/video_renderer_impl.h b/media/renderers/video_renderer_impl.h
index 69cf140..eec8b15 100644
--- a/media/renderers/video_renderer_impl.h
+++ b/media/renderers/video_renderer_impl.h
@@ -60,7 +60,8 @@
                   const PaintCB& paint_cb,
                   const base::Closure& ended_cb,
                   const PipelineStatusCB& error_cb,
-                  const TimeDeltaCB& get_time_cb) override;
+                  const TimeDeltaCB& get_time_cb,
+                  const base::Closure& waiting_for_decryption_key_cb) override;
   void Flush(const base::Closure& callback) override;
   void StartPlayingFrom(base::TimeDelta timestamp) override;
 
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index c771ad4..d9cad51 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -94,6 +94,7 @@
       demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
     EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
         DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
         &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
         base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
@@ -102,7 +103,9 @@
                    base::Unretained(&mock_cb_)),
         base::Bind(&StrictMock<MockCB>::Display, base::Unretained(&mock_cb_)),
         ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
-        base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)));
+        base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)),
+        base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey,
+                   base::Unretained(this)));
   }
 
   void StartPlayingFrom(int milliseconds) {
@@ -289,6 +292,8 @@
 
   void OnStatisticsUpdate(const PipelineStatistics& stats) {}
 
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+
   base::MessageLoop message_loop_;
 
   // Used to protect |time_|.
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index c2e23f8f..55bba587 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -659,6 +659,10 @@
         .WillRepeatedly(SaveArg<0>(&metadata_));
     EXPECT_CALL(*this, OnBufferingStateChanged(BUFFERING_HAVE_ENOUGH))
         .Times(AtMost(1));
+
+    // Encrypted content not used, so this is never called.
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
+
     demuxer_ = source->GetDemuxer().Pass();
     pipeline_->Start(
         demuxer_.get(), CreateRenderer(),
@@ -673,7 +677,9 @@
         base::Bind(&PipelineIntegrationTest::OnVideoFramePaint,
                    base::Unretained(this)),
         base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
-                                    base::Unretained(this)));
+                                    base::Unretained(this)),
+        base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey,
+                   base::Unretained(this)));
     message_loop_.Run();
     EXPECT_EQ(PIPELINE_OK, pipeline_status_);
   }
@@ -694,6 +700,10 @@
         .Times(AtMost(1));
     EXPECT_CALL(*this, DecryptorAttached(true));
 
+    // Encrypted content used but keys provided in advance, so this is
+    // never called.
+    EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
+
     demuxer_ = source->GetDemuxer().Pass();
 
     pipeline_->SetCdm(encrypted_media->GetCdmContext(),
@@ -713,7 +723,9 @@
         base::Bind(&PipelineIntegrationTest::OnVideoFramePaint,
                    base::Unretained(this)),
         base::Closure(), base::Bind(&PipelineIntegrationTest::OnAddTextTrack,
-                                    base::Unretained(this)));
+                                    base::Unretained(this)),
+        base::Bind(&PipelineIntegrationTest::OnWaitingForDecryptionKey,
+                   base::Unretained(this)));
 
     source->set_encrypted_media_init_data_cb(
         base::Bind(&FakeEncryptedMedia::OnEncryptedMediaInitData,
diff --git a/media/test/pipeline_integration_test_base.cc b/media/test/pipeline_integration_test_base.cc
index d40b0dcb..e122d9a8 100644
--- a/media/test/pipeline_integration_test_base.cc
+++ b/media/test/pipeline_integration_test_base.cc
@@ -121,6 +121,10 @@
                                 base::Unretained(this)));
   }
 
+  // Should never be called as the required decryption keys for the encrypted
+  // media files are provided in advance.
+  EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
+
   pipeline_->Start(
       demuxer_.get(), CreateRenderer(),
       base::Bind(&PipelineIntegrationTestBase::OnEnded, base::Unretained(this)),
@@ -134,7 +138,9 @@
       base::Bind(&PipelineIntegrationTestBase::OnVideoFramePaint,
                  base::Unretained(this)),
       base::Closure(), base::Bind(&PipelineIntegrationTestBase::OnAddTextTrack,
-                                  base::Unretained(this)));
+                                  base::Unretained(this)),
+      base::Bind(&PipelineIntegrationTestBase::OnWaitingForDecryptionKey,
+                 base::Unretained(this)));
   message_loop_.Run();
   return pipeline_status_;
 }
diff --git a/media/test/pipeline_integration_test_base.h b/media/test/pipeline_integration_test_base.h
index de6c0e0..716e27cf 100644
--- a/media/test/pipeline_integration_test_base.h
+++ b/media/test/pipeline_integration_test_base.h
@@ -140,6 +140,7 @@
   MOCK_METHOD2(OnAddTextTrack,
                void(const TextTrackConfig& config,
                     const AddTextTrackDoneCB& done_cb));
+  MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
 };
 
 }  // namespace media
diff --git a/media/tools/player_x11/player_x11.cc b/media/tools/player_x11/player_x11.cc
index afd5d0b..60eb45c 100644
--- a/media/tools/player_x11/player_x11.cc
+++ b/media/tools/player_x11/player_x11.cc
@@ -149,7 +149,8 @@
                   base::Bind(&OnBufferingStateChanged),
                   paint_cb,
                   base::Bind(&DoNothing),
-                  base::Bind(&OnAddTextTrack));
+                  base::Bind(&OnAddTextTrack),
+                  base::Bind(&DoNothing));
 
   // Wait until the pipeline is fully initialized.
   event.Wait();
diff --git a/native_client_sdk/doc_generated/reference/ideas.html b/native_client_sdk/doc_generated/reference/ideas.html
index 863af86a..69422c7 100644
--- a/native_client_sdk/doc_generated/reference/ideas.html
+++ b/native_client_sdk/doc_generated/reference/ideas.html
@@ -4,41 +4,42 @@
 <span id="ideas"></span><h1 id="contributor-ideas"><span id="ideas"></span>Contributor Ideas</h1>
 <div class="contents local" id="contents" style="display: none">
 <ul class="small-gap">
-<li><a class="reference internal" href="#contributing-me" id="id8">Contributing? Me‽</a></li>
-<li><p class="first"><a class="reference internal" href="#id1" id="id9">Ideas</a></p>
+<li><a class="reference internal" href="#contributing-me" id="id9">Contributing? Me‽</a></li>
+<li><a class="reference internal" href="#google-summer-of-code" id="id10">Google Summer of Code</a></li>
+<li><p class="first"><a class="reference internal" href="#id2" id="id11">Ideas</a></p>
 <ul class="small-gap">
-<li><p class="first"><a class="reference internal" href="#ports" id="id10">Ports</a></p>
+<li><p class="first"><a class="reference internal" href="#ports" id="id12">Ports</a></p>
 <ul class="small-gap">
-<li><a class="reference internal" href="#new-filesystems" id="id11">New Filesystems</a></li>
-<li><a class="reference internal" href="#open-source-porting" id="id12">Open Source Porting</a></li>
+<li><a class="reference internal" href="#new-filesystems" id="id13">New Filesystems</a></li>
+<li><a class="reference internal" href="#open-source-porting" id="id14">Open Source Porting</a></li>
 </ul>
 </li>
-<li><p class="first"><a class="reference internal" href="#languages" id="id13">Languages</a></p>
+<li><p class="first"><a class="reference internal" href="#languages" id="id15">Languages</a></p>
 <ul class="small-gap">
-<li><a class="reference internal" href="#rust" id="id14">Rust</a></li>
-<li><a class="reference internal" href="#haskell" id="id15">Haskell</a></li>
-<li><a class="reference internal" href="#julia" id="id16">Julia</a></li>
-<li><a class="reference internal" href="#scala" id="id17">Scala</a></li>
-<li><a class="reference internal" href="#elm" id="id18">Elm</a></li>
-<li><a class="reference internal" href="#mono" id="id19">Mono</a></li>
-<li><a class="reference internal" href="#perl" id="id20">Perl</a></li>
+<li><a class="reference internal" href="#rust" id="id16">Rust</a></li>
+<li><a class="reference internal" href="#haskell" id="id17">Haskell</a></li>
+<li><a class="reference internal" href="#julia" id="id18">Julia</a></li>
+<li><a class="reference internal" href="#scala" id="id19">Scala</a></li>
+<li><a class="reference internal" href="#elm" id="id20">Elm</a></li>
+<li><a class="reference internal" href="#mono" id="id21">Mono</a></li>
+<li><a class="reference internal" href="#perl" id="id22">Perl</a></li>
 </ul>
 </li>
-<li><a class="reference internal" href="#tcc" id="id21">TCC</a></li>
-<li><p class="first"><a class="reference internal" href="#llvm-and-pnacl" id="id22">LLVM and PNaCl</a></p>
+<li><a class="reference internal" href="#tcc" id="id23">TCC</a></li>
+<li><p class="first"><a class="reference internal" href="#llvm-and-pnacl" id="id24">LLVM and PNaCl</a></p>
 <ul class="small-gap">
-<li><a class="reference internal" href="#sandboxing-optimizations" id="id23">Sandboxing Optimizations</a></li>
-<li><a class="reference internal" href="#binary-size-reduction" id="id24">Binary Size Reduction</a></li>
-<li><a class="reference internal" href="#vector-support" id="id25">Vector Support</a></li>
-<li><a class="reference internal" href="#atomics" id="id26">Atomics</a></li>
-<li><a class="reference internal" href="#security-enhanced-pnacl" id="id27">Security-enhanced PNaCl</a></li>
+<li><a class="reference internal" href="#sandboxing-optimizations" id="id25">Sandboxing Optimizations</a></li>
+<li><a class="reference internal" href="#binary-size-reduction" id="id26">Binary Size Reduction</a></li>
+<li><a class="reference internal" href="#vector-support" id="id27">Vector Support</a></li>
+<li><a class="reference internal" href="#atomics" id="id28">Atomics</a></li>
+<li><a class="reference internal" href="#security-enhanced-pnacl" id="id29">Security-enhanced PNaCl</a></li>
 </ul>
 </li>
-<li><p class="first"><a class="reference internal" href="#nacl" id="id28">NaCl</a></p>
+<li><p class="first"><a class="reference internal" href="#nacl" id="id30">NaCl</a></p>
 <ul class="small-gap">
-<li><a class="reference internal" href="#auto-sandboxing" id="id29">Auto-Sandboxing</a></li>
-<li><a class="reference internal" href="#new-sandbox" id="id30">New Sandbox</a></li>
-<li><a class="reference internal" href="#bit-sandbox" id="id31">64-bit Sandbox</a></li>
+<li><a class="reference internal" href="#auto-sandboxing" id="id31">Auto-Sandboxing</a></li>
+<li><a class="reference internal" href="#new-sandbox" id="id32">New Sandbox</a></li>
+<li><a class="reference internal" href="#bit-sandbox" id="id33">64-bit Sandbox</a></li>
 </ul>
 </li>
 </ul>
@@ -57,7 +58,12 @@
 this page please contact the <a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a> mailing list.</p>
 <p>If you like an idea on this page and would like to get started, contact the
 <a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a> mailing list so that we can help you find a mentor.</p>
-<h2 id="id1">Ideas</h2>
+<h2 id="google-summer-of-code">Google Summer of Code</h2>
+<p>PNaCl participates in the <a class="reference external" href="https://www.google-melange.com/gsoc/homepage/google/gsoc2015">2015 Google Summer of Code</a> (see the <a class="reference external" href="https://www.google-melange.com/gsoc/org2/google/gsoc2015/pnacl">PNaCl GSoC
+page</a>). <a class="reference external" href="https://www.google-melange.com/gsoc/document/show/gsoc_program/google/gsoc2015/help_page#4._How_does_a_student_apply">Student applications</a> are open March 16–27. Discuss project ideas no
+<a class="reference external" href="https://groups.google.com/group/native-client-discuss">native-client-discuss</a>, and submit your proposal on the GSoC page by the
+deadline.</p>
+<h2 id="id2">Ideas</h2>
 <p>We&#8217;ve separated contributor ideas into broad areas of interest:</p>
 <ul class="small-gap">
 <li><strong>Ports</strong> encompass all the code that <em>uses</em> the PNaCl platform. Put simply,
diff --git a/native_client_sdk/doc_generated/sdk/release-notes.html b/native_client_sdk/doc_generated/sdk/release-notes.html
index 7a81d94..798946f 100644
--- a/native_client_sdk/doc_generated/sdk/release-notes.html
+++ b/native_client_sdk/doc_generated/sdk/release-notes.html
@@ -4,6 +4,13 @@
 <span id="sdk-release-notes"></span><h1 id="release-notes"><span id="sdk-release-notes"></span>Release Notes</h1>
 <p>The dates in the following release notes denote when Chrome and the NaCl SDK
 reached canary status. The stable release is typically 6 weeks later.</p>
+<h2 id="chrome-pepper-43-03-april-2015">Chrome/Pepper 43 (03 April 2015)</h2>
+<h3 id="pnacl">PNaCl</h3>
+<ul class="small-gap">
+<li>The C11/C++11 <code>acquire</code>, <code>release</code>, and <code>acq_rel</code> memory orders are now
+generated by default. The in-browser Chrome 42 translator supports them, the
+SDK can therefore generate them.</li>
+</ul>
 <h2 id="chrome-pepper-42-20-february-2015">Chrome/Pepper 42 (20 February 2015)</h2>
 <h3 id="sdk">SDK</h3>
 <ul class="small-gap">
@@ -16,17 +23,17 @@
 <h3 id="nacl">NaCl</h3>
 <ul class="small-gap">
 <li>The x86 NaCl validators accept instructions from the FMA3 extensions, as well
-as AVX2 instructions (except <cite>VGATHER</cite>).</li>
+as AVX2 instructions (except <code>VGATHER</code>).</li>
 </ul>
-<h3 id="pnacl">PNaCl</h3>
+<h3 id="id1">PNaCl</h3>
 <ul class="small-gap">
-<li>PNaCl supports C11/C++11 memory orders <cite>acquire</cite>, <cite>release</cite>, and <cite>acq_rel</cite>. It
-used to upgrade all accesses to <cite>seq_cst</cite>. It still upgrades <cite>consume</cite> to
-<cite>acquire</cite> (no compiler currently implements <cite>consume</cite>), and <cite>relaxed</cite> to
-<cite>seq_cst</cite> (to conservatively avoid platform differences due to out-of-thin-air
-problems). This is currently disabled by default in the SDK so that the
-in-browser translator installed on users&#8217; machines has time to gain this
-support. Developers can turn it on by passing the
+<li>PNaCl supports C11/C++11 memory orders <code>acquire</code>, <code>release</code>, and
+<code>acq_rel</code>. It used to upgrade all accesses to <code>seq_cst</code>. It still upgrades
+<code>consume</code> to <code>acquire</code> (no compiler currently implements <code>consume</code>), and
+<code>relaxed</code> to <code>seq_cst</code> (to conservatively avoid platform differences due
+to out-of-thin-air problems). This is currently disabled by default in the SDK
+so that the in-browser translator installed on users&#8217; machines has time to
+gain this support. Developers can turn it on by passing the
 <code>-pnacl-memory-order-seq-cst-only=false</code> flag to <code>opt</code>.</li>
 <li>PNaCl handles nested struct type expansion, which allows it to better support
 non-C languages such as Rust.</li>
@@ -34,11 +41,11 @@
 operations. This is often encountered when using large consecutive bitfields.</li>
 </ul>
 <h2 id="chrome-pepper-41-09-january-2015">Chrome/Pepper 41 (09 January 2015)</h2>
-<h3 id="id1">NaCl</h3>
+<h3 id="id2">NaCl</h3>
 <ul class="small-gap">
 <li>The x86 NaCl validators accept instructions from the AVX1 extensions.</li>
 </ul>
-<h3 id="id2">PNaCl</h3>
+<h3 id="id3">PNaCl</h3>
 <ul class="small-gap">
 <li>PNaCl is now based on LLVM 3.5.</li>
 </ul>
@@ -57,31 +64,31 @@
 embeds.</li>
 </ul>
 <h2 id="chrome-pepper-38-15-august-2014">Chrome/Pepper 38 (15 August 2014)</h2>
-<h3 id="id3">PNaCl</h3>
+<h3 id="id4">PNaCl</h3>
 <ul class="small-gap">
 <li>Compilation speed improvements due to validation caching of the translator and
 linker.</li>
 <li>Performance improvement of SIMD vector shuffle.</li>
 </ul>
 <h2 id="chrome-pepper-37-20-june-2014">Chrome/Pepper 37 (20 June 2014)</h2>
-<h3 id="id4">PNaCl</h3>
+<h3 id="id5">PNaCl</h3>
 <ul class="small-gap">
 <li>2–10% translation time improvement.</li>
 <li>Improved vector load/store and shuffle performance.</li>
 </ul>
-<h3 id="id5">Pepper</h3>
+<h3 id="id6">Pepper</h3>
 <ul class="small-gap">
 <li>Media Streams Input support.</li>
 <li>Compositor API.</li>
 <li>Hardware Decode API in development preview.</li>
 <li>Sync API in development preview.</li>
 </ul>
-<h3 id="id6">SDK</h3>
+<h3 id="id7">SDK</h3>
 <ul class="small-gap">
 <li>Demo of a <a class="reference internal" href="/native-client/io2014.html#io2014"><em>full development environment in the browser</em></a>.</li>
 </ul>
 <h2 id="chrome-pepper-36-09-may-2014">Chrome/Pepper 36 (09 May 2014)</h2>
-<h3 id="id7">PNaCl</h3>
+<h3 id="id8">PNaCl</h3>
 <ul class="small-gap">
 <li>Support <a class="reference external" href="http://clang.llvm.org/docs/LanguageExtensions.html#vectors-and-extended-vectors">LLVM vectors</a>
 and <a class="reference external" href="http://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html">GCC vectors</a> for SIMD
@@ -90,7 +97,7 @@
 Chrome. More SIMD instructions will be added in later releases.</li>
 </ul>
 <h2 id="chrome-pepper-35-31-mar-2014">Chrome/Pepper 35 (31 Mar 2014)</h2>
-<h3 id="id8">PNaCl</h3>
+<h3 id="id9">PNaCl</h3>
 <ul class="small-gap">
 <li>Upgraded LLVM to version 3.4.</li>
 <li>Translation now uses dynamic load balancing, making translation time faster.</li>
@@ -98,7 +105,7 @@
 Chrome, simplifying debugging with PNaCl. See <a class="reference internal" href="/native-client/devguide/devcycle/debugging.html#debugging-pnacl-pexes"><em>Debugging PNaCl pexes</em></a></li>
 </ul>
 <h2 id="chrome-pepper-34-20-feb-2014">Chrome/Pepper 34 (20 Feb 2014)</h2>
-<h3 id="id9">Pepper</h3>
+<h3 id="id10">Pepper</h3>
 <ul class="small-gap">
 <li>Filesystems can now be passed from JavaScript to NaCl. The resulting
 <code>pp::Var</code> will contain a <code>pp::Resource</code> that can be given to the
@@ -108,7 +115,7 @@
 <a class="reference external" href="/native-client/pepper_dev/cpp/classpp_1_1_media_stream_video_track">pp::MediaStreamVideoTrack</a> for
 more details.</li>
 </ul>
-<h3 id="id10">PNaCl</h3>
+<h3 id="id11">PNaCl</h3>
 <ul class="small-gap">
 <li>Parallel translation: at least 1.7x faster, even with older pexes.</li>
 <li>Intelligent abbreviations in the bitcode: 20% reduction in binary size using
@@ -122,7 +129,7 @@
 handling (see <a class="reference external" href="https://groups.google.com/forum/#!topic/native-client-discuss/0spfg6O04FM">announcement</a>
 for details).</li>
 </ul>
-<h3 id="id11">SDK</h3>
+<h3 id="id12">SDK</h3>
 <ul class="small-gap">
 <li>The <code>nacl_io</code> library now includes a FUSE mount.</li>
 <li>In the SDK examples, <code>common.js</code> now loads the Release version of the
@@ -236,7 +243,7 @@
 <p>The Pepper 26 bundle includes a new HTTP filesystem type in the nacl_mounts
 library (which has been renamed nacl_io), changes to the example Makefiles, a
 simple new 3D example, and a threaded file IO example.</p>
-<h3 id="id12">Build tools and toolchains</h3>
+<h3 id="id13">Build tools and toolchains</h3>
 <ul class="small-gap">
 <li><p class="first">Makefiles have been changed significantly:</p>
 <ul class="small-gap">
@@ -256,14 +263,14 @@
 the same set of header files as host builds. Previously host and NaCl builds
 used different headers, which could cause build problems.</li>
 </ul>
-<h3 id="id13">Libraries</h3>
+<h3 id="id14">Libraries</h3>
 <ul class="small-gap">
 <li>The nacl_mounts library has been renamed <strong>nacl_io</strong>, and has been expanded
 with a new type of mount, httpfs, which can be used to read URLs via HTTP.
 For details see <code>include/nacl_io/nacl_io.h</code>, as well as the
 <code>hello_nacl_io</code> example.</li>
 </ul>
-<h3 id="id14">Examples</h3>
+<h3 id="id15">Examples</h3>
 <ul class="small-gap">
 <li>A new example, <strong>hello_world_instance3d</strong>, has been added to demonstrate a
 simplified 3D app.</li>
@@ -285,7 +292,7 @@
 operations, and ppapi_main, which lets you implement a Native Client module
 using a simple ppapi_main function), and two new examples that demonstrate how
 to use the nacl_mounts and ppapi_main libraries.</p>
-<h3 id="id15">Build tools and toolchains</h3>
+<h3 id="id16">Build tools and toolchains</h3>
 <ul class="small-gap">
 <li><p class="first">The SDK includes a new toolchain to build Native Client executables (.nexe
 files) for <strong>ARM devices</strong>.</p>
@@ -322,7 +329,7 @@
 cannot make asynchronous PPAPI calls on a background thread without creating
 and using a message loop.</li>
 </ul>
-<h3 id="id16">Libraries</h3>
+<h3 id="id17">Libraries</h3>
 <p>The SDK includes two new libraries:</p>
 <ul class="small-gap">
 <li><p class="first">The <strong>nacl_mounts</strong> library provides a virtual file system that your module
@@ -356,7 +363,7 @@
 <p>Header files for the new libraries are in the <code>include/</code> directory, source
 files are in the <code>src/</code> directory, and compiled libraries are in the <code>lib/</code>
 directory.</p>
-<h3 id="id17">Examples</h3>
+<h3 id="id18">Examples</h3>
 <ul class="small-gap">
 <li><p class="first">The SDK includes two new examples:</p>
 <ul class="small-gap">
@@ -397,7 +404,7 @@
 for &#8220;Portable Native Client&#8221;), a new library (pthreads-win32) for the Windows
 SDK, and an expanded list of attributes for Pepper 3D contexts that lets
 applications specify a GPU preference for low power or performance.</p>
-<h3 id="id18">Build tools and toolchains</h3>
+<h3 id="id19">Build tools and toolchains</h3>
 <ul class="small-gap">
 <li>The SDK includes a new, experimental toolchain called <a class="reference external" href="http://nativeclient.googlecode.com/svn/data/site/pnacl.pdf">PNaCl</a> (pronounced
 &#8220;pinnacle&#8221;). The PNaCl toolchain produces architecture-independent executable
@@ -413,7 +420,7 @@
 names of your .nexe files and <code>create_nmf.py</code> will still be able to
 generate the appropriate Native Client manifest file for your application.</li>
 </ul>
-<h3 id="id20">Examples</h3>
+<h3 id="id21">Examples</h3>
 <ul class="small-gap">
 <li>The SDK examples now build with four toolchains: the glibc and newlib
 toolchains, the experimental PNaCl toolchain, and the hosted toolchain on
@@ -424,7 +431,7 @@
 drawing function is now set up as the Flush() callback, which allows 2D
 drawing to occur as quickly as possible.</li>
 </ul>
-<h3 id="id21">PPAPI</h3>
+<h3 id="id22">PPAPI</h3>
 <ul class="small-gap">
 <li>When creating a 3D rendering context, the <a class="reference external" href="/native-client/pepper_stable/c/group___enums#ga7df48e1c55f6401beea2a1b9c07967e8">attribute list</a>
 for the context can specify whether to prefer low power or performance for
@@ -496,7 +503,7 @@
 </ul>
 </li>
 </ul>
-<h3 id="id22">Examples</h3>
+<h3 id="id23">Examples</h3>
 <ul class="small-gap">
 <li>On Linux and Windows systems, most of the examples now build with three
 toolchains: the Native Client glibc and newlib toolchains, and the native
@@ -512,7 +519,7 @@
 a list of changes between version 1 and version 2 of the manifest file
 format, and a support schedule for applications that use version 1.</li>
 </ul>
-<h3 id="id23">PPAPI</h3>
+<h3 id="id24">PPAPI</h3>
 <ul class="small-gap">
 <li><a class="reference external" href="/native-client/pepper_stable/c/group___enums#ga21b811ac0484a214a8751aa3e1c959d9">PP_InputEvent_Modifier</a>
 has two new enum values (_ISLEFT and _ISRIGHT).</li>
@@ -523,14 +530,14 @@
 <p>The Pepper 22 bundle includes a <strong>command-line debugger</strong>, resources to enable
 <strong>hosted development on Windows</strong>, and changes to the example Makefiles (each
 example now builds both a debug and a release version).</p>
-<h3 id="id24">Tools</h3>
+<h3 id="id25">Tools</h3>
 <ul class="small-gap">
 <li>The SDK now includes a <strong>command-line debugger</strong> that you can use to debug
 Native Client modules. See <a class="reference internal" href="/native-client/devguide/devcycle/debugging.html#devcycle-debugging"><em>Debugging with nacl-gdb</em></a> for instructions on how to use this debugger. For now,
 nacl-gdb only works on 64-bit Windows, 64-bit Linux, and 32-bit Linux
 systems. Support for Mac and 32-bit Windows systems will be added soon.</li>
 </ul>
-<h3 id="id25">Windows SDK</h3>
+<h3 id="id26">Windows SDK</h3>
 <ul class="small-gap">
 <li><p class="first">Developers using the Windows SDK can now <strong>build a module as a Pepper
 plugin</strong> (sometimes called a &#8220;trusted&#8221; or &#8220;in-process&#8221; plugin) using the
@@ -578,7 +585,7 @@
 In the future, the SDK will include resources for hosted development on Mac
 and Linux as well as Windows.
 </aside>
-<h3 id="id26">Examples</h3>
+<h3 id="id27">Examples</h3>
 <ul class="small-gap">
 <li>Each example in the SDK now builds both a debug and a release version. As
 before, most examples also build newlib and glibc versions, which means that
@@ -592,7 +599,7 @@
 of the module, and implements handleMessage() to respond to messages sent
 from the NaCl module to the JavaScript side of the application</li>
 </ul>
-<h3 id="id27">PPAPI</h3>
+<h3 id="id28">PPAPI</h3>
 <ul class="small-gap">
 <li>The <code>CompletionCallbackFactory</code> class template now takes a thread traits
 class as its second parameter. For details see the <a class="reference external" href="/native-client/pepper_stable/cpp/classpp_1_1_completion_callback_factory#details">CompletionCallbackFactory
diff --git a/native_client_sdk/doc_generated/sitemap.html b/native_client_sdk/doc_generated/sitemap.html
index f6cfcb25..53eba14 100644
--- a/native_client_sdk/doc_generated/sitemap.html
+++ b/native_client_sdk/doc_generated/sitemap.html
@@ -42,6 +42,7 @@
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="/native-client/sdk/release-notes.html">Release Notes</a><ul class="small-gap">
+<li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-43-03-april-2015">Chrome/Pepper 43 (03 April 2015)</a></li>
 <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-42-20-february-2015">Chrome/Pepper 42 (20 February 2015)</a></li>
 <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-41-09-january-2015">Chrome/Pepper 41 (09 January 2015)</a></li>
 <li class="toctree-l2"><a class="reference internal" href="/native-client/sdk/release-notes.html#chrome-pepper-40-november-07-2014">Chrome/Pepper 40 (November 07 2014)</a></li>
@@ -384,7 +385,8 @@
 <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/index.html">Reference</a></li>
 <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/ideas.html">Contributor Ideas</a><ul class="small-gap">
 <li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#contributing-me">Contributing? Me‽</a></li>
-<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#id1">Ideas</a></li>
+<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#google-summer-of-code">Google Summer of Code</a></li>
+<li class="toctree-l2"><a class="reference internal" href="/native-client/reference/ideas.html#id2">Ideas</a></li>
 </ul>
 </li>
 <li class="toctree-l1"><a class="reference internal" href="/native-client/reference/pnacl-bitcode-abi.html">PNaCl Bitcode Reference Manual</a><ul class="small-gap">
diff --git a/native_client_sdk/src/build_tools/build_app.py b/native_client_sdk/src/build_tools/build_app.py
index 0c406c0..e0def78 100755
--- a/native_client_sdk/src/build_tools/build_app.py
+++ b/native_client_sdk/src/build_tools/build_app.py
@@ -132,14 +132,20 @@
     return list1 + [x for x in list2 if x not in list1]
   all_permissions = []
   all_socket_permissions = []
+  all_filesystem_permissions = []
   for _, project in parse_dsc.GenerateProjects(tree):
     permissions = project.get('PERMISSIONS', [])
     all_permissions = MergeLists(all_permissions, permissions)
     socket_permissions = project.get('SOCKET_PERMISSIONS', [])
     all_socket_permissions = MergeLists(all_socket_permissions,
                                         socket_permissions)
+    filesystem_permissions = project.get('FILESYSTEM_PERMISSIONS', [])
+    all_filesystem_permissions = MergeLists(all_filesystem_permissions,
+                                            filesystem_permissions)
   if all_socket_permissions:
     all_permissions.append({'socket': all_socket_permissions})
+  if all_filesystem_permissions:
+    all_permissions.append({'fileSystem': all_filesystem_permissions})
   pretty_permissions = json.dumps(all_permissions, sort_keys=True, indent=4)
 
   for filename in ['background.js', 'icon128.png']:
diff --git a/native_client_sdk/src/doc/reference/ideas.rst b/native_client_sdk/src/doc/reference/ideas.rst
index 71d4360..c9a3bfb3 100644
--- a/native_client_sdk/src/doc/reference/ideas.rst
+++ b/native_client_sdk/src/doc/reference/ideas.rst
@@ -28,6 +28,18 @@
 
 .. _native-client-discuss: https://groups.google.com/group/native-client-discuss
 
+Google Summer of Code
+=====================
+
+PNaCl participates in the `2015 Google Summer of Code`_ (see the `PNaCl GSoC
+page`_). `Student applications`_ are open March 16–27. Discuss project ideas no
+native-client-discuss_, and submit your proposal on the GSoC page by the
+deadline.
+
+.. _PNaCl GSoC page: https://www.google-melange.com/gsoc/org2/google/gsoc2015/pnacl
+.. _2015 Google Summer of Code: https://www.google-melange.com/gsoc/homepage/google/gsoc2015
+.. _Student applications: https://www.google-melange.com/gsoc/document/show/gsoc_program/google/gsoc2015/help_page#4._How_does_a_student_apply
+
 Ideas
 =====
 
diff --git a/native_client_sdk/src/doc/sdk/release-notes.rst b/native_client_sdk/src/doc/sdk/release-notes.rst
index f3ccf1537..06eb85777 100644
--- a/native_client_sdk/src/doc/sdk/release-notes.rst
+++ b/native_client_sdk/src/doc/sdk/release-notes.rst
@@ -8,15 +8,15 @@
 reached canary status. The stable release is typically 6 weeks later.
 
 
-.. Chrome/Pepper 43 (03 April 2015)
-.. ===================================
-..
-.. PNaCl
-.. -----
-..
-.. * The C11/C++11 `acquire`, `release`, and `acq_rel` memory orders are now
-   generated by default. The in-browser Chrome 42 translator supports them, the
-   SDK can therefore generate them.
+Chrome/Pepper 43 (03 April 2015)
+================================
+
+PNaCl
+-----
+
+* The C11/C++11 ``acquire``, ``release``, and ``acq_rel`` memory orders are now
+  generated by default. The in-browser Chrome 42 translator supports them, the
+  SDK can therefore generate them.
 
 Chrome/Pepper 42 (20 February 2015)
 ===================================
@@ -34,18 +34,18 @@
 ----
 
 * The x86 NaCl validators accept instructions from the FMA3 extensions, as well
-  as AVX2 instructions (except `VGATHER`).
+  as AVX2 instructions (except ``VGATHER``).
 
 PNaCl
 -----
 
-* PNaCl supports C11/C++11 memory orders `acquire`, `release`, and `acq_rel`. It
-  used to upgrade all accesses to `seq_cst`. It still upgrades `consume` to
-  `acquire` (no compiler currently implements `consume`), and `relaxed` to
-  `seq_cst` (to conservatively avoid platform differences due to out-of-thin-air
-  problems). This is currently disabled by default in the SDK so that the
-  in-browser translator installed on users' machines has time to gain this
-  support. Developers can turn it on by passing the
+* PNaCl supports C11/C++11 memory orders ``acquire``, ``release``, and
+  ``acq_rel``. It used to upgrade all accesses to ``seq_cst``. It still upgrades
+  ``consume`` to ``acquire`` (no compiler currently implements ``consume``), and
+  ``relaxed`` to ``seq_cst`` (to conservatively avoid platform differences due
+  to out-of-thin-air problems). This is currently disabled by default in the SDK
+  so that the in-browser translator installed on users' machines has time to
+  gain this support. Developers can turn it on by passing the
   ``-pnacl-memory-order-seq-cst-only=false`` flag to ``opt``.
 * PNaCl handles nested struct type expansion, which allows it to better support
   non-C languages such as Rust.
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc
index f77c46c6..74ded45 100644
--- a/net/cert/x509_certificate_unittest.cc
+++ b/net/cert/x509_certificate_unittest.cc
@@ -1011,7 +1011,7 @@
     // be present.
     { true, "www.test.example", "*.test.example" },
     { true, "test.example.co.uk", "*.example.co.uk" },
-    { false, "test.example", "*.exmaple" },
+    { false, "test.example", "*.example" },
     { false, "example.co.uk", "*.co.uk" },
     { false, "foo.com", "*.com" },
     { false, "foo.us", "*.us" },
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 66873abc..3a594d5 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -4,13 +4,16 @@
 
 #include "net/dns/mdns_client_impl.h"
 
+#include <algorithm>
 #include <queue>
 
 #include "base/bind.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/stl_util.h"
+#include "base/time/clock.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
+#include "base/timer/timer.h"
 #include "net/base/dns_util.h"
 #include "net/base/net_errors.h"
 #include "net/base/net_log.h"
@@ -80,9 +83,7 @@
       connection_->OnDatagramReceived(&response_, recv_addr_, rv);
 
     rv = socket_->RecvFrom(
-        response_.io_buffer(),
-        response_.io_buffer()->size(),
-        &recv_addr_,
+        response_.io_buffer(), response_.io_buffer()->size(), &recv_addr_,
         base::Bind(&MDnsConnection::SocketHandler::OnDatagramReceived,
                    base::Unretained(this)));
   } while (rv > 0);
@@ -195,7 +196,10 @@
   delegate_->HandlePacket(response, bytes_read);
 }
 
-MDnsClientImpl::Core::Core() : connection_(new MDnsConnection(this)) {
+MDnsClientImpl::Core::Core(base::Clock* clock, base::Timer* timer)
+    : clock_(clock),
+      cleanup_timer_(timer),
+      connection_(new MDnsConnection(this)) {
 }
 
 MDnsClientImpl::Core::~Core() {
@@ -241,8 +245,8 @@
 
   for (unsigned i = 0; i < answer_count; i++) {
     offset = parser.GetOffset();
-    scoped_ptr<const RecordParsed> record = RecordParsed::CreateFrom(
-        &parser, base::Time::Now());
+    scoped_ptr<const RecordParsed> record =
+        RecordParsed::CreateFrom(&parser, clock_->Now());
 
     if (!record) {
       DVLOG(1) << "Could not understand an mDNS record.";
@@ -295,8 +299,7 @@
   // Remove all cached records matching the nonexistent RR types.
   std::vector<const RecordParsed*> records_to_remove;
 
-  cache_.FindDnsRecords(0, record->name(), &records_to_remove,
-                        base::Time::Now());
+  cache_.FindDnsRecords(0, record->name(), &records_to_remove, clock_->Now());
 
   for (std::vector<const RecordParsed*>::iterator i = records_to_remove.begin();
        i != records_to_remove.end(); i++) {
@@ -380,25 +383,26 @@
 
 void MDnsClientImpl::Core::ScheduleCleanup(base::Time cleanup) {
   // Cleanup is already scheduled, no need to do anything.
-  if (cleanup == scheduled_cleanup_) return;
+  if (cleanup == scheduled_cleanup_) {
+    return;
+  }
   scheduled_cleanup_ = cleanup;
 
   // This cancels the previously scheduled cleanup.
-  cleanup_callback_.Reset(base::Bind(
-      &MDnsClientImpl::Core::DoCleanup, base::Unretained(this)));
+  cleanup_timer_->Stop();
 
   // If |cleanup| is empty, then no cleanup necessary.
   if (cleanup != base::Time()) {
-    base::MessageLoop::current()->PostDelayedTask(
-        FROM_HERE,
-        cleanup_callback_.callback(),
-        cleanup - base::Time::Now());
+    cleanup_timer_->Start(
+        FROM_HERE, std::max(base::TimeDelta(), cleanup - clock_->Now()),
+        base::Bind(&MDnsClientImpl::Core::DoCleanup, base::Unretained(this)));
   }
 }
 
 void MDnsClientImpl::Core::DoCleanup() {
-  cache_.CleanupRecords(base::Time::Now(), base::Bind(
-      &MDnsClientImpl::Core::OnRecordRemoved, base::Unretained(this)));
+  cache_.CleanupRecords(clock_->Now(),
+                        base::Bind(&MDnsClientImpl::Core::OnRecordRemoved,
+                                   base::Unretained(this)));
 
   ScheduleCleanup(cache_.next_expiration());
 }
@@ -412,10 +416,17 @@
 void MDnsClientImpl::Core::QueryCache(
     uint16 rrtype, const std::string& name,
     std::vector<const RecordParsed*>* records) const {
-  cache_.FindDnsRecords(rrtype, name, records, base::Time::Now());
+  cache_.FindDnsRecords(rrtype, name, records, clock_->Now());
 }
 
-MDnsClientImpl::MDnsClientImpl() {
+MDnsClientImpl::MDnsClientImpl()
+    : clock_(new base::DefaultClock),
+      cleanup_timer_(new base::Timer(false, false)) {
+}
+
+MDnsClientImpl::MDnsClientImpl(scoped_ptr<base::Clock> clock,
+                               scoped_ptr<base::Timer> timer)
+    : clock_(clock.Pass()), cleanup_timer_(timer.Pass()) {
 }
 
 MDnsClientImpl::~MDnsClientImpl() {
@@ -423,7 +434,7 @@
 
 bool MDnsClientImpl::StartListening(MDnsSocketFactory* socket_factory) {
   DCHECK(!core_.get());
-  core_.reset(new Core());
+  core_.reset(new Core(clock_.get(), cleanup_timer_.get()));
   if (!core_->Init(socket_factory)) {
     core_.reset();
     return false;
@@ -444,7 +455,7 @@
     const std::string& name,
     MDnsListener::Delegate* delegate) {
   return scoped_ptr<net::MDnsListener>(
-      new MDnsListenerImpl(rrtype, name, delegate, this));
+      new MDnsListenerImpl(rrtype, name, clock_.get(), delegate, this));
 }
 
 scoped_ptr<MDnsTransaction> MDnsClientImpl::CreateTransaction(
@@ -456,13 +467,18 @@
       new MDnsTransactionImpl(rrtype, name, flags, callback, this));
 }
 
-MDnsListenerImpl::MDnsListenerImpl(
-    uint16 rrtype,
-    const std::string& name,
-    MDnsListener::Delegate* delegate,
-    MDnsClientImpl* client)
-    : rrtype_(rrtype), name_(name), client_(client), delegate_(delegate),
-      started_(false), active_refresh_(false) {
+MDnsListenerImpl::MDnsListenerImpl(uint16 rrtype,
+                                   const std::string& name,
+                                   base::Clock* clock,
+                                   MDnsListener::Delegate* delegate,
+                                   MDnsClientImpl* client)
+    : rrtype_(rrtype),
+      name_(name),
+      clock_(clock),
+      client_(client),
+      delegate_(delegate),
+      started_(false),
+      active_refresh_(false) {
 }
 
 MDnsListenerImpl::~MDnsListenerImpl() {
@@ -571,14 +587,10 @@
                        kListenerRefreshRatio2 * ttl_));
 
   base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      next_refresh_.callback(),
-      next_refresh1 - base::Time::Now());
+      FROM_HERE, next_refresh_.callback(), next_refresh1 - clock_->Now());
 
   base::MessageLoop::current()->PostDelayedTask(
-      FROM_HERE,
-      next_refresh_.callback(),
-      next_refresh2 - base::Time::Now());
+      FROM_HERE, next_refresh_.callback(), next_refresh2 - clock_->Now());
 }
 
 void MDnsListenerImpl::DoRefresh() {
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index 4ed85f2..a0c5b98 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -6,6 +6,7 @@
 #define NET_DNS_MDNS_CLIENT_IMPL_H_
 
 #include <map>
+#include <queue>
 #include <string>
 #include <utility>
 #include <vector>
@@ -21,11 +22,16 @@
 #include "net/udp/udp_server_socket.h"
 #include "net/udp/udp_socket.h"
 
+namespace base {
+class Clock;
+class Timer;
+}  // namespace base
+
 namespace net {
 
 class MDnsSocketFactoryImpl : public MDnsSocketFactory {
  public:
-  MDnsSocketFactoryImpl() {};
+  MDnsSocketFactoryImpl() {}
   ~MDnsSocketFactoryImpl() override{};
 
   void CreateSockets(ScopedVector<DatagramServerSocket>* sockets) override;
@@ -109,7 +115,7 @@
   // invalidate the core.
   class Core : public base::SupportsWeakPtr<Core>, MDnsConnection::Delegate {
    public:
-    Core();
+    Core(base::Clock* clock, base::Timer* timer);
     ~Core() override;
 
     // Initialize the core. Returns true on success.
@@ -132,6 +138,8 @@
     void OnConnectionError(int error) override;
 
    private:
+    FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL);
+
     typedef std::pair<std::string, uint16> ListenerKey;
     typedef std::map<ListenerKey, ObserverList<MDnsListenerImpl>* >
     ListenerMap;
@@ -159,7 +167,8 @@
 
     MDnsCache cache_;
 
-    base::CancelableClosure cleanup_callback_;
+    base::Clock* clock_;
+    base::Timer* cleanup_timer_;
     base::Time scheduled_cleanup_;
 
     scoped_ptr<MDnsConnection> connection_;
@@ -189,7 +198,15 @@
   Core* core() { return core_.get(); }
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(MDnsTest, CacheCleanupWithShortTTL);
+
+  // Test constructor, takes a mock clock and mock timer.
+  MDnsClientImpl(scoped_ptr<base::Clock> clock,
+                 scoped_ptr<base::Timer> cleanup_timer);
+
   scoped_ptr<Core> core_;
+  scoped_ptr<base::Clock> clock_;
+  scoped_ptr<base::Timer> cleanup_timer_;
 
   DISALLOW_COPY_AND_ASSIGN(MDnsClientImpl);
 };
@@ -199,6 +216,7 @@
  public:
   MDnsListenerImpl(uint16 rrtype,
                    const std::string& name,
+                   base::Clock* clock,
                    MDnsListener::Delegate* delegate,
                    MDnsClientImpl* client);
 
@@ -229,6 +247,7 @@
 
   uint16 rrtype_;
   std::string name_;
+  base::Clock* clock_;
   MDnsClientImpl* client_;
   MDnsListener::Delegate* delegate_;
 
diff --git a/net/dns/mdns_client_unittest.cc b/net/dns/mdns_client_unittest.cc
index ba03082..70514f3 100644
--- a/net/dns/mdns_client_unittest.cc
+++ b/net/dns/mdns_client_unittest.cc
@@ -6,6 +6,9 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
+#include "base/time/clock.h"
+#include "base/time/default_clock.h"
+#include "base/timer/mock_timer.h"
 #include "net/base/rand_callback.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mdns_client_impl.h"
@@ -222,6 +225,38 @@
   0xc0, 0x32
 };
 
+const uint8 kSamplePacket3[] = {
+    // Header
+    0x00, 0x00,  // ID is zeroed out
+    0x81, 0x80,  // Standard query response, RA, no error
+    0x00, 0x00,  // No questions (for simplicity)
+    0x00, 0x02,  // 2 RRs (answers)
+    0x00, 0x00,  // 0 authority RRs
+    0x00, 0x00,  // 0 additional RRs
+
+    // Answer 1
+    0x07, '_',  'p',  'r', 'i', 'v', 'e', 't',  //
+    0x04, '_',  't',  'c', 'p',                 //
+    0x05, 'l',  'o',  'c', 'a', 'l',            //
+    0x00, 0x00, 0x0c,                           // TYPE is PTR.
+    0x00, 0x01,                                 // CLASS is IN.
+    0x00, 0x00,                                 // TTL (4 bytes) is 1 second;
+    0x00, 0x01,                                 //
+    0x00, 0x08,                                 // RDLENGTH is 8 bytes.
+    0x05, 'h',  'e',  'l', 'l', 'o',            //
+    0xc0, 0x0c,                                 //
+
+    // Answer 2
+    0x08, '_',  'p',  'r', 'i', 'n', 't', 'e', 'r',  //
+    0xc0, 0x14,                                      // Pointer to "._tcp.local"
+    0x00, 0x0c,                                      // TYPE is PTR.
+    0x00, 0x01,                                      // CLASS is IN.
+    0x00, 0x00,                       // TTL (4 bytes) is 3 seconds.
+    0x00, 0x03,                       //
+    0x00, 0x08,                       // RDLENGTH is 8 bytes.
+    0x05, 'h',  'e',  'l', 'l', 'o',  //
+    0xc0, 0x32};
+
 const uint8 kQueryPacketPrivet[] = {
   // Header
   0x00, 0x00,               // ID is zeroed out
@@ -389,9 +424,45 @@
   int ttl_;
 };
 
+class MockClock : public base::DefaultClock {
+ public:
+  MockClock() : base::DefaultClock() {}
+  virtual ~MockClock() {}
+
+  MOCK_METHOD0(Now, base::Time());
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockClock);
+};
+
+class MockTimer : public base::MockTimer {
+ public:
+  MockTimer() : base::MockTimer(false, false) {}
+  ~MockTimer() {}
+
+  void Start(const tracked_objects::Location& posted_from,
+             base::TimeDelta delay,
+             const base::Closure& user_task) {
+    StartObserver(posted_from, delay, user_task);
+    base::MockTimer::Start(posted_from, delay, user_task);
+  }
+
+  // StartObserver is invoked when MockTimer::Start() is called.
+  // Does not replace the behavior of MockTimer::Start().
+  MOCK_METHOD3(StartObserver,
+               void(const tracked_objects::Location& posted_from,
+                    base::TimeDelta delay,
+                    const base::Closure& user_task));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockTimer);
+};
+
+}  // namespace
+
 class MDnsTest : public ::testing::Test {
  public:
-  virtual void SetUp() override;
+  void SetUp() override;
   void DeleteTransaction();
   void DeleteBothListeners();
   void RunFor(base::TimeDelta time_period);
@@ -403,12 +474,11 @@
   MOCK_METHOD2(MockableRecordCallback2, void(MDnsTransaction::Result result,
                                              const RecordParsed* record));
 
-
  protected:
   void ExpectPacket(const uint8* packet, unsigned size);
   void SimulatePacketReceive(const uint8* packet, unsigned size);
 
-  MDnsClientImpl test_client_;
+  scoped_ptr<MDnsClientImpl> test_client_;
   IPEndPoint mdns_ipv4_endpoint_;
   StrictMock<MockMDnsSocketFactory> socket_factory_;
 
@@ -429,7 +499,8 @@
 };
 
 void MDnsTest::SetUp() {
-  test_client_.StartListening(&socket_factory_);
+  test_client_.reset(new MDnsClientImpl());
+  test_client_->StartListening(&socket_factory_);
 }
 
 void MDnsTest::SimulatePacketReceive(const uint8* packet, unsigned size) {
@@ -471,12 +542,10 @@
   PtrRecordCopyContainer record_privet;
   PtrRecordCopyContainer record_printer;
 
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_privet);
-  scoped_ptr<MDnsListener> listener_printer =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
-                                  &delegate_printer);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
+  scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
 
   ASSERT_TRUE(listener_privet->Start());
   ASSERT_TRUE(listener_printer->Start());
@@ -515,9 +584,8 @@
   PtrRecordCopyContainer record_privet;
   PtrRecordCopyContainer record_privet2;
 
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
 
   ASSERT_TRUE(listener_privet->Start());
 
@@ -545,14 +613,75 @@
                                           "hello._privet._tcp.local"));
 }
 
+// Ensure that the cleanup task scheduler won't schedule cleanup tasks in the
+// past if the system clock creeps past the expiration time while in the
+// cleanup dispatcher.
+TEST_F(MDnsTest, CacheCleanupWithShortTTL) {
+  // Use a nonzero starting time as a base.
+  base::Time start_time = base::Time() + base::TimeDelta::FromSeconds(1);
+
+  MockClock* clock = new MockClock;
+  MockTimer* timer = new MockTimer;
+
+  test_client_.reset(
+      new MDnsClientImpl(make_scoped_ptr(clock), make_scoped_ptr(timer)));
+  test_client_->StartListening(&socket_factory_);
+
+  EXPECT_CALL(*timer, StartObserver(_, _, _)).Times(1);
+  EXPECT_CALL(*clock, Now())
+      .Times(3)
+      .WillRepeatedly(Return(start_time))
+      .RetiresOnSaturation();
+
+  // Receive two records with different TTL values.
+  // TTL(privet)=1.0s
+  // TTL(printer)=3.0s
+  StrictMock<MockListenerDelegate> delegate_privet;
+  StrictMock<MockListenerDelegate> delegate_printer;
+
+  PtrRecordCopyContainer record_privet;
+  PtrRecordCopyContainer record_printer;
+
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
+  scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
+
+  ASSERT_TRUE(listener_privet->Start());
+  ASSERT_TRUE(listener_printer->Start());
+
+  EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
+      .Times(Exactly(1));
+  EXPECT_CALL(delegate_printer, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
+      .Times(Exactly(1));
+
+  SimulatePacketReceive(kSamplePacket3, sizeof(kSamplePacket3));
+
+  EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_REMOVED, _))
+      .Times(Exactly(1));
+
+  // Set the clock to 2.0s, which should clean up the 'privet' record, but not
+  // the printer. The mock clock will change Now() mid-execution from 2s to 4s.
+  // Note: expectations are FILO-ordered -- t+2 seconds is returned, then t+4.
+  EXPECT_CALL(*clock, Now())
+      .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(4)))
+      .RetiresOnSaturation();
+  EXPECT_CALL(*clock, Now())
+      .WillOnce(Return(start_time + base::TimeDelta::FromSeconds(2)))
+      .RetiresOnSaturation();
+
+  EXPECT_CALL(*timer, StartObserver(_, base::TimeDelta(), _));
+
+  timer->Fire();
+}
+
 TEST_F(MDnsTest, MalformedPacket) {
   StrictMock<MockListenerDelegate> delegate_printer;
 
   PtrRecordCopyContainer record_printer;
 
-  scoped_ptr<MDnsListener> listener_printer =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_printer._tcp.local",
-                                  &delegate_printer);
+  scoped_ptr<MDnsListener> listener_printer = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_printer._tcp.local", &delegate_printer);
 
   ASSERT_TRUE(listener_printer->Start());
 
@@ -582,11 +711,10 @@
   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
 
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -607,10 +735,9 @@
 
 TEST_F(MDnsTest, TransactionCacheOnlyNoResult) {
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -624,10 +751,8 @@
 TEST_F(MDnsTest, TransactionWithCache) {
   // Listener to force the client to listen
   StrictMock<MockListenerDelegate> delegate_irrelevant;
-  scoped_ptr<MDnsListener> listener_irrelevant =
-      test_client_.CreateListener(dns_protocol::kTypeA,
-                                  "codereview.chromium.local",
-                                  &delegate_irrelevant);
+  scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
+      dns_protocol::kTypeA, "codereview.chromium.local", &delegate_irrelevant);
 
   ASSERT_TRUE(listener_irrelevant->Start());
 
@@ -641,11 +766,10 @@
                        &PtrRecordCopyContainer::SaveWithDummyArg));
 
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -660,9 +784,8 @@
 
   PtrRecordCopyContainer record_privet;
 
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
 
   ASSERT_TRUE(listener_privet->Start());
 
@@ -683,11 +806,10 @@
   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
 
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -705,10 +827,9 @@
   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
 
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE ,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -742,13 +863,11 @@
 TEST_F(MDnsTest, TransactionReentrantDelete) {
   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
 
-  transaction_ = test_client_.CreateTransaction(
+  transaction_ = test_client_->CreateTransaction(
       dns_protocol::kTypePTR, "_privet._tcp.local",
-      MDnsTransaction::QUERY_NETWORK |
-      MDnsTransaction::QUERY_CACHE |
-      MDnsTransaction::SINGLE_RESULT,
-      base::Bind(&MDnsTest::MockableRecordCallback,
-                 base::Unretained(this)));
+      MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+          MDnsTransaction::SINGLE_RESULT,
+      base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this)));
 
   ASSERT_TRUE(transaction_->Start());
 
@@ -765,19 +884,16 @@
 
 TEST_F(MDnsTest, TransactionReentrantDeleteFromCache) {
   StrictMock<MockListenerDelegate> delegate_irrelevant;
-  scoped_ptr<MDnsListener> listener_irrelevant = test_client_.CreateListener(
-      dns_protocol::kTypeA, "codereview.chromium.local",
-      &delegate_irrelevant);
+  scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
+      dns_protocol::kTypeA, "codereview.chromium.local", &delegate_irrelevant);
   ASSERT_TRUE(listener_irrelevant->Start());
 
   SimulatePacketReceive(kSamplePacket1, sizeof(kSamplePacket1));
 
-  transaction_ = test_client_.CreateTransaction(
+  transaction_ = test_client_->CreateTransaction(
       dns_protocol::kTypePTR, "_privet._tcp.local",
-      MDnsTransaction::QUERY_NETWORK |
-      MDnsTransaction::QUERY_CACHE,
-      base::Bind(&MDnsTest::MockableRecordCallback,
-                 base::Unretained(this)));
+      MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE,
+      base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this)));
 
   EXPECT_CALL(*this, MockableRecordCallback(MDnsTransaction::RESULT_RECORD, _))
       .Times(Exactly(1))
@@ -791,22 +907,16 @@
 TEST_F(MDnsTest, TransactionReentrantCacheLookupStart) {
   ExpectPacket(kQueryPacketPrivet, sizeof(kQueryPacketPrivet));
 
-  scoped_ptr<MDnsTransaction> transaction1 =
-      test_client_.CreateTransaction(
-          dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
+  scoped_ptr<MDnsTransaction> transaction1 = test_client_->CreateTransaction(
+      dns_protocol::kTypePTR, "_privet._tcp.local",
+      MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
           MDnsTransaction::SINGLE_RESULT,
-          base::Bind(&MDnsTest::MockableRecordCallback,
-                     base::Unretained(this)));
+      base::Bind(&MDnsTest::MockableRecordCallback, base::Unretained(this)));
 
-  scoped_ptr<MDnsTransaction> transaction2 =
-      test_client_.CreateTransaction(
-          dns_protocol::kTypePTR, "_printer._tcp.local",
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
-          base::Bind(&MDnsTest::MockableRecordCallback2,
-                     base::Unretained(this)));
+  scoped_ptr<MDnsTransaction> transaction2 = test_client_->CreateTransaction(
+      dns_protocol::kTypePTR, "_printer._tcp.local",
+      MDnsTransaction::QUERY_CACHE | MDnsTransaction::SINGLE_RESULT,
+      base::Bind(&MDnsTest::MockableRecordCallback2, base::Unretained(this)));
 
   EXPECT_CALL(*this, MockableRecordCallback2(MDnsTransaction::RESULT_RECORD,
                                              _))
@@ -826,7 +936,7 @@
 TEST_F(MDnsTest, GoodbyePacketNotification) {
   StrictMock<MockListenerDelegate> delegate_privet;
 
-  scoped_ptr<MDnsListener> listener_privet = test_client_.CreateListener(
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
       dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
   ASSERT_TRUE(listener_privet->Start());
 
@@ -838,9 +948,8 @@
 TEST_F(MDnsTest, GoodbyePacketRemoval) {
   StrictMock<MockListenerDelegate> delegate_privet;
 
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
   ASSERT_TRUE(listener_privet->Start());
 
   EXPECT_CALL(delegate_privet, OnRecordUpdate(MDnsListener::RECORD_ADDED, _))
@@ -863,13 +972,11 @@
 TEST_F(MDnsTest, ListenerReentrantDelete) {
   StrictMock<MockListenerDelegate> delegate_privet;
 
-  listener1_ = test_client_.CreateListener(dns_protocol::kTypePTR,
-                                           "_privet._tcp.local",
-                                           &delegate_privet);
+  listener1_ = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
 
-  listener2_ = test_client_.CreateListener(dns_protocol::kTypePTR,
-                                           "_privet._tcp.local",
-                                           &delegate_privet);
+  listener2_ = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet);
 
   ASSERT_TRUE(listener1_->Start());
 
@@ -896,9 +1003,8 @@
   IPAddressNumber address;
   StrictMock<MockListenerDelegate> delegate_privet;
 
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypeA, "privet.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypeA, "privet.local", &delegate_privet);
 
   ASSERT_TRUE(listener_privet->Start());
 
@@ -914,16 +1020,14 @@
 
 TEST_F(MDnsTest, NsecWithListener) {
   StrictMock<MockListenerDelegate> delegate_privet;
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
 
   // Test to make sure nsec callback is NOT called for PTR
   // (which is marked as existing).
   StrictMock<MockListenerDelegate> delegate_privet2;
-  scoped_ptr<MDnsListener> listener_privet2 =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_privet2);
+  scoped_ptr<MDnsListener> listener_privet2 = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_privet2);
 
   ASSERT_TRUE(listener_privet->Start());
 
@@ -936,11 +1040,10 @@
 
 TEST_F(MDnsTest, NsecWithTransactionFromNetwork) {
   scoped_ptr<MDnsTransaction> transaction_privet =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypeA, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -958,9 +1061,8 @@
 TEST_F(MDnsTest, NsecWithTransactionFromCache) {
   // Force mDNS to listen.
   StrictMock<MockListenerDelegate> delegate_irrelevant;
-  scoped_ptr<MDnsListener> listener_irrelevant =
-      test_client_.CreateListener(dns_protocol::kTypePTR, "_privet._tcp.local",
-                                  &delegate_irrelevant);
+  scoped_ptr<MDnsListener> listener_irrelevant = test_client_->CreateListener(
+      dns_protocol::kTypePTR, "_privet._tcp.local", &delegate_irrelevant);
   listener_irrelevant->Start();
 
   SimulatePacketReceive(kSamplePacketNsec,
@@ -970,11 +1072,10 @@
               MockableRecordCallback(MDnsTransaction::RESULT_NSEC, NULL));
 
   scoped_ptr<MDnsTransaction> transaction_privet_a =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypeA, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -984,11 +1085,10 @@
   // valid answer to the query
 
   scoped_ptr<MDnsTransaction> transaction_privet_ptr =
-      test_client_.CreateTransaction(
+      test_client_->CreateTransaction(
           dns_protocol::kTypePTR, "_privet._tcp.local",
-          MDnsTransaction::QUERY_NETWORK |
-          MDnsTransaction::QUERY_CACHE |
-          MDnsTransaction::SINGLE_RESULT,
+          MDnsTransaction::QUERY_NETWORK | MDnsTransaction::QUERY_CACHE |
+              MDnsTransaction::SINGLE_RESULT,
           base::Bind(&MDnsTest::MockableRecordCallback,
                      base::Unretained(this)));
 
@@ -999,9 +1099,8 @@
 
 TEST_F(MDnsTest, NsecConflictRemoval) {
   StrictMock<MockListenerDelegate> delegate_privet;
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
 
   ASSERT_TRUE(listener_privet->Start());
 
@@ -1029,9 +1128,8 @@
 
 TEST_F(MDnsTest, RefreshQuery) {
   StrictMock<MockListenerDelegate> delegate_privet;
-  scoped_ptr<MDnsListener> listener_privet =
-      test_client_.CreateListener(dns_protocol::kTypeA, "_privet._tcp.local",
-                                  &delegate_privet);
+  scoped_ptr<MDnsListener> listener_privet = test_client_->CreateListener(
+      dns_protocol::kTypeA, "_privet._tcp.local", &delegate_privet);
 
   listener_privet->SetActiveRefresh(true);
   ASSERT_TRUE(listener_privet->Start());
@@ -1087,7 +1185,7 @@
 
  protected:
   // Follow successful connection initialization.
-  virtual void SetUp() override {
+  void SetUp() override {
     socket_ipv4_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV4);
     socket_ipv6_ = new MockMDnsDatagramServerSocket(ADDRESS_FAMILY_IPV6);
     factory_.PushSocket(socket_ipv6_);
@@ -1219,6 +1317,4 @@
   callback.Run(OK);
 }
 
-}  // namespace
-
 }  // namespace net
diff --git a/net/proxy/proxy_script_decider.cc b/net/proxy/proxy_script_decider.cc
index 7e5544a..3d830fc 100644
--- a/net/proxy/proxy_script_decider.cc
+++ b/net/proxy/proxy_script_decider.cc
@@ -476,7 +476,6 @@
       proxy_script_fetcher_->Cancel();
       break;
     default:
-      NOTREACHED();
       break;
   }
 
diff --git a/net/proxy/proxy_script_decider_unittest.cc b/net/proxy/proxy_script_decider_unittest.cc
index 8914f5b..f26e5e1 100644
--- a/net/proxy/proxy_script_decider_unittest.cc
+++ b/net/proxy/proxy_script_decider_unittest.cc
@@ -428,6 +428,16 @@
   EXPECT_EQ(rule.url, decider_->effective_config().pac_url());
 }
 
+// Regression test for http://crbug.com/409698.
+// This test lets the state machine get into state QUICK_CHECK_COMPLETE, then
+// destroys the decider, causing a cancel.
+TEST_F(ProxyScriptDeciderQuickCheckTest, CancelPartway) {
+  resolver_.set_synchronous_mode(false);
+  resolver_.set_ondemand_mode(true);
+  EXPECT_EQ(ERR_IO_PENDING, StartDecider());
+  decider_.reset(NULL);
+}
+
 // Fails at WPAD (downloading), but succeeds in choosing the custom PAC.
 TEST(ProxyScriptDeciderTest, AutodetectFailCustomSuccess1) {
   Rules rules;
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index b179e1e..8f48768 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1614,25 +1614,27 @@
   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_DP);
 }
 
-PDFiumPage::Area PDFiumEngine::GetCharIndex(
-    const pp::MouseInputEvent& event, int* page_index,
-    int* char_index, PDFiumPage::LinkTarget* target) {
+PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::MouseInputEvent& event,
+                                            int* page_index,
+                                            int* char_index,
+                                            int* form_type,
+                                            PDFiumPage::LinkTarget* target) {
   // First figure out which page this is in.
   pp::Point mouse_point = event.GetPosition();
-  pp::Point point(
-      static_cast<int>((mouse_point.x() + position_.x()) / current_zoom_),
-      static_cast<int>((mouse_point.y() + position_.y()) / current_zoom_));
-  return GetCharIndex(point, page_index, char_index, target);
+  return GetCharIndex(mouse_point, page_index, char_index, form_type, target);
 }
 
-PDFiumPage::Area PDFiumEngine::GetCharIndex(
-    const pp::Point& point,
-    int* page_index,
-    int* char_index,
-    PDFiumPage::LinkTarget* target) {
+PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point,
+                                            int* page_index,
+                                            int* char_index,
+                                            int* form_type,
+                                            PDFiumPage::LinkTarget* target) {
   int page = -1;
+  pp::Point point_in_page(
+      static_cast<int>((point.x() + position_.x()) / current_zoom_),
+      static_cast<int>((point.y() + position_.y()) / current_zoom_));
   for (size_t i = 0; i < visible_pages_.size(); ++i) {
-    if (pages_[visible_pages_[i]]->rect().Contains(point)) {
+    if (pages_[visible_pages_[i]]->rect().Contains(point_in_page)) {
       page = visible_pages_[i];
       break;
     }
@@ -1648,15 +1650,11 @@
   }
 
   *page_index = page;
-  return pages_[page]->GetCharIndex(point, current_rotation_, char_index,
-                                    target);
+  return pages_[page]->GetCharIndex(
+      point_in_page, current_rotation_, char_index, form_type, target);
 }
 
 bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) {
-  if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT &&
-      event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_RIGHT) {
-    return false;
-  }
   if (event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT) {
     if (!selection_.size())
       return false;
@@ -1672,15 +1670,18 @@
     selection_.clear();
     return true;
   }
+  if (event.GetButton() != PP_INPUTEVENT_MOUSEBUTTON_LEFT)
+    return false;
 
   SelectionChangeInvalidator selection_invalidator(this);
   selection_.clear();
 
   int page_index = -1;
   int char_index = -1;
+  int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
-  PDFiumPage::Area area = GetCharIndex(event, &page_index,
-                                       &char_index, &target);
+  PDFiumPage::Area area =
+      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
   mouse_down_state_.Set(area, target);
 
   // Decide whether to open link or not based on user action in mouse up and
@@ -1701,16 +1702,14 @@
     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
 
     FORM_OnLButtonDown(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
-    int control = FPDPage_HasFormFieldAtPoint(
-        form_, pages_[page_index]->GetPage(), page_x, page_y);
-    if (control > FPDF_FORMFIELD_UNKNOWN) {  // returns -1 sometimes...
+    if (form_type > FPDF_FORMFIELD_UNKNOWN) {  // returns -1 sometimes...
+      mouse_down_state_.Set(PDFiumPage::NONSELECTABLE_AREA, target);
+      bool is_valid_control = (form_type == FPDF_FORMFIELD_TEXTFIELD ||
+                               form_type == FPDF_FORMFIELD_COMBOBOX);
 #ifdef PDF_USE_XFA
-    client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD ||
-        control == FPDF_FORMFIELD_COMBOBOX || control == FPDF_FORMFIELD_XFA);
-#else
-    client_->FormTextFieldFocusChange(control == FPDF_FORMFIELD_TEXTFIELD ||
-        control == FPDF_FORMFIELD_COMBOBOX);
+      is_valid_control |= (form_type == FPDF_FORMFIELD_XFA);
 #endif
+      client_->FormTextFieldFocusChange(is_valid_control);
       return true;  // Return now before we get into the selection code.
     }
   }
@@ -1769,9 +1768,10 @@
 
   int page_index = -1;
   int char_index = -1;
+  int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
   PDFiumPage::Area area =
-      GetCharIndex(event, &page_index, &char_index, &target);
+      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
 
   // Open link on mouse up for same link for which mouse down happened earlier.
   if (mouse_down_state_.Matches(area, target)) {
@@ -1801,9 +1801,10 @@
 bool PDFiumEngine::OnMouseMove(const pp::MouseInputEvent& event) {
   int page_index = -1;
   int char_index = -1;
+  int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
   PDFiumPage::Area area =
-      GetCharIndex(event, &page_index, &char_index, &target);
+      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
 
   // Clear |mouse_down_state_| if mouse moves away from where the mouse down
   // happened.
@@ -1822,7 +1823,21 @@
         break;
       case PDFiumPage::NONSELECTABLE_AREA:
       default:
-        cursor = PP_CURSORTYPE_POINTER;
+        switch (form_type) {
+          case FPDF_FORMFIELD_PUSHBUTTON:
+          case FPDF_FORMFIELD_CHECKBOX:
+          case FPDF_FORMFIELD_RADIOBUTTON:
+          case FPDF_FORMFIELD_COMBOBOX:
+          case FPDF_FORMFIELD_LISTBOX:
+            cursor = PP_CURSORTYPE_HAND;
+            break;
+          case FPDF_FORMFIELD_TEXTFIELD:
+            cursor = PP_CURSORTYPE_IBEAM;
+            break;
+          default:
+            cursor = PP_CURSORTYPE_POINTER;
+            break;
+        }
         break;
     }
 
@@ -1830,24 +1845,7 @@
       double page_x, page_y;
       pp::Point point = event.GetPosition();
       DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
-
       FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
-      int control = FPDPage_HasFormFieldAtPoint(
-          form_, pages_[page_index]->GetPage(), page_x, page_y);
-      switch (control) {
-        case FPDF_FORMFIELD_PUSHBUTTON:
-        case FPDF_FORMFIELD_CHECKBOX:
-        case FPDF_FORMFIELD_RADIOBUTTON:
-        case FPDF_FORMFIELD_COMBOBOX:
-        case FPDF_FORMFIELD_LISTBOX:
-          cursor = PP_CURSORTYPE_HAND;
-          break;
-        case FPDF_FORMFIELD_TEXTFIELD:
-          cursor = PP_CURSORTYPE_IBEAM;
-          break;
-        default:
-          break;
-      }
     }
 
     client_->UpdateCursor(cursor);
@@ -2321,15 +2319,16 @@
 }
 
 std::string PDFiumEngine::GetLinkAtPosition(const pp::Point& point) {
+  std::string url;
   int temp;
+  int page_index = -1;
+  int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
-  pp::Point point_in_page(
-      static_cast<int>((point.x() + position_.x()) / current_zoom_),
-      static_cast<int>((point.y() + position_.y()) / current_zoom_));
-  PDFiumPage::Area area = GetCharIndex(point_in_page, &temp, &temp, &target);
+  PDFiumPage::Area area =
+      GetCharIndex(point, &page_index, &temp, &form_type, &target);
   if (area == PDFiumPage::WEBLINK_AREA)
-    return target.url;
-  return std::string();
+    url = target.url;
+  return url;
 }
 
 bool PDFiumEngine::IsSelecting() {
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 44ed9ae..ac05303 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -310,10 +310,12 @@
   PDFiumPage::Area GetCharIndex(const pp::MouseInputEvent& event,
                                 int* page_index,
                                 int* char_index,
+                                int* form_type,
                                 PDFiumPage::LinkTarget* target);
   PDFiumPage::Area GetCharIndex(const pp::Point& point,
                                 int* page_index,
                                 int* char_index,
+                                int* form_type,
                                 PDFiumPage::LinkTarget* target);
 
   void OnSingleClick(int page_index, int char_index);
diff --git a/pdf/pdfium/pdfium_page.cc b/pdf/pdfium/pdfium_page.cc
index 1335f07..e514af33 100644
--- a/pdf/pdfium/pdfium_page.cc
+++ b/pdf/pdfium/pdfium_page.cc
@@ -258,6 +258,7 @@
 PDFiumPage::Area PDFiumPage::GetCharIndex(const pp::Point& point,
                                           int rotation,
                                           int* char_index,
+                                          int* form_type,
                                           LinkTarget* target) {
   if (!available_)
     return NONSELECTABLE_AREA;
@@ -270,6 +271,13 @@
       GetTextPage(), new_x, new_y, kTolerance, kTolerance);
   *char_index = rv;
 
+  int control =
+      FPDPage_HasFormFieldAtPoint(engine_->form(), GetPage(), new_x, new_y);
+  if (control > FPDF_FORMFIELD_UNKNOWN) {
+    *form_type = control;
+    return PDFiumPage::NONSELECTABLE_AREA;
+  }
+
   FPDF_LINK link = FPDFLink_GetLinkAtPoint(GetPage(), new_x, new_y);
   if (link) {
     // We don't handle all possible link types of the PDF. For example,
diff --git a/pdf/pdfium/pdfium_page.h b/pdf/pdfium/pdfium_page.h
index de4317e..d4174f54 100644
--- a/pdf/pdfium/pdfium_page.h
+++ b/pdf/pdfium/pdfium_page.h
@@ -64,7 +64,7 @@
   // Target is optional. It will be filled in for WEBLINK_AREA or
   // DOCLINK_AREA only.
   Area GetCharIndex(const pp::Point& point, int rotation, int* char_index,
-                    LinkTarget* target);
+                    int* form_type, LinkTarget* target);
 
   // Gets the character at the given index.
   base::char16 GetCharAtIndex(int index);
diff --git a/ppapi/examples/BUILD.gn b/ppapi/examples/BUILD.gn
index fedb176..9369c585 100644
--- a/ppapi/examples/BUILD.gn
+++ b/ppapi/examples/BUILD.gn
@@ -32,5 +32,6 @@
     "//ppapi/examples/video_capture",
     "//ppapi/examples/video_decode",
     "//ppapi/examples/video_effects",
+    "//ppapi/examples/video_encode",
   ]
 }
diff --git a/ppapi/examples/video_encode/BUILD.gn b/ppapi/examples/video_encode/BUILD.gn
new file mode 100644
index 0000000..eaa3586f
--- /dev/null
+++ b/ppapi/examples/video_encode/BUILD.gn
@@ -0,0 +1,15 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//ppapi/examples/ppapi_example.gni")
+
+ppapi_example("video_encode") {
+  output_name = "ppapi_example_video_encode"
+  sources = [
+    "video_encode.cc",
+  ]
+  deps = [
+    "//ppapi/cpp",
+  ]
+}
diff --git a/ppapi/examples/video_encode/video_encode.cc b/ppapi/examples/video_encode/video_encode.cc
new file mode 100644
index 0000000..26c66df
--- /dev/null
+++ b/ppapi/examples/video_encode/video_encode.cc
@@ -0,0 +1,502 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/ppb_console.h"
+#include "ppapi/cpp/input_event.h"
+#include "ppapi/cpp/instance.h"
+#include "ppapi/cpp/media_stream_video_track.h"
+#include "ppapi/cpp/module.h"
+#include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/var.h"
+#include "ppapi/cpp/var_array_buffer.h"
+#include "ppapi/cpp/var_dictionary.h"
+#include "ppapi/cpp/video_encoder.h"
+#include "ppapi/cpp/video_frame.h"
+#include "ppapi/utility/completion_callback_factory.h"
+
+// TODO(llandwerlin): turn on by default when we have software encode.
+// #define USE_VP8_INSTEAD_OF_H264
+
+// When compiling natively on Windows, PostMessage can be #define-d to
+// something else.
+#ifdef PostMessage
+#undef PostMessage
+#endif
+
+// Use assert as a poor-man's CHECK, even in non-debug mode.
+// Since <assert.h> redefines assert on every inclusion (it doesn't use
+// include-guards), make sure this is the last file #include'd in this file.
+#undef NDEBUG
+#include <assert.h>
+
+namespace {
+
+std::string VideoProfileToString(PP_VideoProfile profile) {
+  switch (profile) {
+    case PP_VIDEOPROFILE_H264BASELINE:
+      return "h264baseline";
+    case PP_VIDEOPROFILE_H264MAIN:
+      return "h264main";
+    case PP_VIDEOPROFILE_H264EXTENDED:
+      return "h264extended";
+    case PP_VIDEOPROFILE_H264HIGH:
+      return "h264high";
+    case PP_VIDEOPROFILE_H264HIGH10PROFILE:
+      return "h264high10";
+    case PP_VIDEOPROFILE_H264HIGH422PROFILE:
+      return "h264high422";
+    case PP_VIDEOPROFILE_H264HIGH444PREDICTIVEPROFILE:
+      return "h264high444predictive";
+    case PP_VIDEOPROFILE_H264SCALABLEBASELINE:
+      return "h264scalablebaseline";
+    case PP_VIDEOPROFILE_H264SCALABLEHIGH:
+      return "h264scalablehigh";
+    case PP_VIDEOPROFILE_H264STEREOHIGH:
+      return "h264stereohigh";
+    case PP_VIDEOPROFILE_H264MULTIVIEWHIGH:
+      return "h264multiviewhigh";
+    case PP_VIDEOPROFILE_VP8_ANY:
+      return "vp8";
+    case PP_VIDEOPROFILE_VP9_ANY:
+      return "vp9";
+    // No default to catch unhandled profiles.
+  }
+  return "unknown";
+}
+
+std::string HardwareAccelerationToString(PP_HardwareAcceleration acceleration) {
+  switch (acceleration) {
+    case PP_HARDWAREACCELERATION_ONLY:
+      return "hardware";
+    case PP_HARDWAREACCELERATION_WITHFALLBACK:
+      return "hardware/software";
+    case PP_HARDWAREACCELERATION_NONE:
+      return "software";
+    // No default to catch unhandled accelerations.
+  }
+  return "unknown";
+}
+
+// This object is the global object representing this plugin library as long
+// as it is loaded.
+class VideoEncoderModule : public pp::Module {
+ public:
+  VideoEncoderModule() : pp::Module() {}
+  virtual ~VideoEncoderModule() {}
+
+  virtual pp::Instance* CreateInstance(PP_Instance instance);
+};
+
+class VideoEncoderInstance : public pp::Instance {
+ public:
+  VideoEncoderInstance(PP_Instance instance, pp::Module* module);
+  virtual ~VideoEncoderInstance();
+
+  // pp::Instance implementation.
+  virtual void HandleMessage(const pp::Var& var_message);
+
+ private:
+  void ConfigureTrack();
+  void OnConfiguredTrack(int32_t result);
+  void ProbeEncoder();
+  void OnEncoderProbed(int32_t result,
+                       const std::vector<PP_VideoProfileDescription> profiles);
+  void OnInitializedEncoder(int32_t result);
+  void ScheduleNextEncode();
+  void GetEncoderFrameTick(int32_t result);
+  void GetEncoderFrame(const pp::VideoFrame& track_frame);
+  void OnEncoderFrame(int32_t result,
+                      pp::VideoFrame encoder_frame,
+                      pp::VideoFrame track_frame);
+  int32_t CopyVideoFrame(pp::VideoFrame dest, pp::VideoFrame src);
+  void EncodeFrame(const pp::VideoFrame& frame);
+  void OnEncodeDone(int32_t result);
+  void OnGetBitstreamBuffer(int32_t result, PP_BitstreamBuffer buffer);
+  void StartTrackFrames();
+  void StopTrackFrames();
+  void OnTrackFrame(int32_t result, pp::VideoFrame frame);
+
+  void StopEncode();
+
+  void LogError(int32_t error, const std::string& message);
+  void Log(const std::string& message);
+
+  void PostDataMessage(const void* buffer, uint32_t size);
+  void PostSignalMessage(const char* name);
+
+  bool is_encoding_;
+  bool is_receiving_track_frames_;
+
+  pp::VideoEncoder video_encoder_;
+  pp::MediaStreamVideoTrack video_track_;
+  pp::CompletionCallbackFactory<VideoEncoderInstance> callback_factory_;
+
+  PP_VideoProfile video_profile_;
+  PP_VideoFrame_Format frame_format_;
+
+  pp::Size requested_size_;
+  pp::Size frame_size_;
+  pp::Size encoder_size_;
+  uint32_t encoded_frames_;
+
+  pp::VideoFrame current_track_frame_;
+};
+
+VideoEncoderInstance::VideoEncoderInstance(PP_Instance instance,
+                                           pp::Module* module)
+    : pp::Instance(instance),
+      is_encoding_(false),
+      callback_factory_(this),
+#if defined(USE_VP8_INSTEAD_OF_H264)
+      video_profile_(PP_VIDEOPROFILE_VP8_ANY),
+#else
+      video_profile_(PP_VIDEOPROFILE_H264MAIN),
+#endif
+      frame_format_(PP_VIDEOFRAME_FORMAT_I420),
+      encoded_frames_(0) {
+}
+
+VideoEncoderInstance::~VideoEncoderInstance() {
+}
+
+void VideoEncoderInstance::ConfigureTrack() {
+  if (encoder_size_.IsEmpty())
+    frame_size_ = requested_size_;
+  else
+    frame_size_ = encoder_size_;
+
+  int32_t attrib_list[] = {PP_MEDIASTREAMVIDEOTRACK_ATTRIB_FORMAT,
+                           frame_format_,
+                           PP_MEDIASTREAMVIDEOTRACK_ATTRIB_WIDTH,
+                           frame_size_.width(),
+                           PP_MEDIASTREAMVIDEOTRACK_ATTRIB_HEIGHT,
+                           frame_size_.height(),
+                           PP_MEDIASTREAMVIDEOTRACK_ATTRIB_NONE};
+
+  pp::VarDictionary dict;
+  dict.Set(pp::Var("status"), pp::Var("configuring video track"));
+  dict.Set(pp::Var("width"), pp::Var(frame_size_.width()));
+  dict.Set(pp::Var("height"), pp::Var(frame_size_.height()));
+  PostMessage(dict);
+
+  video_track_.Configure(
+      attrib_list,
+      callback_factory_.NewCallback(&VideoEncoderInstance::OnConfiguredTrack));
+}
+
+void VideoEncoderInstance::OnConfiguredTrack(int32_t result) {
+  if (result != PP_OK) {
+    LogError(result, "Cannot configure track");
+    return;
+  }
+
+  if (is_encoding_) {
+    StartTrackFrames();
+    ScheduleNextEncode();
+  } else
+    ProbeEncoder();
+}
+
+void VideoEncoderInstance::ProbeEncoder() {
+  video_encoder_ = pp::VideoEncoder(this);
+  video_encoder_.GetSupportedProfiles(callback_factory_.NewCallbackWithOutput(
+      &VideoEncoderInstance::OnEncoderProbed));
+}
+
+void VideoEncoderInstance::OnEncoderProbed(
+    int32_t result,
+    const std::vector<PP_VideoProfileDescription> profiles) {
+  bool has_required_profile = false;
+
+  Log("Available profiles:");
+  for (const PP_VideoProfileDescription& profile : profiles) {
+    std::ostringstream oss;
+    oss << " profile=" << VideoProfileToString(profile.profile)
+        << " max_resolution=" << profile.max_resolution.width << "x"
+        << profile.max_resolution.height
+        << " max_framerate=" << profile.max_framerate_numerator << "/"
+        << profile.max_framerate_denominator << " acceleration="
+        << HardwareAccelerationToString(profile.acceleration);
+    Log(oss.str());
+
+    has_required_profile |= profile.profile == video_profile_;
+  }
+
+  if (!has_required_profile) {
+    std::ostringstream oss;
+    oss << "Cannot find required video profile: ";
+    oss << VideoProfileToString(video_profile_);
+    LogError(PP_ERROR_FAILED, oss.str());
+    return;
+  }
+
+  video_encoder_ = pp::VideoEncoder(this);
+
+  pp::VarDictionary dict;
+  dict.Set(pp::Var("status"), pp::Var("initializing encoder"));
+  dict.Set(pp::Var("width"), pp::Var(encoder_size_.width()));
+  dict.Set(pp::Var("height"), pp::Var(encoder_size_.height()));
+  PostMessage(dict);
+
+  int32_t error = video_encoder_.Initialize(
+      frame_format_, frame_size_, video_profile_, 2000000,
+      PP_HARDWAREACCELERATION_WITHFALLBACK,
+      callback_factory_.NewCallback(
+          &VideoEncoderInstance::OnInitializedEncoder));
+  if (error != PP_OK_COMPLETIONPENDING) {
+    LogError(error, "Cannot initialize encoder");
+    return;
+  }
+}
+
+void VideoEncoderInstance::OnInitializedEncoder(int32_t result) {
+  if (result != PP_OK) {
+    LogError(result, "Encoder initialization failed");
+    return;
+  }
+
+  is_encoding_ = true;
+
+  if (video_encoder_.GetFrameCodedSize(&encoder_size_) != PP_OK) {
+    LogError(result, "Cannot get encoder coded frame size");
+    return;
+  }
+
+  pp::VarDictionary dict;
+  dict.Set(pp::Var("status"), pp::Var("encoder initialized"));
+  dict.Set(pp::Var("width"), pp::Var(encoder_size_.width()));
+  dict.Set(pp::Var("height"), pp::Var(encoder_size_.height()));
+  PostMessage(dict);
+
+  video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
+      &VideoEncoderInstance::OnGetBitstreamBuffer));
+
+  if (encoder_size_ != frame_size_)
+    ConfigureTrack();
+  else {
+    StartTrackFrames();
+    ScheduleNextEncode();
+  }
+}
+
+void VideoEncoderInstance::ScheduleNextEncode() {
+  pp::Module::Get()->core()->CallOnMainThread(
+      1000 / 30,
+      callback_factory_.NewCallback(&VideoEncoderInstance::GetEncoderFrameTick),
+      0);
+}
+
+void VideoEncoderInstance::GetEncoderFrameTick(int32_t result) {
+  if (is_encoding_) {
+    if (!current_track_frame_.is_null()) {
+      pp::VideoFrame frame = current_track_frame_;
+      current_track_frame_.detach();
+      GetEncoderFrame(frame);
+    }
+    ScheduleNextEncode();
+  }
+}
+
+void VideoEncoderInstance::GetEncoderFrame(const pp::VideoFrame& track_frame) {
+  video_encoder_.GetVideoFrame(callback_factory_.NewCallbackWithOutput(
+      &VideoEncoderInstance::OnEncoderFrame, track_frame));
+}
+
+void VideoEncoderInstance::OnEncoderFrame(int32_t result,
+                                          pp::VideoFrame encoder_frame,
+                                          pp::VideoFrame track_frame) {
+  if (result == PP_ERROR_ABORTED) {
+    video_track_.RecycleFrame(track_frame);
+    return;
+  }
+  if (result != PP_OK) {
+    video_track_.RecycleFrame(track_frame);
+    LogError(result, "Cannot get video frame from video encoder");
+    return;
+  }
+
+  track_frame.GetSize(&frame_size_);
+
+  if (frame_size_ != encoder_size_) {
+    video_track_.RecycleFrame(track_frame);
+    LogError(PP_ERROR_FAILED, "MediaStreamVideoTrack frame size incorrect");
+    return;
+  }
+
+  if (CopyVideoFrame(encoder_frame, track_frame) == PP_OK)
+    EncodeFrame(encoder_frame);
+  video_track_.RecycleFrame(track_frame);
+}
+
+int32_t VideoEncoderInstance::CopyVideoFrame(pp::VideoFrame dest,
+                                             pp::VideoFrame src) {
+  if (dest.GetDataBufferSize() < src.GetDataBufferSize()) {
+    std::ostringstream oss;
+    oss << "Incorrect destination video frame buffer size : "
+        << dest.GetDataBufferSize() << " < " << src.GetDataBufferSize();
+    LogError(PP_ERROR_FAILED, oss.str());
+    return PP_ERROR_FAILED;
+  }
+
+  memcpy(dest.GetDataBuffer(), src.GetDataBuffer(), src.GetDataBufferSize());
+  return PP_OK;
+}
+
+void VideoEncoderInstance::EncodeFrame(const pp::VideoFrame& frame) {
+  video_encoder_.Encode(
+      frame, PP_FALSE,
+      callback_factory_.NewCallback(&VideoEncoderInstance::OnEncodeDone));
+}
+
+void VideoEncoderInstance::OnEncodeDone(int32_t result) {
+  if (result == PP_ERROR_ABORTED)
+    return;
+  if (result != PP_OK)
+    LogError(result, "Encode failed");
+}
+
+void VideoEncoderInstance::OnGetBitstreamBuffer(int32_t result,
+                                                PP_BitstreamBuffer buffer) {
+  if (result == PP_ERROR_ABORTED)
+    return;
+  if (result != PP_OK) {
+    LogError(result, "Cannot get bitstream buffer");
+    return;
+  }
+
+  encoded_frames_++;
+  PostDataMessage(buffer.buffer, buffer.size);
+  video_encoder_.RecycleBitstreamBuffer(buffer);
+
+  video_encoder_.GetBitstreamBuffer(callback_factory_.NewCallbackWithOutput(
+      &VideoEncoderInstance::OnGetBitstreamBuffer));
+}
+
+void VideoEncoderInstance::StartTrackFrames() {
+  is_receiving_track_frames_ = true;
+  video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
+      &VideoEncoderInstance::OnTrackFrame));
+}
+
+void VideoEncoderInstance::StopTrackFrames() {
+  is_receiving_track_frames_ = false;
+  if (!current_track_frame_.is_null()) {
+    video_track_.RecycleFrame(current_track_frame_);
+    current_track_frame_.detach();
+  }
+}
+
+void VideoEncoderInstance::OnTrackFrame(int32_t result, pp::VideoFrame frame) {
+  if (result == PP_ERROR_ABORTED)
+    return;
+
+  if (!current_track_frame_.is_null()) {
+    video_track_.RecycleFrame(current_track_frame_);
+    current_track_frame_.detach();
+  }
+
+  if (result != PP_OK) {
+    LogError(result, "Cannot get video frame from video track");
+    return;
+  }
+
+  current_track_frame_ = frame;
+  if (is_receiving_track_frames_)
+    video_track_.GetFrame(callback_factory_.NewCallbackWithOutput(
+        &VideoEncoderInstance::OnTrackFrame));
+}
+
+void VideoEncoderInstance::StopEncode() {
+  video_encoder_.Close();
+  StopTrackFrames();
+  video_track_.Close();
+  is_encoding_ = false;
+  encoded_frames_ = 0;
+}
+
+//
+
+void VideoEncoderInstance::HandleMessage(const pp::Var& var_message) {
+  if (!var_message.is_dictionary()) {
+    LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid message!"));
+    return;
+  }
+
+  pp::VarDictionary dict_message(var_message);
+  std::string command = dict_message.Get("command").AsString();
+
+  if (command == "start") {
+    requested_size_ = pp::Size(dict_message.Get("width").AsInt(),
+                               dict_message.Get("height").AsInt());
+    pp::Var var_track = dict_message.Get("track");
+    if (!var_track.is_resource()) {
+      LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Given track is not a resource"));
+      return;
+    }
+    pp::Resource resource_track = var_track.AsResource();
+    video_track_ = pp::MediaStreamVideoTrack(resource_track);
+    video_encoder_ = pp::VideoEncoder();
+    ConfigureTrack();
+  } else if (command == "stop") {
+    StopEncode();
+    PostSignalMessage("stopped");
+  } else {
+    LogToConsole(PP_LOGLEVEL_ERROR, pp::Var("Invalid command!"));
+  }
+}
+
+void VideoEncoderInstance::PostDataMessage(const void* buffer, uint32_t size) {
+  pp::VarDictionary dictionary;
+
+  dictionary.Set(pp::Var("name"), pp::Var("data"));
+
+  pp::VarArrayBuffer array_buffer(size);
+  void* data_ptr = array_buffer.Map();
+  memcpy(data_ptr, buffer, size);
+  array_buffer.Unmap();
+  dictionary.Set(pp::Var("data"), array_buffer);
+
+  PostMessage(dictionary);
+}
+
+void VideoEncoderInstance::PostSignalMessage(const char* name) {
+  pp::VarDictionary dictionary;
+  dictionary.Set(pp::Var("name"), pp::Var(name));
+
+  PostMessage(dictionary);
+}
+
+void VideoEncoderInstance::LogError(int32_t error, const std::string& message) {
+  std::string msg("Error: ");
+  msg.append(pp::Var(error).DebugString());
+  msg.append(" : ");
+  msg.append(message);
+  LogToConsole(PP_LOGLEVEL_ERROR, pp::Var(msg));
+}
+
+void VideoEncoderInstance::Log(const std::string& message) {
+  LogToConsole(PP_LOGLEVEL_LOG, pp::Var(message));
+}
+
+pp::Instance* VideoEncoderModule::CreateInstance(PP_Instance instance) {
+  return new VideoEncoderInstance(instance, this);
+}
+
+}  // anonymous namespace
+
+namespace pp {
+// Factory function for your specialization of the Module object.
+Module* CreateModule() {
+  return new VideoEncoderModule();
+}
+}  // namespace pp
diff --git a/ppapi/examples/video_encode/video_encode.html b/ppapi/examples/video_encode/video_encode.html
new file mode 100644
index 0000000..803c1f4
--- /dev/null
+++ b/ppapi/examples/video_encode/video_encode.html
@@ -0,0 +1,127 @@
+<!DOCTYPE html>
+<html>
+  <!--
+  Copyright 2015 The Chromium Authors. All rights reserved.
+  Use of this source code is governed by a BSD-style license that can be
+  found in the LICENSE file.
+  -->
+<head>
+  <title>Video Encoder Example</title>
+  <style type="text/css">
+    #video {
+      position: fixed;
+    }
+    #video-playback {
+      position: fixed;
+      left: 640px;
+    }
+    #plugin {
+      position: fixed;
+    }
+  </style>
+  <script type="text/javascript">
+    var plugin;
+    var track;
+    var video;
+
+    function $(id) {
+      return document.getElementById(id);
+    }
+
+    function success(stream) {
+      track = stream.getVideoTracks()[0];
+      video.src = URL.createObjectURL(stream);
+      video.play();
+
+      plugin.postMessage({
+        command: 'start',
+        track: track,
+        width: 640,
+        height: 480
+      });
+    }
+
+    function failure(e) {
+      console.log("Error: ", e);
+    }
+
+    function startRecord() {
+      console.log("starting record");
+      navigator.webkitGetUserMedia({audio: false, video: true},
+                                   success, failure);
+    }
+
+    function stopRecord() {
+      plugin.postMessage({
+        command: "stop"
+      });
+      var video = $('video');
+      video.pause();
+      track.stop();
+    }
+
+    function saveBlob(blob) {
+      var blobUrl = URL.createObjectURL(blob);
+      window.location = blobUrl;
+    }
+
+    function handleMessage(msg) {
+      if (msg.data.name == 'started') {
+        console.log('recording!');
+      } else if (msg.data.name == 'data') {
+        appendData(msg.data.data);
+      } else if (msg.data.name == 'stopped') {
+        console.log('done recording! bytes: ' + dataArray.byteLength);
+      }
+    }
+
+    function resetData() {
+      window.dataArray = new ArrayBuffer(0);
+    }
+
+    function appendData(data) {
+      var tmp = new Uint8Array(dataArray.byteLength + data.byteLength);
+      tmp.set(new Uint8Array(dataArray), 0 );
+      tmp.set(new Uint8Array(data), dataArray.byteLength);
+      dataArray = tmp.buffer;
+      $('length').innerHTML = ' Size: ' + dataArray.byteLength + ' bytes';
+    }
+
+    function initialize() {
+      plugin = $('plugin');
+      plugin.addEventListener('message', handleMessage, false);
+
+      video = $('video');
+
+      $('start').addEventListener('click', function (e) {
+        resetData();
+        startRecord();
+      });
+      $('stop').addEventListener('click', function (e) {
+        stopRecord();
+      });
+      $('download').addEventListener('click', function (e) {
+        saveBlob(new Blob([dataArray], { type: "application/octet-stream" }));
+      });
+    }
+
+    document.addEventListener('DOMContentLoaded', initialize, false);
+  </script>
+</head>
+
+<body>
+  <h1>Video Encoder API Example</h1><br>
+  This example demonstrates receiving frames from a video MediaStreamTrack and
+  encoding them in a plugin.
+  <br>
+  <input type="button" id="start" value="Start Recording"/>
+  <input type="button" id="stop" value="Stop Recording"/>
+  <input type="button" id="download" value="Download Recording"/>
+  <div id="length"></div>
+  <br>
+  <div>
+    <embed id="plugin" type="application/x-ppapi-example-video-encode"/>
+    <video id="video" width="640" height="480"/>
+  </div>
+</body>
+</html>
diff --git a/ppapi/ppapi_tests.gypi b/ppapi/ppapi_tests.gypi
index 562903d..3267e0b 100644
--- a/ppapi/ppapi_tests.gypi
+++ b/ppapi/ppapi_tests.gypi
@@ -498,6 +498,16 @@
       ],
     },
     {
+      'target_name': 'ppapi_example_video_encode',
+      'dependencies': [
+        'ppapi_example_skeleton',
+        'ppapi.gyp:ppapi_cpp',
+      ],
+      'sources': [
+        'examples/video_encode/video_encode.cc',
+      ],
+    },
+    {
       # GN version: //ppapi/example/video_capture
       'target_name': 'ppapi_example_vc',
       'dependencies': [
diff --git a/remoting/app_remoting_webapp.gyp b/remoting/app_remoting_webapp.gyp
index de11d0f..e179f1e78 100644
--- a/remoting/app_remoting_webapp.gyp
+++ b/remoting/app_remoting_webapp.gyp
@@ -62,6 +62,29 @@
               '<@(remoting_webapp_js_proto_files)',
             ],
           },
+          {
+            'action_name': 'Verify >(ar_app_name) feedback_consent.html',
+            'variables': {
+              'success_stamp': '<(PRODUCT_DIR)/>(_target_name)_feedback_consent_jscompile.stamp',
+            },
+            'inputs': [
+              '<@(ar_feedback_consent_js_files)',
+              '<@(remoting_webapp_js_proto_files)',
+              # Include zip as input so that this action is run after the build.
+              '<(zip_path)',
+            ],
+            'outputs': [
+              '<(success_stamp)',
+            ],
+            'action': [
+              'python', '../third_party/closure_compiler/checker.py',
+              '--strict',
+              '--no-single-file',
+              '--success-stamp', '<(success_stamp)',
+              '<@(ar_feedback_consent_js_files)',
+              '<@(remoting_webapp_js_proto_files)',
+            ],
+          },
         ],  # actions
       }],
     ],  # conditions
diff --git a/remoting/app_remoting_webapp_build.gypi b/remoting/app_remoting_webapp_build.gypi
index 9e739f7..cdd5ecf5 100644
--- a/remoting/app_remoting_webapp_build.gypi
+++ b/remoting/app_remoting_webapp_build.gypi
@@ -6,15 +6,12 @@
   'includes': [
     'remoting_version.gypi',
     'remoting_locales.gypi',
+    'remoting_options.gypi',
     'remoting_webapp_files.gypi',
     'app_remoting_webapp_files.gypi',
   ],
 
   'variables': {
-    'chromium_code': 1,
-
-    'run_jscompile%': 0,
-
     # The ar_service_environment variable is used to define the target
     # environment for the app being built.
     # The allowed values are dev, test, staging, and prod.
@@ -58,6 +55,7 @@
       'ar_generated_html_files': [
         '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/main.html',
         '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/wcs_sandbox.html',
+        '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html',
       ],
       'ar_webapp_files': [
         '<@(ar_app_specific_files)',
@@ -189,6 +187,28 @@
           '<@(remoting_webapp_wcs_sandbox_html_js_files)',
         ],
       },
+      {
+        'action_name': 'Build ">(ar_app_name)" feedback_consent.html',
+        'inputs': [
+          '<(DEPTH)/remoting/webapp/build-html.py',
+          '<(ar_feedback_consent_template)',
+          '<@(ar_feedback_consent_template_files)',
+        ],
+        'outputs': [
+          '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html',
+        ],
+        'action': [
+          'python', '<(DEPTH)/remoting/webapp/build-html.py',
+          '<(SHARED_INTERMEDIATE_DIR)/>(_target_name)/feedback_consent.html',
+          '<(ar_feedback_consent_template)',
+          '--template-dir',
+          '<(DEPTH)/remoting',
+          '--templates',
+          '<@(ar_feedback_consent_template_files)',
+          '--js',
+          '<@(ar_feedback_consent_js_files)',
+        ],
+      },
     ],  # actions
     'conditions': [
       ['buildtype == "Dev"', {
diff --git a/remoting/app_remoting_webapp_files.gypi b/remoting/app_remoting_webapp_files.gypi
index cd9bf8c..5df8b8e 100644
--- a/remoting/app_remoting_webapp_files.gypi
+++ b/remoting/app_remoting_webapp_files.gypi
@@ -6,13 +6,29 @@
   'variables': {
     'ar_shared_resource_files': [
       'webapp/app_remoting/html/ar_dialog.css',
+      'webapp/app_remoting/html/ar_main.css',
       'webapp/app_remoting/html/feedback_consent.css',
-      'webapp/app_remoting/html/feedback_consent.html',
       'webapp/app_remoting/html/context_menu.css',
       'resources/drag.webp',
       '<@(remoting_webapp_resource_files)',
     ],
 
+    # Variables for feedback_consent.html.
+    'ar_feedback_consent_template':
+      '<(DEPTH)/remoting/webapp/app_remoting/html/template_feedback_consent.html',
+    'ar_feedback_consent_template_files': [
+    ],
+    'ar_feedback_consent_js_files': [
+      'webapp/app_remoting/js/feedback_consent.js',
+      'webapp/base/js/base.js',
+      'webapp/crd/js/error.js',
+      'webapp/crd/js/oauth2_api.js',
+      'webapp/crd/js/oauth2_api_impl.js',
+      'webapp/crd/js/plugin_settings.js',
+      'webapp/crd/js/l10n.js',
+      'webapp/crd/js/xhr.js',
+    ],
+
     # Variables for main.html.
     # These template files are used to construct the webapp html files.
     'ar_main_template':
@@ -74,7 +90,7 @@
     'app_remoting_webapp_localizable_files': [
       '<(ar_main_template)',
       '<@(ar_main_template_files)',
-      'webapp/app_remoting/html/feedback_consent.html',
+      '<(ar_feedback_consent_template)',
       '<@(ar_all_js_files)',
     ],
 
diff --git a/remoting/base/auth_token_util.cc b/remoting/base/auth_token_util.cc
deleted file mode 100644
index 45caa92..0000000
--- a/remoting/base/auth_token_util.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/base/auth_token_util.h"
-#include "remoting/base/constants.h"
-
-namespace remoting {
-
-void ParseAuthTokenWithService(const std::string& auth_service_with_token,
-                               std::string* auth_token,
-                               std::string* auth_service) {
-  size_t delimiter_pos = auth_service_with_token.find(':');
-  if (delimiter_pos == std::string::npos) {
-    // Legacy case: there is no delimiter. Assume the whole string is the
-    // auth_token, and that we're using the default service.
-    //
-    // TODO(ajwong): Remove this defaulting once all webclients are migrated.
-    // BUG:83897
-    auth_token->assign(auth_service_with_token);
-    auth_service->assign(kChromotingTokenDefaultServiceName);
-  } else {
-    auth_service->assign(auth_service_with_token.substr(0, delimiter_pos));
-
-    // Make sure there is *something* after the delimiter before doing substr.
-    if (delimiter_pos < auth_service_with_token.size()) {
-      auth_token->assign(auth_service_with_token.substr(delimiter_pos + 1));
-    } else {
-      auth_token->clear();
-    }
-  }
-}
-
-}  // namespace remoting
diff --git a/remoting/base/auth_token_util.h b/remoting/base/auth_token_util.h
deleted file mode 100644
index 309a888..0000000
--- a/remoting/base/auth_token_util.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef REMOTING_BASE_AUTH_TOKEN_UTIL_H_
-#define REMOTING_BASE_AUTH_TOKEN_UTIL_H_
-
-#include <string>
-
-namespace remoting {
-
-// Given a string of the form "auth_service:auth_token" parses it into its
-// component pieces.
-void ParseAuthTokenWithService(const std::string& auth_service_with_token,
-                               std::string* auth_token,
-                               std::string* auth_service);
-
-}  // namespace remoting
-
-#endif  // REMOTING_BASE_AUTH_TOKEN_UTIL_H_
diff --git a/remoting/base/auth_token_util_unittest.cc b/remoting/base/auth_token_util_unittest.cc
deleted file mode 100644
index 2732b44..0000000
--- a/remoting/base/auth_token_util_unittest.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "remoting/base/auth_token_util.h"
-#include "remoting/base/constants.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace remoting {
-namespace {
-
-TEST(AuthTokenUtilTest, ParseAuthTokenWithService) {
-  std::string auth_token;
-  std::string auth_service;
-
-  ParseAuthTokenWithService("service:token", &auth_token, &auth_service);
-  EXPECT_EQ("token", auth_token);
-  EXPECT_EQ("service", auth_service);
-
-  // Check for legacy support.
-  ParseAuthTokenWithService("token2", &auth_token, &auth_service);
-  EXPECT_EQ("token2", auth_token);
-  EXPECT_EQ(std::string(kChromotingTokenDefaultServiceName), auth_service);
-
-  ParseAuthTokenWithService("just_service:", &auth_token, &auth_service);
-  EXPECT_EQ("", auth_token);
-  EXPECT_EQ("just_service", auth_service);
-
-  ParseAuthTokenWithService("yay:token:has:colons", &auth_token, &auth_service);
-  EXPECT_EQ("token:has:colons", auth_token);
-  EXPECT_EQ("yay", auth_service);
-}
-
-}  // namespace
-
-}  // namespace remoting
diff --git a/remoting/base/constants.cc b/remoting/base/constants.cc
index 00995702..172c73e 100644
--- a/remoting/base/constants.cc
+++ b/remoting/base/constants.cc
@@ -6,8 +6,6 @@
 
 namespace remoting {
 
-const char kChromotingTokenDefaultServiceName[] = "chromiumsync";
-
 const char kChromotingXmlNamespace[] = "google:remoting";
 
 const char kAudioChannelName[] = "audio";
diff --git a/remoting/base/constants.h b/remoting/base/constants.h
index 80c557266..43e3564 100644
--- a/remoting/base/constants.h
+++ b/remoting/base/constants.h
@@ -7,11 +7,6 @@
 
 namespace remoting {
 
-// Service name used for authentication.
-// TODO(ajwong): Remove this once we've killed off XmppToken usage.
-// BUG:83897
-extern const char kChromotingTokenDefaultServiceName[];
-
 // Namespace used for chromoting XMPP stanzas.
 extern const char kChromotingXmlNamespace[];
 
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index 2c77fda..6cfc8870e 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -63,7 +63,6 @@
   xmpp_config_.use_tls = kXmppUseTls;
   xmpp_config_.username = username;
   xmpp_config_.auth_token = auth_token;
-  xmpp_config_.auth_service = "oauth2";
 
   // Initialize |authenticator_|.
   scoped_ptr<protocol::ThirdPartyClientAuthenticator::TokenFetcher>
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 12c6bd0..3b0e4ac 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -34,13 +34,13 @@
     "//ui/events:dom4_keycode_converter",
   ]
 
-  if (is_linux) {
+  if (is_linux && !is_chromeos) {
     libs += [ "pam" ]
   }
 
   if (use_x11) {
     configs += [
-      #TODO : (kelvinp) Add GTK to the configs.
+      # TODO(kelvinp): Add GTK to the configs.
       "//build/config/linux:x11",
     ]
   } else {
@@ -83,7 +83,6 @@
       "continue_window_linux.cc",
       "disconnect_window_linux.cc",
       "local_input_monitor_x11.cc",
-      "remoting_me2me_host.cc",
     ]
   }
 
diff --git a/remoting/host/host_config.h b/remoting/host/host_config.h
index 198ddbb..1ec35ce9c8 100644
--- a/remoting/host/host_config.h
+++ b/remoting/host/host_config.h
@@ -27,12 +27,8 @@
 extern const char kHostOwnerEmailConfigPath[];
 // Login used to authenticate in XMPP network (could be a service account).
 extern const char kXmppLoginConfigPath[];
-// Auth token used to authenticate to XMPP network.
-extern const char kXmppAuthTokenConfigPath[];
 // OAuth refresh token used to fetch an access token for the XMPP network.
 extern const char kOAuthRefreshTokenConfigPath[];
-// Auth service used to authenticate to XMPP network.
-extern const char kXmppAuthServiceConfigPath[];
 // Unique identifier of the host used to register the host in directory.
 // Normally a random UUID.
 extern const char kHostIdConfigPath[];
diff --git a/remoting/host/host_config_constants.cc b/remoting/host/host_config_constants.cc
index c98e182..62631c2c 100644
--- a/remoting/host/host_config_constants.cc
+++ b/remoting/host/host_config_constants.cc
@@ -13,9 +13,7 @@
 const char kHostOwnerConfigPath[] = "host_owner";
 const char kHostOwnerEmailConfigPath[] = "host_owner_email";
 const char kXmppLoginConfigPath[] = "xmpp_login";
-const char kXmppAuthTokenConfigPath[] = "xmpp_auth_token";
 const char kOAuthRefreshTokenConfigPath[] = "oauth_refresh_token";
-const char kXmppAuthServiceConfigPath[] = "xmpp_auth_service";
 const char kHostIdConfigPath[] = "host_id";
 const char kHostNameConfigPath[] = "host_name";
 const char kHostSecretHashConfigPath[] = "host_secret_hash";
diff --git a/remoting/host/host_config_unittest.cc b/remoting/host/host_config_unittest.cc
index 5e6fab6c..3500381 100644
--- a/remoting/host/host_config_unittest.cc
+++ b/remoting/host/host_config_unittest.cc
@@ -17,7 +17,7 @@
 const char* kTestConfig =
 "{\n"
 "  \"xmpp_login\" : \"test@gmail.com\",\n"
-"  \"xmpp_auth_token\" : \"TEST_AUTH_TOKEN\",\n"
+"  \"oauth_refresh_token\" : \"TEST_REFRESH_TOKEN\",\n"
 "  \"host_id\" : \"TEST_HOST_ID\",\n"
 "  \"host_name\" : \"TEST_MACHINE_NAME\",\n"
 "  \"private_key\" : \"TEST_PRIVATE_KEY\"\n"
@@ -57,8 +57,8 @@
   std::string value;
   EXPECT_TRUE(target->GetString(kXmppLoginConfigPath, &value));
   EXPECT_EQ("test@gmail.com", value);
-  EXPECT_TRUE(target->GetString(kXmppAuthTokenConfigPath, &value));
-  EXPECT_EQ("TEST_AUTH_TOKEN", value);
+  EXPECT_TRUE(target->GetString(kOAuthRefreshTokenConfigPath, &value));
+  EXPECT_EQ("TEST_REFRESH_TOKEN", value);
   EXPECT_TRUE(target->GetString(kHostIdConfigPath, &value));
   EXPECT_EQ("TEST_HOST_ID", value);
   EXPECT_TRUE(target->GetString(kHostNameConfigPath, &value));
@@ -77,8 +77,8 @@
   scoped_ptr<base::DictionaryValue> target(HostConfigFromJsonFile(test_file));
   ASSERT_TRUE(target);
 
-  std::string new_auth_token_value = "NEW_AUTH_TOKEN";
-  target->SetString(kXmppAuthTokenConfigPath, new_auth_token_value);
+  std::string new_refresh_token_value = "NEW_REFRESH_TOKEN";
+  target->SetString(kOAuthRefreshTokenConfigPath, new_refresh_token_value);
   ASSERT_TRUE(HostConfigToJsonFile(*target, test_file));
 
   // Now read the file again and check that the value has been written.
@@ -88,8 +88,8 @@
   std::string value;
   EXPECT_TRUE(reader->GetString(kXmppLoginConfigPath, &value));
   EXPECT_EQ("test@gmail.com", value);
-  EXPECT_TRUE(reader->GetString(kXmppAuthTokenConfigPath, &value));
-  EXPECT_EQ(new_auth_token_value, value);
+  EXPECT_TRUE(reader->GetString(kOAuthRefreshTokenConfigPath, &value));
+  EXPECT_EQ(new_refresh_token_value, value);
   EXPECT_TRUE(reader->GetString(kHostIdConfigPath, &value));
   EXPECT_EQ("TEST_HOST_ID", value);
   EXPECT_TRUE(reader->GetString(kHostNameConfigPath, &value));
diff --git a/remoting/host/host_signaling_manager.cc b/remoting/host/host_signaling_manager.cc
index 99ad431b..f9bb941 100644
--- a/remoting/host/host_signaling_manager.cc
+++ b/remoting/host/host_signaling_manager.cc
@@ -43,18 +43,14 @@
 
   scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker(new DnsBlackholeChecker(
       url_request_context_getter, talkgadget_prefix_policy));
+  scoped_ptr<OAuthTokenGetter> oauth_token_getter(new OAuthTokenGetter(
+      oauth_credentials.Pass(), url_request_context_getter, false));
 
   scoped_ptr<SignalingConnector> signaling_connector(new SignalingConnector(
       signal_strategy.get(), dns_blackhole_checker.Pass(),
+      oauth_token_getter.Pass(),
       base::Bind(&Listener::OnAuthFailed, base::Unretained(listener))));
 
-  if (!oauth_credentials->refresh_token.empty()) {
-    scoped_ptr<OAuthTokenGetter> oauth_token_getter(new OAuthTokenGetter(
-        oauth_credentials.Pass(), url_request_context_getter, false));
-
-    signaling_connector->EnableOAuth(oauth_token_getter.Pass());
-  }
-
   scoped_ptr<HeartbeatSender> heartbeat_sender(new HeartbeatSender(
       base::Bind(&Listener::OnHeartbeatSuccessful, base::Unretained(listener)),
       base::Bind(&Listener::OnUnknownHostIdError, base::Unretained(listener)),
diff --git a/remoting/host/it2me/it2me_native_messaging_host.cc b/remoting/host/it2me/it2me_native_messaging_host.cc
index 148dc01..7af2db74 100644
--- a/remoting/host/it2me/it2me_native_messaging_host.cc
+++ b/remoting/host/it2me/it2me_native_messaging_host.cc
@@ -12,13 +12,13 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringize_macros.h"
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "media/base/media.h"
 #include "net/base/net_util.h"
 #include "net/url_request/url_request_context_getter.h"
-#include "remoting/base/auth_token_util.h"
 #include "remoting/base/service_urls.h"
 #include "remoting/host/chromoting_host_context.h"
 #include "remoting/host/host_exit_codes.h"
@@ -164,16 +164,19 @@
     return;
   }
 
-  ParseAuthTokenWithService(auth_service_with_token,
-                            &xmpp_config.auth_token,
-                            &xmpp_config.auth_service);
-  if (xmpp_config.auth_token.empty()) {
-    SendErrorAndExit(
-        response.Pass(),
-        "Invalid 'authServiceWithToken': " + auth_service_with_token);
+  // For backward compatibility the webapp still passes OAuth service as part of
+  // the authServiceWithToken field. But auth service part is always expected to
+  // be set to oauth2.
+  const char kOAuth2ServicePrefix[] = "oauth2:";
+  if (!StartsWithASCII(auth_service_with_token, kOAuth2ServicePrefix, true)) {
+    SendErrorAndExit(response.Pass(), "Invalid 'authServiceWithToken': " +
+                                          auth_service_with_token);
     return;
   }
 
+  xmpp_config.auth_token =
+      auth_service_with_token.substr(strlen(kOAuth2ServicePrefix));
+
 #if !defined(NDEBUG)
   std::string address;
   if (!message.GetString("xmppServerAddress", &address)) {
diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc
index 8cf6cce..51331685 100644
--- a/remoting/host/remoting_me2me_host.cc
+++ b/remoting/host/remoting_me2me_host.cc
@@ -947,29 +947,13 @@
     return false;
   }
 
-  // Use an XMPP connection to the Talk network for session signalling.
+  // Use an XMPP connection to the Talk network for session signaling.
   if (!config.GetString(kXmppLoginConfigPath, &xmpp_server_config_.username) ||
-      !(config.GetString(kXmppAuthTokenConfigPath,
-                         &xmpp_server_config_.auth_token) ||
-        config.GetString(kOAuthRefreshTokenConfigPath,
-                         &oauth_refresh_token_))) {
+      !config.GetString(kOAuthRefreshTokenConfigPath, &oauth_refresh_token_)) {
     LOG(ERROR) << "XMPP credentials are not defined in the config.";
     return false;
   }
 
-  if (!oauth_refresh_token_.empty()) {
-    // SignalingConnector (inside HostSignalingManager) is responsible for
-    // getting OAuth token.
-    xmpp_server_config_.auth_token = "";
-    xmpp_server_config_.auth_service = "oauth2";
-  } else if (!config.GetString(kXmppAuthServiceConfigPath,
-                               &xmpp_server_config_.auth_service)) {
-    // For the me2me host, we default to ClientLogin token for chromiumsync
-    // because earlier versions of the host had no HTTP stack with which to
-    // request an OAuth2 access token.
-    xmpp_server_config_.auth_service = kChromotingTokenDefaultServiceName;
-  }
-
   if (config.GetString(kHostOwnerConfigPath, &host_owner_)) {
     // Service account configs have a host_owner, different from the xmpp_login.
     use_service_account_ = true;
diff --git a/remoting/host/signaling_connector.cc b/remoting/host/signaling_connector.cc
index adc1571..7359e154 100644
--- a/remoting/host/signaling_connector.cc
+++ b/remoting/host/signaling_connector.cc
@@ -26,10 +26,12 @@
 SignalingConnector::SignalingConnector(
     XmppSignalStrategy* signal_strategy,
     scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,
+    scoped_ptr<OAuthTokenGetter> oauth_token_getter,
     const base::Closure& auth_failed_callback)
     : signal_strategy_(signal_strategy),
       auth_failed_callback_(auth_failed_callback),
       dns_blackhole_checker_(dns_blackhole_checker.Pass()),
+      oauth_token_getter_(oauth_token_getter.Pass()),
       reconnect_attempts_(0) {
   DCHECK(!auth_failed_callback_.is_null());
   DCHECK(dns_blackhole_checker_.get());
@@ -45,11 +47,6 @@
   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
 }
 
-void SignalingConnector::EnableOAuth(
-    scoped_ptr<OAuthTokenGetter> oauth_token_getter) {
-  oauth_token_getter_ = oauth_token_getter.Pass();
-}
-
 void SignalingConnector::OnSignalStrategyStateChange(
     SignalStrategy::State state) {
   DCHECK(CalledOnValidThread());
@@ -110,7 +107,7 @@
   DCHECK_EQ(status, OAuthTokenGetter::SUCCESS);
   HOST_LOG << "Received user info.";
 
-  signal_strategy_->SetAuthInfo(user_email, access_token, "oauth2");
+  signal_strategy_->SetAuthInfo(user_email, access_token);
 
   // Now that we've refreshed the token and verified that it's for the correct
   // user account, try to connect using the new token.
diff --git a/remoting/host/signaling_connector.h b/remoting/host/signaling_connector.h
index acb6921..8a59e903 100644
--- a/remoting/host/signaling_connector.h
+++ b/remoting/host/signaling_connector.h
@@ -34,13 +34,10 @@
   SignalingConnector(
       XmppSignalStrategy* signal_strategy,
       scoped_ptr<DnsBlackholeChecker> dns_blackhole_checker,
+      scoped_ptr<OAuthTokenGetter> oauth_token_getter,
       const base::Closure& auth_failed_callback);
   ~SignalingConnector() override;
 
-  // May be called immediately after the constructor to enable OAuth
-  // access token updating.
-  void EnableOAuth(scoped_ptr<OAuthTokenGetter> oauth_token_getter);
-
   // OAuthTokenGetter callback.
   void OnAccessToken(OAuthTokenGetter::Status status,
                      const std::string& user_email,
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 0f40d356..a0da127b 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -4,27 +4,6 @@
 
 {
   'variables': {
-    'chromium_code': 1,
-
-    # Set this to run the jscompile checks after building the webapp.
-    'run_jscompile%': 1,
-
-    # Set this to enable cast mode on the android client.
-    'enable_cast%': 0,
-
-    'variables': {
-      'conditions': [
-        # Enable the multi-process host on Windows by default.
-        ['OS=="win"', {
-          'remoting_multi_process%': 1,
-        }, {
-          'remoting_multi_process%': 0,
-        }],
-      ],
-    },
-
-    'remoting_multi_process%': '<(remoting_multi_process)',
-    'remoting_rdp_session%': 1,
 
     'branding_path': '../remoting/branding_<(branding)',
 
@@ -44,11 +23,6 @@
             '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'655bd819-c08c-4b04-80c2-f160739ff6ef\'), \'<(version_full)\')")',
         'rdp_desktop_session_clsid':
             '<!(python -c "import uuid; print uuid.uuid5(uuid.UUID(\'6a7699f0-ee43-43e7-aa30-a6738f9bd470\'), \'<(version_full)\')")',
-
-        # Java is not available on Windows bots, so we need to disable
-        # JScompile checks.
-        'run_jscompile': 0,
-
       }],
     ],
   },
@@ -61,6 +35,7 @@
     'remoting_host_srcs.gypi',
     'remoting_key_tester.gypi',
     'remoting_locales.gypi',
+    'remoting_options.gypi',
     'remoting_srcs.gypi',
     'remoting_test.gypi',
     'remoting_version.gypi',
diff --git a/remoting/remoting_host.gypi b/remoting/remoting_host.gypi
index e818a971..33d1e4a 100644
--- a/remoting/remoting_host.gypi
+++ b/remoting/remoting_host.gypi
@@ -75,11 +75,6 @@
                   ],
                 }]
               ],
-              'link_settings': {
-                'libraries': [
-                  '-lpam',
-                ],
-              },
             }],
             ['chromeos==1', {
               'dependencies' : [
@@ -102,7 +97,6 @@
                 'host/linux/x_server_clipboard.cc',
                 'host/linux/x_server_clipboard.h',
                 'host/local_input_monitor_x11.cc',
-                'host/remoting_me2me_host.cc',
               ],
               'conditions': [
                 ['use_ash==1', {
@@ -144,7 +138,6 @@
               'link_settings': {
                 'libraries': [
                   '$(SDKROOT)/System/Library/Frameworks/OpenGL.framework',
-                  'libpam.a',
                ],
               },
             }],
@@ -420,6 +413,8 @@
           'dependencies': [
             '../base/base.gyp:base',
             '../base/base.gyp:base_i18n',
+            '../components/components.gyp:policy',
+            '../components/components.gyp:policy_component_common',
             '../net/net.gyp:net',
             '../third_party/webrtc/modules/modules.gyp:desktop_capture',
             'remoting_base',
@@ -435,14 +430,26 @@
             'host/curtain_mode_linux.cc',
             'host/curtain_mode_mac.cc',
             'host/curtain_mode_win.cc',
+            'host/pam_authorization_factory_posix.cc',
+            'host/pam_authorization_factory_posix.h',
             'host/posix/signal_handler.cc',
             'host/posix/signal_handler.h',
+            'host/remoting_me2me_host.cc',
           ],
           'conditions': [
-            ['os_posix != 1', {
-              'sources/': [
-                ['exclude', '^host/posix/'],
-              ],
+            ['OS=="linux"', {
+              'link_settings': {
+                'libraries': [
+                  '-lpam',
+                ],
+              },
+            }],
+            ['OS=="mac"', {
+              'link_settings': {
+                'libraries': [
+                  'libpam.a',
+               ],
+              },
             }],
           ],  # end of 'conditions'
         },  # end of target 'remoting_me2me_host_static'
diff --git a/remoting/remoting_host_linux.gypi b/remoting/remoting_host_linux.gypi
index 5ef7418..f9b89ea 100644
--- a/remoting/remoting_host_linux.gypi
+++ b/remoting/remoting_host_linux.gypi
@@ -41,6 +41,18 @@
               ],
               'action': [ 'zip', '-j', '-0', '<@(_outputs)', '<@(_inputs)' ],
             },
+            {
+              # Copy the debian package file, which has version info in it,
+              # to a consistent filename for use on Chromoting swarming bots.
+              'action_name': 'Copy debian package.',
+              'inputs': [
+                '<@(deb_filename)',
+              ],
+              'outputs': [
+                '<(PRODUCT_DIR)/remoting-me2me-host.deb',
+              ],
+              'action': [ 'cp', '<@(_inputs)', '<@(_outputs)'],
+            },
           ],
         }, {
           'target_name': 'remoting_me2me_host_deb_installer',
diff --git a/remoting/remoting_host_srcs.gypi b/remoting/remoting_host_srcs.gypi
index fbdfc71..9c99640 100644
--- a/remoting/remoting_host_srcs.gypi
+++ b/remoting/remoting_host_srcs.gypi
@@ -187,8 +187,6 @@
       'host/pairing_registry_delegate_mac.cc',
       'host/pairing_registry_delegate_win.cc',
       'host/pairing_registry_delegate_win.h',
-      'host/pam_authorization_factory_posix.cc',
-      'host/pam_authorization_factory_posix.h',
       'host/pin_hash.cc',
       'host/pin_hash.h',
       'host/policy_watcher.cc',
@@ -197,7 +195,6 @@
       'host/register_support_host_request.h',
       'host/remote_input_filter.cc',
       'host/remote_input_filter.h',
-      'host/remoting_me2me_host.cc',
       'host/resizing_host_observer.cc',
       'host/resizing_host_observer.h',
       'host/sas_injector.h',
diff --git a/remoting/remoting_key_tester.gypi b/remoting/remoting_key_tester.gypi
index d85a321..68db9b0 100644
--- a/remoting/remoting_key_tester.gypi
+++ b/remoting/remoting_key_tester.gypi
@@ -55,7 +55,8 @@
                   'action_name': 'jscompile remoting_key_tester',
                   'inputs': [
                     '<@(remoting_key_tester_js_files)',
-                    'webapp/js_proto/chrome_proto.js'
+                    'webapp/js_proto/chrome_proto.js',
+                    'webapp/js_proto/chrome_event_proto.js',
                   ],
                   'outputs': [
                     '<(success_stamp)',
@@ -66,7 +67,8 @@
                     '--no-single-file',
                     '--success-stamp', '<(success_stamp)',
                     '<@(remoting_key_tester_js_files)',
-                    'webapp/js_proto/chrome_proto.js'
+                    'webapp/js_proto/chrome_proto.js',
+                    'webapp/js_proto/chrome_event_proto.js',
                   ],
                 },
               ],  # actions
diff --git a/remoting/remoting_options.gypi b/remoting/remoting_options.gypi
new file mode 100644
index 0000000..56d339e
--- /dev/null
+++ b/remoting/remoting_options.gypi
@@ -0,0 +1,40 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'variables': {
+    'chromium_code': 1,
+
+    # Set this to run the jscompile checks after building the webapp.
+    'run_jscompile%': 1,
+
+    # Set this to enable cast mode on the android client.
+    'enable_cast%': 0,
+
+    'variables': {
+      'conditions': [
+        # Enable the multi-process host on Windows by default.
+        ['OS=="win"', {
+          'remoting_multi_process%': 1,
+        }, {
+          'remoting_multi_process%': 0,
+        }],
+      ],
+    },
+    'remoting_multi_process%': '<(remoting_multi_process)',
+
+    'remoting_rdp_session%': 1,
+
+    'branding_path': '../remoting/branding_<(branding)',
+
+    'conditions': [
+      ['OS=="win"', {
+        # Java is not available on Windows bots, so we need to disable
+        # JScompile checks.
+        'run_jscompile': 0,
+      }],
+    ],
+  },
+
+}
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi
index df1fbc7..4093c8e 100644
--- a/remoting/remoting_srcs.gypi
+++ b/remoting/remoting_srcs.gypi
@@ -5,8 +5,6 @@
 {
   'variables': {
     'remoting_base_sources': [
-      'base/auth_token_util.cc',
-      'base/auth_token_util.h',
       'base/auto_thread.cc',
       'base/auto_thread.h',
       'base/auto_thread_task_runner.cc',
diff --git a/remoting/remoting_test.gypi b/remoting/remoting_test.gypi
index 7d3c50b..2c34855 100644
--- a/remoting/remoting_test.gypi
+++ b/remoting/remoting_test.gypi
@@ -107,7 +107,6 @@
         '../testing/gmock/include',
       ],
       'sources': [
-        'base/auth_token_util_unittest.cc',
         'base/auto_thread_task_runner_unittest.cc',
         'base/auto_thread_unittest.cc',
         'base/breakpad_win_unittest.cc',
diff --git a/remoting/remoting_webapp.gypi b/remoting/remoting_webapp.gypi
index 7d72c67..e7b00fd 100644
--- a/remoting/remoting_webapp.gypi
+++ b/remoting/remoting_webapp.gypi
@@ -24,6 +24,7 @@
       'variables': {
         'success_stamp': '<(PRODUCT_DIR)/<(_target_name)_jscompile.stamp',
         'success_stamp_bt': '<(PRODUCT_DIR)/<(_target_name)_bt_jscompile.stamp',
+        'success_stamp_ut': '<(PRODUCT_DIR)/<(_target_name)_ut_jscompile.stamp',
       },
       'actions': [
         {
@@ -49,7 +50,7 @@
           'inputs': [
             '<@(remoting_webapp_crd_js_files)',
             '<@(remoting_webapp_browsertest_all_js_files)',
-            '<@(remoting_webapp_js_proto_files)',
+            '<@(remoting_webapp_browsertest_js_proto_files)',
           ],
           'outputs': [
             '<(success_stamp_bt)',
@@ -61,7 +62,27 @@
             '--success-stamp', '<(success_stamp_bt)',
             '<@(remoting_webapp_crd_js_files)',
             '<@(remoting_webapp_browsertest_all_js_files)',
-            '<@(remoting_webapp_js_proto_files)',
+            '<@(remoting_webapp_browsertest_js_proto_files)',
+          ],
+        },
+        {
+          'action_name': 'Verify remoting webapp unittests',
+          'inputs': [
+            '<@(remoting_webapp_crd_js_files)',
+            '<@(remoting_webapp_unittest_all_js_files)',
+            '<@(remoting_webapp_unittest_js_proto_files)',
+          ],
+          'outputs': [
+            '<(success_stamp_ut)',
+          ],
+          'action': [
+            'python', '../third_party/closure_compiler/checker.py',
+            '--strict',
+            '--no-single-file',
+            '--success-stamp', '<(success_stamp_ut)',
+            '<@(remoting_webapp_crd_js_files)',
+            '<@(remoting_webapp_unittest_all_js_files)',
+            '<@(remoting_webapp_unittest_js_proto_files)',
           ],
         },
       ],  # actions
diff --git a/remoting/remoting_webapp_files.gypi b/remoting/remoting_webapp_files.gypi
index 129f198b..ad13a552 100644
--- a/remoting/remoting_webapp_files.gypi
+++ b/remoting/remoting_webapp_files.gypi
@@ -14,19 +14,16 @@
     # These provide type information for jscompile.
     'remoting_webapp_js_proto_files': [
       'webapp/js_proto/chrome_proto.js',
+      'webapp/js_proto/chrome_cast_proto.js',
+      'webapp/js_proto/chrome_event_proto.js',
       'webapp/js_proto/dom_proto.js',
       'webapp/js_proto/remoting_proto.js',
-      'webapp/js_proto/test_proto.js',
     ],
 
     #
-    # Webapp browsertest and unittest JavaScript files.
+    # Webapp browsertest JavaScript files.
     #
 
-    # Shared files for tests.
-    'remoting_webapp_test_js_common_files': [
-      'webapp/unittests/mock_signal_strategy.js',
-    ],
     # Browser test files.
     'remoting_webapp_browsertest_js_files': [
       'webapp/browser_test/browser_test.js',
@@ -34,21 +31,34 @@
       'webapp/browser_test/cancel_pin_browser_test.js',
       'webapp/browser_test/invalid_pin_browser_test.js',
       'webapp/browser_test/it2me_browser_test.js',
-      'webapp/browser_test/mock_client_plugin.js',
-      'webapp/browser_test/mock_host_list_api.js',
-      'webapp/browser_test/mock_identity.js',
-      'webapp/browser_test/mock_oauth2_api.js',
-      'webapp/browser_test/mock_session_connector.js',
       'webapp/browser_test/scrollbar_browser_test.js',
       'webapp/browser_test/timeout_waiter.js',
       'webapp/browser_test/unauthenticated_browser_test.js',
       'webapp/browser_test/update_pin_browser_test.js',
     ],
+    # Browser test files.
+    'remoting_webapp_browsertest_js_mock_files': [
+      'webapp/browser_test/mock_client_plugin.js',
+      'webapp/browser_test/mock_host_list_api.js',
+      'webapp/browser_test/mock_identity.js',
+      'webapp/browser_test/mock_oauth2_api.js',
+      'webapp/browser_test/mock_session_connector.js',
+      'webapp/unittests/mock_signal_strategy.js',
+    ],
+    'remoting_webapp_browsertest_js_proto_files': [
+      'webapp/js_proto/sinon_proto.js',
+      'webapp/js_proto/test_proto.js',
+      '<@(remoting_webapp_js_proto_files)',
+    ],
     'remoting_webapp_browsertest_all_js_files': [
       '<@(remoting_webapp_browsertest_js_files)',
-      '<@(remoting_webapp_test_js_common_files)',
+      '<@(remoting_webapp_browsertest_js_mock_files)',
     ],
 
+    #
+    # Webapp unittest JavaScript files.
+    #
+
     # These product files are excluded from our JavaScript unittest
     'remoting_webapp_unittest_exclude_js_files': [
       # background.js is where the onLoad handler is defined, which
@@ -57,8 +67,6 @@
     ],
     # The unit test cases for the webapp
     'remoting_webapp_unittest_js_files': [
-      'webapp/unittests/chrome_mocks.js',
-      'webapp/js_proto/chrome_proto.js',
       'webapp/unittests/apps_v2_migration_unittest.js',
       'webapp/unittests/base_unittest.js',
       'webapp/unittests/desktop_viewport_unittest.js',
@@ -76,10 +84,29 @@
       'webapp/unittests/xmpp_login_handler_unittest.js',
       'webapp/unittests/xmpp_stream_parser_unittest.js',
     ],
+    'remoting_webapp_unittest_js_mock_files': [
+      # Some proto files can be repurposed as simple mocks for the unittests.
+      # Note that some defs in chrome_proto are overwritten by chrome_mocks.
+      'webapp/js_proto/chrome_proto.js',
+      'webapp/unittests/chrome_mocks.js',
+      'webapp/unittests/mock_signal_strategy.js',
+      'webapp/unittests/sinon_helpers.js',
+      'webapp/unittests/test_start.js',
+    ],
+    # Prototypes for objects that are not mocked.
+    'remoting_webapp_unittest_js_proto_files': [
+      'webapp/js_proto/chrome_cast_proto.js',
+      'webapp/js_proto/dom_proto.js',
+      'webapp/js_proto/remoting_proto.js',
+      'webapp/js_proto/qunit_proto.js',
+      'webapp/js_proto/sinon_proto.js',
+      'webapp/js_proto/sinon_stub_proto.js',
+    ],
     'remoting_webapp_unittest_all_js_files': [
       '<@(remoting_webapp_unittest_js_files)',
-      '<@(remoting_webapp_test_js_common_files)',
+      '<@(remoting_webapp_unittest_js_mock_files)',
     ],
+    # All the files needed to run the unittests.
     'remoting_webapp_unittest_all_files': [
       'webapp/crd/html/menu_button.css',
       '<@(remoting_webapp_unittest_all_js_files)',
@@ -127,6 +154,7 @@
       'webapp/crd/js/client_screen.js',
       'webapp/crd/js/client_session.js',
       'webapp/crd/js/clipboard.js',
+      'webapp/crd/js/credentials_provider.js',
       'webapp/crd/js/desktop_connected_view.js',
       'webapp/crd/js/hangout_session.js',
       'webapp/crd/js/host_desktop.js',
diff --git a/remoting/signaling/xmpp_signal_strategy.cc b/remoting/signaling/xmpp_signal_strategy.cc
index 806852e..5ad0c03 100644
--- a/remoting/signaling/xmpp_signal_strategy.cc
+++ b/remoting/signaling/xmpp_signal_strategy.cc
@@ -83,7 +83,7 @@
   settings.set_user(login_jid.node());
   settings.set_host(login_jid.domain());
   settings.set_resource(resource_name_);
-  settings.set_token_service(xmpp_server_config_.auth_service);
+  settings.set_token_service("oauth2");
   settings.set_auth_token(buzz::AUTH_MECHANISM_GOOGLE_TOKEN,
                           xmpp_server_config_.auth_token);
 
@@ -203,12 +203,10 @@
 }
 
 void XmppSignalStrategy::SetAuthInfo(const std::string& username,
-                                     const std::string& auth_token,
-                                     const std::string& auth_service) {
+                                     const std::string& auth_token) {
   DCHECK(CalledOnValidThread());
   xmpp_server_config_.username = username;
   xmpp_server_config_.auth_token = auth_token;
-  xmpp_server_config_.auth_service = auth_service;
 }
 
 void XmppSignalStrategy::SetResourceName(const std::string &resource_name) {
@@ -269,13 +267,8 @@
 buzz::PreXmppAuth* XmppSignalStrategy::CreatePreXmppAuth(
     const buzz::XmppClientSettings& settings) {
   buzz::Jid jid(settings.user(), settings.host(), buzz::STR_EMPTY);
-  std::string mechanism = notifier::kDefaultGaiaAuthMechanism;
-  if (settings.token_service() == "oauth2") {
-    mechanism = "X-OAUTH2";
-  }
-
   return new notifier::GaiaTokenPreXmppAuth(
-      jid.Str(), settings.auth_token(), settings.token_service(), mechanism);
+      jid.Str(), settings.auth_token(), settings.token_service(), "X-OAUTH2");
 }
 
 }  // namespace remoting
diff --git a/remoting/signaling/xmpp_signal_strategy.h b/remoting/signaling/xmpp_signal_strategy.h
index 18ae841..2d8268b786 100644
--- a/remoting/signaling/xmpp_signal_strategy.h
+++ b/remoting/signaling/xmpp_signal_strategy.h
@@ -50,7 +50,6 @@
 
     std::string username;
     std::string auth_token;
-    std::string auth_service;
   };
 
   XmppSignalStrategy(
@@ -77,8 +76,7 @@
   // access token is renewed). It is OK to call this even when we are in the
   // CONNECTED state. It will be used on the next Connect() call.
   void SetAuthInfo(const std::string& username,
-                   const std::string& auth_token,
-                   const std::string& auth_service);
+                   const std::string& auth_token);
 
   // Use this method to override the default resource name used (optional).
   // This will be used on the next Connect() call.
diff --git a/remoting/webapp/app_remoting/html/ar_main.css b/remoting/webapp/app_remoting/html/ar_main.css
new file mode 100644
index 0000000..56cd979
--- /dev/null
+++ b/remoting/webapp/app_remoting/html/ar_main.css
@@ -0,0 +1,8 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+html {
+  background-image: radial-gradient(#444, #111);
+}
\ No newline at end of file
diff --git a/remoting/webapp/app_remoting/html/feedback_consent.html b/remoting/webapp/app_remoting/html/template_feedback_consent.html
similarity index 89%
rename from remoting/webapp/app_remoting/html/feedback_consent.html
rename to remoting/webapp/app_remoting/html/template_feedback_consent.html
index adaf745f8..a0cb8da 100644
--- a/remoting/webapp/app_remoting/html/feedback_consent.html
+++ b/remoting/webapp/app_remoting/html/template_feedback_consent.html
@@ -13,12 +13,9 @@
     <link rel="stylesheet" href="feedback_consent.css">
     <link rel="stylesheet" href="main.css">
     <link rel="stylesheet" href="message_window.css">
-    <script src="error.js"></script>
-    <script src="feedback_consent.js"></script>
-    <script src="oauth2_api_impl.js"></script>
-    <script src="plugin_settings.js"></script>
-    <script src="l10n.js"></script>
-    <script src="xhr.js"></script>
+
+    <meta-include type="javascript"/>
+
     <title i18n-content="FEEDBACK_CONSENT_TITLE"></title>
   </head>
   <body>
diff --git a/remoting/webapp/app_remoting/html/template_lg.html b/remoting/webapp/app_remoting/html/template_lg.html
index 9b666acfa..32bb369 100644
--- a/remoting/webapp/app_remoting/html/template_lg.html
+++ b/remoting/webapp/app_remoting/html/template_lg.html
@@ -9,11 +9,12 @@
   <head>
     <meta charset="utf-8">
     <link rel="icon" type="image/png" href="icon16.png">
-    <link rel="stylesheet" href="open_sans.css">
+    <link rel="stylesheet" href="ar_main.css">
     <link rel="stylesheet" href="connection_stats.css">
     <link rel="stylesheet" href="context_menu.css">
     <link rel="stylesheet" href="main.css">
     <link rel="stylesheet" href="menu_button.css">
+    <link rel="stylesheet" href="open_sans.css">
 
     <meta-include type="javascript"/>
 
diff --git a/remoting/webapp/app_remoting/js/app_remoting.js b/remoting/webapp/app_remoting/js/app_remoting.js
index 2aab7393..de4700a9 100644
--- a/remoting/webapp/app_remoting/js/app_remoting.js
+++ b/remoting/webapp/app_remoting/js/app_remoting.js
@@ -190,7 +190,7 @@
       method: 'POST',
       url: that.runApplicationUrl(),
       onDone: parseAppHostResponse,
-      oauthToken: token,
+      oauthToken: token
     });
   };
 
@@ -238,9 +238,12 @@
  * @return {void} Nothing.
  */
 remoting.AppRemoting.prototype.handleConnected = function(clientSession) {
-  remoting.clientSession.sendClientMessage(
-      'setUserDisplayInfo',
-      JSON.stringify({fullName: remoting.identity.getCachedUserFullName()}));
+  remoting.identity.getUserInfo().then(
+      function(userInfo) {
+        remoting.clientSession.sendClientMessage(
+            'setUserDisplayInfo',
+            JSON.stringify({fullName: userInfo.name}));
+      });
 
   // Set up a ping at 10-second intervals to test the connection speed.
   function ping() {
diff --git a/remoting/webapp/app_remoting/js/feedback_consent.js b/remoting/webapp/app_remoting/js/feedback_consent.js
index 6691ed2..f792376 100644
--- a/remoting/webapp/app_remoting/js/feedback_consent.js
+++ b/remoting/webapp/app_remoting/js/feedback_consent.js
@@ -15,7 +15,7 @@
  * @type {string} The network stats at the time the feedback consent dialog
  *     was shown.
  */
-var connectionStats = null;
+var connectionStats = '';
 
 /**
  * @type {string} "no" => user did not request a VM reset; "yes" => VM was
@@ -102,8 +102,8 @@
  */
 function generateId() {
   var idArray = new Uint8Array(20);
-  crypto.getRandomValues(idArray);
-  return btoa(String.fromCharCode.apply(null, idArray));
+  window.crypto.getRandomValues(idArray);
+  return window.btoa(String.fromCharCode.apply(null, idArray));
 }
 
 /**
@@ -123,10 +123,6 @@
         'abandonHost': 'true',
         'crashServiceReportId': crashServiceReportId
       };
-      var headers = {
-        'Authorization': 'OAuth ' + token,
-        'Content-type': 'application/json'
-      };
       var uri = remoting.settings.APP_REMOTING_API_BASE_URL +
           '/applications/' + remoting.settings.getAppRemotingApplicationId() +
           '/hosts/'  + hostId +
@@ -139,7 +135,13 @@
           showError();
         }
       };
-      remoting.xhr.post(uri, onDone, JSON.stringify(body), headers);
+      remoting.xhr.start({
+        method: 'POST',
+        url: uri,
+        onDone: onDone,
+        jsonContent: body,
+        oauthToken: token
+      });
     } else {
       getUserInfo();
     }
@@ -184,6 +186,7 @@
   }
 }
 
+/** @param {Event} event */
 function onLearnMore(event) {
   event.preventDefault();  // Clicking the link should not tick the checkbox.
   var learnMoreLink = document.getElementById('learn-more');
diff --git a/remoting/webapp/base/js/auth_init.js b/remoting/webapp/base/js/auth_init.js
index c67e454..009edd14 100644
--- a/remoting/webapp/base/js/auth_init.js
+++ b/remoting/webapp/base/js/auth_init.js
@@ -42,12 +42,14 @@
     }
   }
 
-  remoting.identity.getUserInfo().then(function(userInfo) {
-    onUserInfoAvailable(userInfo.email, userInfo.name);
-  }).catch(function(error) {
-    onGetIdentityInfoError(
-        /** @type {remoting.Error} */ (error));
-  });
+  remoting.identity.getUserInfo().then(
+      /** @param {{email:string, name:string}} userInfo */
+      function(userInfo) {
+        onUserInfoAvailable(userInfo.email, userInfo.name);
+      }).catch(function(error) {
+        onGetIdentityInfoError(
+            /** @type {remoting.Error} */ (error));
+      });
 };
 
 /**
@@ -64,4 +66,4 @@
       window.location.reload();
     }
   });
-};
\ No newline at end of file
+};
diff --git a/remoting/webapp/base/js/ipc.js b/remoting/webapp/base/js/ipc.js
index a940a28..955d150 100644
--- a/remoting/webapp/base/js/ipc.js
+++ b/remoting/webapp/base/js/ipc.js
@@ -89,7 +89,7 @@
 
 /**
  * @param {string} methodName
- * @param {function(...?)} handler The handler can be invoked by calling
+ * @param {Function} handler The handler can be invoked by calling
  *   base.Ipc.invoke(|methodName|, arg1, arg2, ...)
  * Async handlers that return promises are currently not supported.
  * @return {boolean} Whether the handler is successfully registered.
@@ -145,8 +145,8 @@
  *
  * @param {string} methodName
  * @param {...} var_args
- * @return A Promise that would resolve to the return value of the handler or
- *   reject if the handler throws an exception.
+ * @return {Promise} A Promise that would resolve to the return value of the
+ *   handler or reject if the handler throws an exception.
  */
 base.Ipc.invoke = function(methodName, var_args) {
   var params = Array.prototype.slice.call(arguments, 1);
diff --git a/remoting/webapp/browser_test/mock_client_plugin.js b/remoting/webapp/browser_test/mock_client_plugin.js
index 09858e0a1..8a8dafa 100644
--- a/remoting/webapp/browser_test/mock_client_plugin.js
+++ b/remoting/webapp/browser_test/mock_client_plugin.js
@@ -46,10 +46,9 @@
   window.setTimeout(onDone.bind(null, true), 0);
 };
 
-remoting.MockClientPlugin.prototype.connect = function(
-    hostJid, hostPublicKey, localJid, sharedSecret,
-    authenticationMethods, authenticationTag,
-    clientPairingId, clientPairedSecret) {
+
+remoting.MockClientPlugin.prototype.connect =
+    function(host, localJid, credentialsProvider) {
   base.debug.assert(this.connectionStatusUpdateHandler_ != null);
   window.setTimeout(
       this.connectionStatusUpdateHandler_.bind(
@@ -79,16 +78,9 @@
 remoting.MockClientPlugin.prototype.sendClipboardItem =
     function(mimeType, item) {};
 
-remoting.MockClientPlugin.prototype.useAsyncPinDialog = function() {};
-
 remoting.MockClientPlugin.prototype.requestPairing =
     function(clientName, onDone) {};
 
-remoting.MockClientPlugin.prototype.onPinFetched = function(pin) {};
-
-remoting.MockClientPlugin.prototype.onThirdPartyTokenFetched =
-    function(token, sharedSecret) {};
-
 remoting.MockClientPlugin.prototype.pauseAudio = function(pause) {};
 
 remoting.MockClientPlugin.prototype.pauseVideo = function(pause) {};
@@ -142,12 +134,6 @@
 remoting.MockClientPlugin.prototype.setMouseCursorHandler =
     function(handler) {};
 
-remoting.MockClientPlugin.prototype.setFetchThirdPartyTokenHandler =
-    function(handler) {};
-
-remoting.MockClientPlugin.prototype.setFetchPinHandler =
-    function(handler) {};
-
 /**
  * @constructor
  * @implements {remoting.HostDesktop}
diff --git a/remoting/webapp/crd/html/template_unittest.html b/remoting/webapp/crd/html/template_unittest.html
index eb99c5c2..cce27c7 100644
--- a/remoting/webapp/crd/html/template_unittest.html
+++ b/remoting/webapp/crd/html/template_unittest.html
@@ -22,6 +22,7 @@
     <script src="blanketjs/qunit_adapter.js"></script>
     <script src="sinonjs/sinon.js"></script>
     <script src="sinonjs/sinon-qunit.js"></script>
+    <script src="test_start.js"></script>
 
     <!-- product files and unit test files-->
     <meta-include type="javascript"/>
diff --git a/remoting/webapp/crd/js/apps_v2_migration.js b/remoting/webapp/crd/js/apps_v2_migration.js
index 3f49883f..aab9994 100644
--- a/remoting/webapp/crd/js/apps_v2_migration.js
+++ b/remoting/webapp/crd/js/apps_v2_migration.js
@@ -22,9 +22,9 @@
 var MIGRATION_KEY_ = 'remoting-v2-migration';
 
 /**
- * @constructor
  * @param {string} email
  * @param {string} fullName
+ * @constructor
  */
 remoting.MigrationSettings = function(email, fullName) {
   this.email = email;
@@ -88,16 +88,14 @@
   if (base.isAppsV2()) {
     chrome.storage.local.remove(MIGRATION_KEY_);
   } else {
-    /**
-     * @param {string} email
-     * @param {string} fullName
-     */
-    remoting.identity.getUserInfo().then(function(userInfo) {
-      var preference = {};
-      preference[MIGRATION_KEY_] =
-        new remoting.MigrationSettings(userInfo.email, userInfo.name);
-      chrome.storage.local.set(preference);
-    }).catch(base.doNothing);
+    remoting.identity.getUserInfo().then(
+        /** @param {{email:string, name:string}} userInfo */
+        function(userInfo) {
+          var preference = {};
+          preference[MIGRATION_KEY_] =
+              new remoting.MigrationSettings(userInfo.email, userInfo.name);
+          chrome.storage.local.set(preference);
+        }).catch(base.doNothing);
   }
 };
 
diff --git a/remoting/webapp/crd/js/client_plugin.js b/remoting/webapp/crd/js/client_plugin.js
index a7fdd34..cf4360d 100644
--- a/remoting/webapp/crd/js/client_plugin.js
+++ b/remoting/webapp/crd/js/client_plugin.js
@@ -34,25 +34,12 @@
 remoting.ClientPlugin.prototype.initialize = function(onDone) {};
 
 /**
- * @param {string} hostJid The jid of the host to connect to.
- * @param {string} hostPublicKey The base64 encoded version of the host's
- *     public key.
+ * @param {remoting.Host} host The host to connect to.
  * @param {string} localJid Local jid.
- * @param {string} sharedSecret The access code for IT2Me or the PIN
- *     for Me2Me.
- * @param {string} authenticationMethods Comma-separated list of
- *     authentication methods the client should attempt to use.
- * @param {string} authenticationTag A host-specific tag to mix into
- *     authentication hashes.
- * @param {string} clientPairingId For paired Me2Me connections, the
- *     pairing id for this client, as issued by the host.
- * @param {string} clientPairedSecret For paired Me2Me connections, the
- *     paired secret for this client, as issued by the host.
+ * @param {remoting.CredentialsProvider} credentialsProvider
  */
-remoting.ClientPlugin.prototype.connect = function(
-    hostJid, hostPublicKey, localJid, sharedSecret,
-    authenticationMethods, authenticationTag,
-    clientPairingId, clientPairedSecret) {};
+remoting.ClientPlugin.prototype.connect =
+    function(host, localJid, credentialsProvider) {};
 
 /**
  * @param {number} key The keycode to inject.
@@ -98,11 +85,6 @@
     function(mimeType, item) {};
 
 /**
- * Tell the plugin to request a PIN asynchronously.
- */
-remoting.ClientPlugin.prototype.useAsyncPinDialog = function() {};
-
-/**
  * Request that this client be paired with the current host.
  *
  * @param {string} clientName The human-readable name of the client.
@@ -113,27 +95,11 @@
     function(clientName, onDone) {};
 
 /**
- * Called when a PIN is obtained from the user.
- *
- * @param {string} pin The PIN.
- */
-remoting.ClientPlugin.prototype.onPinFetched = function(pin) {};
-
-/**
  * Allows automatic mouse-lock.
  */
 remoting.ClientPlugin.prototype.allowMouseLock = function() {};
 
 /**
- * Sets the third party authentication token and shared secret.
- *
- * @param {string} token The token received from the token URL.
- * @param {string} sharedSecret Shared secret received from the token URL.
- */
-remoting.ClientPlugin.prototype.onThirdPartyTokenFetched =
-    function(token, sharedSecret) {};
-
-/**
  * @param {boolean} pause True to pause the audio stream; false to resume it.
  */
 remoting.ClientPlugin.prototype.pauseAudio = function(pause) {};
@@ -223,23 +189,6 @@
     function(handler) {};
 
 /**
- * @param {function(string, string, string):void} handler Callback for
- *     fetching third-party tokens. The first parameter is the token URL; the
- *     second is the public key of the host; the third is the OAuth2 scope
- *     being requested.
- */
-remoting.ClientPlugin.prototype.setFetchThirdPartyTokenHandler =
-    function(handler) {};
-
-/**
- * @param {function(boolean):void} handler Callback for fetching a PIN from
- *     the user. The parameter is true if PIN pairing is supported by the
- *     host, or false otherwise.
- */
-remoting.ClientPlugin.prototype.setFetchPinHandler =
-    function(handler) {};
-
-/**
  * @param {function({rects:Array<Array<number>>}):void|null} handler Callback
  *     to receive dirty region information for each video frame, for debugging.
  */
diff --git a/remoting/webapp/crd/js/client_plugin_impl.js b/remoting/webapp/crd/js/client_plugin_impl.js
index 2d3efe0..45b95ba 100644
--- a/remoting/webapp/crd/js/client_plugin_impl.js
+++ b/remoting/webapp/crd/js/client_plugin_impl.js
@@ -77,22 +77,11 @@
    * @private
    */
   this.onConnectionReadyHandler_ = function(ready) {};
-
-  /**
-   * @param {string} tokenUrl Token-request URL, received from the host.
-   * @param {string} hostPublicKey Public key for the host.
-   * @param {string} scope OAuth scope to request the token for.
-   * @private
-   */
-  this.fetchThirdPartyTokenHandler_ = function(
-    tokenUrl, hostPublicKey, scope) {};
   /**
    * @param {!Array<string>} capabilities The negotiated capabilities.
    * @private
    */
   this.onSetCapabilitiesHandler_ = function (capabilities) {};
-  /** @private */
-  this.fetchPinHandler_ = function (supportsPairing) {};
   /**
    * @param {string} data Remote gnubbyd data.
    * @private
@@ -168,6 +157,9 @@
 
   this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl(
       this, this.postMessage_.bind(this));
+
+  /** @private {remoting.CredentialsProvider} */
+  this.credentials_ = null;
 };
 
 /**
@@ -282,21 +274,6 @@
 };
 
 /**
- * @param {function(string, string, string):void} handler
- */
-remoting.ClientPluginImpl.prototype.setFetchThirdPartyTokenHandler =
-    function(handler) {
-  this.fetchThirdPartyTokenHandler_ = handler;
-};
-
-/**
- * @param {function(boolean):void} handler
- */
-remoting.ClientPluginImpl.prototype.setFetchPinHandler = function(handler) {
-  this.fetchPinHandler_ = handler;
-};
-
-/**
  * @param {?function({rects:Array<Array<number>>}):void} handler
  */
 remoting.ClientPluginImpl.prototype.setDebugDirtyRegionHandler =
@@ -436,9 +413,10 @@
     // client and host support pairing. If the client doesn't support pairing,
     // then the value won't be there at all, so give it a default of false.
     var pairingSupported = getBooleanAttr(message.data, 'pairingSupported',
-                                          false)
-    this.fetchPinHandler_(pairingSupported);
-
+                                          false);
+    this.credentials_.getPIN(pairingSupported).then(
+        this.onPinFetched_.bind(this)
+    );
   } else if (message.method == 'setCapabilities') {
     /** @type {!Array<string>} */
     var capabilities = tokenize(getStringAttr(message.data, 'capabilities'));
@@ -448,8 +426,9 @@
     var tokenUrl = getStringAttr(message.data, 'tokenUrl');
     var hostPublicKey = getStringAttr(message.data, 'hostPublicKey');
     var scope = getStringAttr(message.data, 'scope');
-    this.fetchThirdPartyTokenHandler_(tokenUrl, hostPublicKey, scope);
-
+    this.credentials_.getThirdPartyToken(tokenUrl, hostPublicKey, scope).then(
+      this.onThirdPartyTokenFetched_.bind(this)
+    );
   } else if (message.method == 'pairingResponse') {
     var clientId = getStringAttr(message.data, 'clientId');
     var sharedSecret = getStringAttr(message.data, 'sharedSecret');
@@ -590,25 +569,12 @@
 };
 
 /**
- * @param {string} hostJid The jid of the host to connect to.
- * @param {string} hostPublicKey The base64 encoded version of the host's
- *     public key.
+ * @param {remoting.Host} host The host to connect to.
  * @param {string} localJid Local jid.
- * @param {string} sharedSecret The access code for IT2Me or the PIN
- *     for Me2Me.
- * @param {string} authenticationMethods Comma-separated list of
- *     authentication methods the client should attempt to use.
- * @param {string} authenticationTag A host-specific tag to mix into
- *     authentication hashes.
- * @param {string} clientPairingId For paired Me2Me connections, the
- *     pairing id for this client, as issued by the host.
- * @param {string} clientPairedSecret For paired Me2Me connections, the
- *     paired secret for this client, as issued by the host.
+ * @param {remoting.CredentialsProvider} credentialsProvider
  */
-remoting.ClientPluginImpl.prototype.connect = function(
-    hostJid, hostPublicKey, localJid, sharedSecret,
-    authenticationMethods, authenticationTag,
-    clientPairingId, clientPairedSecret) {
+remoting.ClientPluginImpl.prototype.connect =
+    function(host, localJid, credentialsProvider) {
   var keyFilter = '';
   if (remoting.platformIsMac()) {
     keyFilter = 'mac';
@@ -623,17 +589,20 @@
       parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 42;
   this.plugin_.postMessage(JSON.stringify(
       { method: 'delegateLargeCursors', data: {} }));
+  var methods = 'third_party,spake2_pair,spake2_hmac,spake2_plain';
+  this.credentials_ = credentialsProvider;
+  this.useAsyncPinDialog_();
   this.plugin_.postMessage(JSON.stringify(
     { method: 'connect', data: {
-        hostJid: hostJid,
-        hostPublicKey: hostPublicKey,
+        hostJid: host.jabberId,
+        hostPublicKey: host.publicKey,
         localJid: localJid,
-        sharedSecret: sharedSecret,
-        authenticationMethods: authenticationMethods,
-        authenticationTag: authenticationTag,
+        sharedSecret: '',
+        authenticationMethods: methods,
+        authenticationTag: host.hostId,
         capabilities: this.capabilities_.join(" "),
-        clientPairingId: clientPairingId,
-        clientPairedSecret: clientPairedSecret,
+        clientPairingId: credentialsProvider.getPairingInfo().id,
+        clientPairedSecret: credentialsProvider.getPairingInfo().secret,
         keyFilter: keyFilter,
         enableVideoDecodeRenderer: enableVideoDecodeRenderer
       }
@@ -790,8 +759,9 @@
  * Called when a PIN is obtained from the user.
  *
  * @param {string} pin The PIN.
+ * @private
  */
-remoting.ClientPluginImpl.prototype.onPinFetched =
+remoting.ClientPluginImpl.prototype.onPinFetched_ =
     function(pin) {
   if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
     return;
@@ -802,8 +772,9 @@
 
 /**
  * Tells the plugin to ask for the PIN asynchronously.
+ * @private
  */
-remoting.ClientPluginImpl.prototype.useAsyncPinDialog =
+remoting.ClientPluginImpl.prototype.useAsyncPinDialog_ =
     function() {
   if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) {
     return;
@@ -823,14 +794,14 @@
 /**
  * Sets the third party authentication token and shared secret.
  *
- * @param {string} token The token received from the token URL.
- * @param {string} sharedSecret Shared secret received from the token URL.
+ * @param {remoting.ThirdPartyToken} token
+ * @private
  */
-remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched = function(
-    token, sharedSecret) {
+remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched_ = function(
+    token) {
   this.plugin_.postMessage(JSON.stringify(
     { method: 'onThirdPartyTokenFetched',
-      data: { token: token, sharedSecret: sharedSecret}}));
+      data: { token: token.token, sharedSecret: token.secret}}));
 };
 
 /**
diff --git a/remoting/webapp/crd/js/client_session.js b/remoting/webapp/crd/js/client_session.js
index dc2a2a9..3d4753b 100644
--- a/remoting/webapp/crd/js/client_session.js
+++ b/remoting/webapp/crd/js/client_session.js
@@ -34,31 +34,17 @@
 /**
  * @param {remoting.Host} host The host to connect to.
  * @param {remoting.SignalStrategy} signalStrategy Signal strategy.
+ * @param {remoting.CredentialsProvider} credentialsProvider
+ *     The credentialsProvider to authenticate the client with the host.
  * @param {HTMLElement} container Container element for the client view.
- * @param {string} accessCode The IT2Me access code. Blank for Me2Me.
- * @param {function(boolean, function(string): void): void} fetchPin
- *     Called by Me2Me connections when a PIN needs to be obtained
- *     interactively.
- * @param {function(string, string, string,
- *                  function(string, string): void): void}
- *     fetchThirdPartyToken Called by Me2Me connections when a third party
- *     authentication token must be obtained.
- * @param {string} authenticationMethods Comma-separated list of
- *     authentication methods the client should attempt to use.
  * @param {remoting.DesktopConnectedView.Mode} mode The mode of this connection.
- * @param {string} clientPairingId For paired Me2Me connections, the
- *     pairing id for this client, as issued by the host.
- * @param {string} clientPairedSecret For paired Me2Me connections, the
- *     paired secret for this client, as issued by the host.
  * @param {string} defaultRemapKeys The default set of remap keys, to use
  *     when the client doesn't define any.
  * @constructor
  * @extends {base.EventSourceImpl}
  */
-remoting.ClientSession = function(host, signalStrategy, container, accessCode,
-                                  fetchPin, fetchThirdPartyToken,
-                                  authenticationMethods, mode, clientPairingId,
-                                  clientPairedSecret, defaultRemapKeys) {
+remoting.ClientSession = function(host, signalStrategy, credentialsProvider,
+                                  container, mode, defaultRemapKeys) {
   /** @private */
   this.state_ = remoting.ClientSession.State.CREATED;
 
@@ -67,18 +53,9 @@
 
   /** @private */
   this.host_ = host;
+
   /** @private */
-  this.accessCode_ = accessCode;
-  /** @private */
-  this.fetchPin_ = fetchPin;
-  /** @private */
-  this.fetchThirdPartyToken_ = fetchThirdPartyToken;
-  /** @private */
-  this.authenticationMethods_ = authenticationMethods;
-  /** @private */
-  this.clientPairingId_ = clientPairingId;
-  /** @private */
-  this.clientPairedSecret_ = clientPairedSecret;
+  this.credentialsProvider_ = credentialsProvider;
 
   /** @private */
   this.uiHandler_ = new remoting.DesktopConnectedView(
@@ -310,7 +287,8 @@
   plugin.setCastExtensionHandler(
       this.processCastExtensionMessage_.bind(this));
 
-  this.initiateConnection_();
+  this.plugin_.connect(
+      this.host_, this.signalStrategy_.getJid(), this.credentialsProvider_);
 };
 
 /**
@@ -321,7 +299,7 @@
   this.removePlugin();
   this.error_ = error;
   this.setState_(remoting.ClientSession.State.FAILED);
-}
+};
 
 /**
  * Deletes the <embed> element from the container, without sending a
@@ -460,64 +438,6 @@
 };
 
 /**
- * @private
- */
-remoting.ClientSession.prototype.initiateConnection_ = function() {
-  /** @type {remoting.ClientSession} */
-  var that = this;
-
-  /** @param {string} sharedSecret Shared secret. */
-  function onSharedSecretReceived(sharedSecret) {
-    that.plugin_.connect(that.host_.jabberId, that.host_.publicKey,
-                         that.signalStrategy_.getJid(), sharedSecret,
-                         that.authenticationMethods_, that.host_.hostId,
-                         that.clientPairingId_, that.clientPairedSecret_);
-  }
-
-  this.getSharedSecret_(onSharedSecretReceived);
-};
-
-/**
- * Gets shared secret to be used for connection.
- *
- * @param {function(string)} callback Callback called with the shared secret.
- * @return {void} Nothing.
- * @private
- */
-remoting.ClientSession.prototype.getSharedSecret_ = function(callback) {
-  /** @type remoting.ClientSession */
-  var that = this;
-  if (this.plugin_.hasFeature(remoting.ClientPlugin.Feature.THIRD_PARTY_AUTH)) {
-    /** @type{function(string, string, string): void} */
-    var fetchThirdPartyToken = function(tokenUrl, hostPublicKey, scope) {
-      that.fetchThirdPartyToken_(
-          tokenUrl, hostPublicKey, scope,
-          that.plugin_.onThirdPartyTokenFetched.bind(that.plugin_));
-    };
-    this.plugin_.setFetchThirdPartyTokenHandler(fetchThirdPartyToken);
-  }
-  if (this.accessCode_) {
-    // Shared secret was already supplied before connecting (It2Me case).
-    callback(this.accessCode_);
-  } else if (this.plugin_.hasFeature(
-      remoting.ClientPlugin.Feature.ASYNC_PIN)) {
-    // Plugin supports asynchronously asking for the PIN.
-    this.plugin_.useAsyncPinDialog();
-    /** @param {boolean} pairingSupported */
-    var fetchPin = function(pairingSupported) {
-      that.fetchPin_(pairingSupported,
-                     that.plugin_.onPinFetched.bind(that.plugin_));
-    };
-    this.plugin_.setFetchPinHandler(fetchPin);
-    callback('');
-  } else {
-    // Clients that don't support asking for a PIN asynchronously also don't
-    // support pairing, so request the PIN now without offering to remember it.
-    this.fetchPin_(false, callback);
-  }
-};
-
-/**
  * Callback that the plugin invokes to indicate that the connection
  * status has changed.
  *
diff --git a/remoting/webapp/crd/js/credentials_provider.js b/remoting/webapp/crd/js/credentials_provider.js
new file mode 100644
index 0000000..b1d9e20
--- /dev/null
+++ b/remoting/webapp/crd/js/credentials_provider.js
@@ -0,0 +1,100 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+var remoting = remoting || {};
+
+/** @typedef {{id: string, secret: string}} */
+remoting.PairingInfo;
+
+/** @typedef {{token: string, secret: string}} */
+remoting.ThirdPartyToken;
+
+/**
+ * Parameters for the remoting.CredentialsProvider constructor.
+ *
+ * fetchPin: Called by Me2Me connections when a PIN needs to be obtained
+ *     interactively.
+ *
+ * pairingInfo: The pairing info for Me2Me Connections.
+ *
+ * accessCode: It2Me access code. If present, the |fetchPin| callback will be
+ *     ignored.
+ *
+ * fetchThirdPartyToken: Called when a third party authentication token
+ *     is needed
+ *
+ * @typedef {{
+ *   accessCode: (string|undefined),
+ *   fetchPin: (function(boolean,function(string): void)|undefined),
+ *   pairingInfo: (remoting.PairingInfo|undefined),
+ *   fetchThirdPartyToken:
+ *      (function(string ,string , string,
+ *                function(string, string):void) | undefined)
+ * }}
+ */
+remoting.CredentialsProviderParams;
+
+/**
+ * @param {remoting.CredentialsProviderParams} args
+ * @constructor
+ */
+remoting.CredentialsProvider = function(args) {
+  /** @private */
+  this.fetchPin_ = (args.accessCode) ? this.getAccessCode_ : args.fetchPin;
+  /** @private */
+  this.pairingInfo_ = args.pairingInfo;
+  /** @private */
+  this.accessCode_ = args.accessCode;
+  /** @private */
+  this.fetchThirdPartyToken_ = args.fetchThirdPartyToken;
+};
+
+/** @returns {void}  */
+remoting.CredentialsProvider.prototype.getAccessCode_ = function(
+  /** boolean */ supportsPairing, /** Function */ callback) {
+  callback(this.accessCode_);
+};
+
+/** @returns {remoting.PairingInfo}  */
+remoting.CredentialsProvider.prototype.getPairingInfo = function() {
+  return this.pairingInfo_ || { id: '', secret: ''};
+};
+
+/**
+ * @param {boolean} pairingSupported Whether pairing is supported by the host.
+ * @returns {Promise<string>}
+ */
+remoting.CredentialsProvider.prototype.getPIN = function(pairingSupported) {
+  var that = this;
+  if (!this.fetchPin_) {
+    Promise.resolve('');
+  }
+  return new Promise(function(/** function(string) */ resolve) {
+    that.fetchPin_(pairingSupported, resolve);
+  });
+};
+
+/**
+ * @param {string} tokenUrl Token-issue URL received from the host.
+ * @param {string} hostPublicKey Host public key (DER and Base64 encoded).
+ * @param {string} scope OAuth scope to request the token for.
+ *
+ * @returns {Promise<remoting.ThirdPartyToken>}
+ */
+remoting.CredentialsProvider.prototype.getThirdPartyToken = function(
+    tokenUrl, hostPublicKey, scope) {
+  var that = this;
+  if (!this.fetchThirdPartyToken_) {
+    Promise.resolve({token: '', secret: ''});
+  }
+  return new Promise(function(/** Function */ resolve) {
+    var onTokenFetched = function(/** string */ token, /** string */ secret) {
+      resolve({token: token, secret: secret});
+    };
+    that.fetchThirdPartyToken_(tokenUrl, hostPublicKey, scope, onTokenFetched);
+  });
+};
+
diff --git a/remoting/webapp/crd/js/fallback_signal_strategy.js b/remoting/webapp/crd/js/fallback_signal_strategy.js
index 030bfb42..f250144 100644
--- a/remoting/webapp/crd/js/fallback_signal_strategy.js
+++ b/remoting/webapp/crd/js/fallback_signal_strategy.js
@@ -112,16 +112,10 @@
 
   /**
    * @type {Array<{strategyType: remoting.SignalStrategy.Type,
-                    progress: remoting.FallbackSignalStrategy.Progress,
-   *                elapsed: number}>}
+                    progress: remoting.FallbackSignalStrategy.Progress}>}
    */
   this.connectionSetupResults_ = [];
 
-  /**
-   * @type {number}
-   * @private
-   */
-  this.startTime_ = 0;
 };
 
 /**
@@ -178,7 +172,6 @@
   this.username_ = username;
   this.authToken_ = authToken;
   this.state_ = this.State.PRIMARY_PENDING;
-  this.startTime_ = new Date().getTime();
   this.primary_.setIncomingStanzaCallback(this.onIncomingStanzaCallback_);
   this.primary_.connect(server, username, authToken);
   this.primaryConnectTimerId_ =
@@ -211,8 +204,7 @@
   for (var i = 0; i < this.connectionSetupResults_.length; ++i) {
     var result = this.connectionSetupResults_[i];
     this.logToServer_.logSignalStrategyProgress(result.strategyType,
-                                                result.progress,
-                                                result.elapsed);
+                                                result.progress);
   }
   this.connectionSetupResults_ = [];
 };
@@ -391,8 +383,7 @@
       progress);
   this.connectionSetupResults_.push({
     'strategyType': strategy.getType(),
-    'progress': progress,
-    'elapsed': new Date().getTime() - this.startTime_
+    'progress': progress
   });
   if (this.logToServer_) {
     this.sendConnectionSetupResultsInternal_();
diff --git a/remoting/webapp/crd/js/host_controller.js b/remoting/webapp/crd/js/host_controller.js
index 4a37ee2..17e29edd 100644
--- a/remoting/webapp/crd/js/host_controller.js
+++ b/remoting/webapp/crd/js/host_controller.js
@@ -184,16 +184,18 @@
       private_key: privateKey
     };
     var hostOwner = clientBaseJid;
-    var hostOwnerEmail = remoting.identity.getCachedEmail();
-    if (hostOwner != xmppLogin) {
-      hostConfig['host_owner'] = hostOwner;
-      if (hostOwnerEmail != hostOwner) {
-        hostConfig['host_owner_email'] = hostOwnerEmail;
-      }
-    }
-    that.hostDaemonFacade_.startDaemon(
-        hostConfig, consent, onStarted.bind(null, hostName, publicKey),
-        onStartError);
+    remoting.identity.getEmail().then(
+        function(/** string */ hostOwnerEmail) {
+          if (hostOwner != xmppLogin) {
+            hostConfig['host_owner'] = hostOwner;
+            if (hostOwnerEmail != hostOwner) {
+              hostConfig['host_owner_email'] = hostOwnerEmail;
+            }
+          }
+          that.hostDaemonFacade_.startDaemon(
+              hostConfig, consent, onStarted.bind(null, hostName, publicKey),
+              onStartError);
+        });
   }
 
   /**
@@ -248,13 +250,14 @@
             onError);
       } else {
         // No authorization code returned, use regular user credential flow.
-        that.hostDaemonFacade_.getPinHash(
-            newHostId, hostPin, startHostWithHash.bind(
-                null, hostName, publicKey, privateKey,
-                remoting.identity.getCachedEmail(),
-                remoting.oauth2.getRefreshToken(),
-                remoting.identity.getCachedEmail()),
-          onError);
+        remoting.identity.getEmail().then(
+            function(/** string */ email) {
+              that.hostDaemonFacade_.getPinHash(
+                  newHostId, hostPin, startHostWithHash.bind(
+                      null, hostName, publicKey, privateKey,
+                      email, remoting.oauth2.getRefreshToken(), email),
+                  onError);
+            });
       }
     } else {
       console.log('Failed to register the host. Status: ' + xhr.status +
diff --git a/remoting/webapp/crd/js/host_screen.js b/remoting/webapp/crd/js/host_screen.js
index 183deb7f..cb3695d 100644
--- a/remoting/webapp/crd/js/host_screen.js
+++ b/remoting/webapp/crd/js/host_screen.js
@@ -94,10 +94,12 @@
 
   base.debug.assert(hostSession_ === null);
   hostSession_ = new remoting.HostSession();
-  var email = /** @type {string} */ (remoting.identity.getCachedEmail());
-  hostSession_.connect(
-      hostFacade, email, token, onHostStateChanged_,
-      onNatTraversalPolicyChanged_, logDebugInfo_, it2meConnectFailed_);
+  remoting.identity.getEmail().then(
+      function(/** string */ email) {
+        hostSession_.connect(
+            hostFacade, email, token, onHostStateChanged_,
+            onNatTraversalPolicyChanged_, logDebugInfo_, it2meConnectFailed_);
+      });
 };
 
 /**
@@ -336,4 +338,4 @@
   }
 }
 
-})();
\ No newline at end of file
+})();
diff --git a/remoting/webapp/crd/js/identity.js b/remoting/webapp/crd/js/identity.js
index b2f2c5a3..dfa7f987 100644
--- a/remoting/webapp/crd/js/identity.js
+++ b/remoting/webapp/crd/js/identity.js
@@ -13,9 +13,6 @@
 var remoting = remoting || {};
 
 /**
- * TODO(jamiewalch): Remove remoting.OAuth2 from this type annotation when
- * the Apps v2 work is complete.
- *
  * @type {remoting.Identity}
  */
 remoting.identity = null;
@@ -163,29 +160,6 @@
 };
 
 /**
- * Gets the user's email address, or null if no successful call to
- * getUserInfo has been made.
- *
- * @return {?string} The cached email address, if available.
- */
-remoting.Identity.prototype.getCachedEmail = function() {
-  return this.email_;
-};
-
-/**
- * Gets the user's full name.
- *
- * This will return null if either:
- *   No successful call to getUserInfo has been made, or
- *   The webapp doesn't have permission to access this value.
- *
- * @return {?string} The cached user's full name, if available.
- */
-remoting.Identity.prototype.getCachedUserFullName = function() {
-  return this.fullName_;
-};
-
-/**
  * Callback for the getAuthToken API.
  *
  * @param {boolean} interactive The value of the "interactive" parameter to
diff --git a/remoting/webapp/crd/js/log_to_server.js b/remoting/webapp/crd/js/log_to_server.js
index 8b87f1b5c..d76b33f 100644
--- a/remoting/webapp/crd/js/log_to_server.js
+++ b/remoting/webapp/crd/js/log_to_server.js
@@ -25,7 +25,7 @@
   /** @private */
   this.sessionIdGenerationTime_ = 0;
   /** @private */
-  this.sessionStartTime_ = 0;
+  this.sessionStartTime_ = new Date().getTime();
   /** @private */
   this.signalStrategy_ = signalStrategy;
   /** @private */
@@ -60,12 +60,6 @@
 remoting.LogToServer.prototype.logClientSessionStateChange =
     function(state, connectionError) {
   this.maybeExpireSessionId_();
-  // Set the session start time if we haven't done so already.
-  if (remoting.LogToServer.isStartOfSession_(state)) {
-    if (this.sessionStartTime_ == 0) {
-      this.sessionStartTime_ = new Date().getTime();
-    }
-  }
   // Log the session state change.
   var entry = remoting.ServerLogEntry.makeClientSessionStateChange(
       state, connectionError, this.mode_);
@@ -73,15 +67,6 @@
   entry.addChromeVersionField();
   entry.addWebappVersionField();
   entry.addSessionIdField(this.sessionId_);
-  // Maybe clear the session start time, and log the session duration.
-  if (remoting.LogToServer.shouldAddDuration_(state) &&
-      (this.sessionStartTime_ != 0)) {
-    entry.addSessionDurationField(
-        (new Date().getTime() - this.sessionStartTime_) / 1000.0);
-    if (remoting.LogToServer.isEndOfSession_(state)) {
-      this.sessionStartTime_ = 0;
-    }
-  }
   this.log_(entry);
   // Don't accumulate connection statistics across state changes.
   this.logAccumulatedStatistics_();
@@ -104,13 +89,12 @@
 /**
  * @param {remoting.SignalStrategy.Type} strategyType
  * @param {remoting.FallbackSignalStrategy.Progress} progress
- * @param {number} elapsedTimeInMs
  */
 remoting.LogToServer.prototype.logSignalStrategyProgress =
-    function(strategyType, progress, elapsedTimeInMs) {
+    function(strategyType, progress) {
   this.maybeExpireSessionId_();
   var entry = remoting.ServerLogEntry.makeSignalStrategyProgress(
-      this.sessionId_, strategyType, progress, elapsedTimeInMs);
+      this.sessionId_, strategyType, progress);
   this.log_(entry);
 };
 
@@ -143,20 +127,6 @@
       (state == remoting.ClientSession.State.CONNECTION_CANCELED));
 };
 
-/**
- * Whether the duration should be added to the log entry for this state.
- *
- * @private
- * @param {remoting.ClientSession.State} state
- * @return {boolean}
- */
-remoting.LogToServer.shouldAddDuration_ = function(state) {
-  // Duration is added to log entries at the end of the session, as well as at
-  // some intermediate states where it is relevant (e.g. to determine how long
-  // it took for a session to become CONNECTED).
-  return (remoting.LogToServer.isEndOfSession_(state) ||
-      (state == remoting.ClientSession.State.CONNECTED));
-};
 
 /**
  * Logs connection statistics.
@@ -203,6 +173,10 @@
  * @param {remoting.ServerLogEntry} entry
  */
 remoting.LogToServer.prototype.log_ = function(entry) {
+  // Log the time taken to get to this point from the time this session started.
+  var elapsedTimeInMs = new Date().getTime() - this.sessionStartTime_;
+  entry.addElapsedTimeMs(elapsedTimeInMs);
+
   // Send the stanza to the debug log.
   console.log('Enqueueing log entry:');
   entry.toDebugLog(1);
diff --git a/remoting/webapp/crd/js/oauth2.js b/remoting/webapp/crd/js/oauth2.js
index 1074ed2..0ad1f7a7 100644
--- a/remoting/webapp/crd/js/oauth2.js
+++ b/remoting/webapp/crd/js/oauth2.js
@@ -23,7 +23,10 @@
 remoting.oauth2 = null;
 
 
-/** @constructor */
+/**
+ * @constructor
+ * @extends {remoting.Identity}
+ */
 remoting.OAuth2 = function() {
 };
 
@@ -445,31 +448,3 @@
         reject);
   });
 };
-
-/**
- * If the user's email address is cached, return it, otherwise return null.
- *
- * @return {?string} The email address, if it has been cached by a previous call
- *     to getEmail or getUserInfo, otherwise null.
- */
-remoting.OAuth2.prototype.getCachedEmail = function() {
-  var value = window.localStorage.getItem(this.KEY_EMAIL_);
-  if (typeof value == 'string') {
-    return value;
-  }
-  return null;
-};
-
-/**
- * If the user's full name is cached, return it, otherwise return null.
- *
- * @return {?string} The user's full name, if it has been cached by a previous
- * call to getUserInfo, otherwise null.
- */
-remoting.OAuth2.prototype.getCachedUserFullName = function() {
-  var value = window.localStorage.getItem(this.KEY_FULLNAME_);
-  if (typeof value == 'string') {
-    return value;
-  }
-  return null;
-};
diff --git a/remoting/webapp/crd/js/server_log_entry.js b/remoting/webapp/crd/js/server_log_entry.js
index 7d848aa5..02e6feb 100644
--- a/remoting/webapp/crd/js/server_log_entry.js
+++ b/remoting/webapp/crd/js/server_log_entry.js
@@ -47,8 +47,8 @@
 remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_ =
     'signal-strategy-progress';
 /** @private */
-remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_ =
-    'signal-strategy-elapsed-time';
+remoting.ServerLogEntry.KEY_ELAPSED_TIME_MS_ = 'elapsed-time';
+
 
 /**
  * @private
@@ -119,8 +119,6 @@
   }
 };
 
-/** @private */
-remoting.ServerLogEntry.KEY_SESSION_DURATION_ = 'session-duration';
 
 /** @private */
 remoting.ServerLogEntry.VALUE_EVENT_NAME_CONNECTION_STATISTICS_ =
@@ -242,17 +240,6 @@
 };
 
 /**
- * Adds a session duration to a log entry.
- *
- * @param {number} sessionDuration
- */
-remoting.ServerLogEntry.prototype.addSessionDurationField = function(
-    sessionDuration) {
-  this.set_(remoting.ServerLogEntry.KEY_SESSION_DURATION_,
-            sessionDuration.toString());
-};
-
-/**
  * Makes a log entry for a set of connection statistics.
  * Returns null if all the statistics were zero.
  *
@@ -357,11 +344,10 @@
  * @param {string} sessionId
  * @param {remoting.SignalStrategy.Type} strategyType
  * @param {remoting.FallbackSignalStrategy.Progress} progress
- * @param {number} elapsedTimeInMs
  * @return {remoting.ServerLogEntry}
  */
 remoting.ServerLogEntry.makeSignalStrategyProgress =
-    function(sessionId, strategyType, progress, elapsedTimeInMs) {
+    function(sessionId, strategyType, progress) {
   var entry = new remoting.ServerLogEntry();
   entry.set_(remoting.ServerLogEntry.KEY_ROLE_,
              remoting.ServerLogEntry.VALUE_ROLE_CLIENT_);
@@ -371,8 +357,6 @@
   entry.addSessionIdField(sessionId);
   entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_TYPE_, strategyType);
   entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_PROGRESS_, progress);
-  entry.set_(remoting.ServerLogEntry.KEY_SIGNAL_STRATEGY_ELAPSED_TIME_,
-             String(elapsedTimeInMs));
 
   return entry;
 };
@@ -467,6 +451,18 @@
 };
 
 /**
+ * Adds a field to this log entry specifying the elapsed time since the start of
+ * the session to the current session state.
+ * @param {number} elapsedTimeInMs
+ */
+remoting.ServerLogEntry.prototype.addElapsedTimeMs =
+    function(elapsedTimeInMs) {
+  this.set_(remoting.ServerLogEntry.KEY_ELAPSED_TIME_MS_,
+            String(elapsedTimeInMs));
+};
+
+
+/**
  * Adds a field specifying the browser version to this log entry.
  */
 remoting.ServerLogEntry.prototype.addChromeVersionField = function() {
diff --git a/remoting/webapp/crd/js/session_connector_impl.js b/remoting/webapp/crd/js/session_connector_impl.js
index a89fdd4f1..fdbd6f0 100644
--- a/remoting/webapp/crd/js/session_connector_impl.js
+++ b/remoting/webapp/crd/js/session_connector_impl.js
@@ -117,32 +117,6 @@
  */
 remoting.SessionConnectorImpl.prototype.reset = function() {
   /**
-   * For paired connections, the client id of this device, issued by the host.
-   *
-   * @type {string}
-   * @private
-   */
-  this.clientPairingId_ = '';
-
-  /**
-   * For paired connections, the paired secret for this device, issued by the
-   * host.
-   *
-   * @type {string}
-   * @private
-   */
-  this.clientPairedSecret_ = '';
-
-  /**
-   * String used to authenticate to the host on connection. For IT2Me, this is
-   * the access code; for Me2Me it is the PIN.
-   *
-   * @type {string}
-   * @private
-   */
-  this.passPhrase_ = '';
-
-  /**
    * @type {remoting.Host}
    * @private
    */
@@ -167,19 +141,10 @@
   this.pendingXhr_ = null;
 
   /**
-   * Function to interactively obtain the PIN from the user.
-   * @type {function(boolean, function(string):void):void}
+   * @type {remoting.CredentialsProvider}
    * @private
    */
-  this.fetchPin_ = function(onPinFetched) {};
-
-  /**
-   * @type {function(string, string, string,
-   *                 function(string, string):void): void}
-   * @private
-   */
-  this.fetchThirdPartyToken_ = function(
-      tokenUrl, hostPublicKey, scope, onThirdPartyTokenFetched) {};
+  this.credentialsProvider_ = null;
 };
 
 /**
@@ -191,10 +156,6 @@
  * @param {remoting.Host} host The Me2Me host to which to connect.
  * @param {function(boolean, function(string):void):void} fetchPin Function to
  *     interactively obtain the PIN from the user.
- * @param {function(string, string, string,
- *                  function(string, string): void): void}
- *     fetchThirdPartyToken Function to obtain a token from a third party
- *     authentication server.
  * @param {string} clientPairingId The client id issued by the host when
  *     this device was paired, if it is already paired.
  * @param {string} clientPairedSecret The shared secret issued by the host when
@@ -206,8 +167,12 @@
              clientPairingId, clientPairedSecret) {
   this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME;
   this.logHostOfflineErrors_ = false;
-  this.connectMe2MeInternal_(host, fetchPin, fetchThirdPartyToken,
-                             clientPairingId, clientPairedSecret);
+  var credentialsProvider = new remoting.CredentialsProvider({
+    fetchPin: fetchPin,
+    pairingInfo: { id: clientPairingId, secret: clientPairedSecret },
+    fetchThirdPartyToken: fetchThirdPartyToken
+  });
+  this.connectInternal_(host, credentialsProvider);
 };
 
 /**
@@ -222,8 +187,7 @@
 remoting.SessionConnectorImpl.prototype.retryConnectMe2Me = function(host) {
   this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME;
   this.logHostOfflineErrors_ = true;
-  this.connectMe2MeInternal_(host, this.fetchPin_, this.fetchThirdPartyToken_,
-                             this.clientPairingId_, this.clientPairedSecret_);
+  this.connectInternal_(host, this.credentialsProvider_);
 };
 
 /**
@@ -240,7 +204,10 @@
     function(host, fetchThirdPartyToken) {
   this.connectionMode_ = remoting.DesktopConnectedView.Mode.APP_REMOTING;
   this.logHostOfflineErrors_ = true;
-  this.connectMe2MeInternal_(host, function() {}, fetchThirdPartyToken, '', '');
+  var credentialsProvider = new remoting.CredentialsProvider({
+    fetchThirdPartyToken : fetchThirdPartyToken
+  });
+  this.connectInternal_(host, credentialsProvider);
 };
 
 /**
@@ -251,38 +218,26 @@
  */
 remoting.SessionConnectorImpl.prototype.updatePairingInfo =
     function(clientId, sharedSecret) {
-  this.clientPairingId_ = clientId;
-  this.clientPairedSecret_ = sharedSecret;
+  var pairingInfo = this.credentialsProvider_.getPairingInfo();
+  pairingInfo.id = clientId;
+  pairingInfo.secret = sharedSecret;
 };
 
 /**
- * Initiate a Me2Me connection.
+ * Initiates a connection.
  *
  * @param {remoting.Host} host the Host to connect to.
- * @param {function(boolean, function(string):void):void} fetchPin Function to
- *     interactively obtain the PIN from the user.
- * @param {function(string, string, string,
- *                  function(string, string): void): void}
- *     fetchThirdPartyToken Function to obtain a token from a third party
- *     authentication server.
- * @param {string} clientPairingId The client id issued by the host when
- *     this device was paired, if it is already paired.
- * @param {string} clientPairedSecret The shared secret issued by the host when
- *     this device was paired, if it is already paired.
+ * @param {remoting.CredentialsProvider} credentialsProvider
  * @return {void} Nothing.
  * @private
  */
-remoting.SessionConnectorImpl.prototype.connectMe2MeInternal_ =
-    function(host, fetchPin, fetchThirdPartyToken,
-             clientPairingId, clientPairedSecret) {
+remoting.SessionConnectorImpl.prototype.connectInternal_ =
+    function(host, credentialsProvider) {
   // Cancel any existing connect operation.
   this.cancel();
 
   this.host_ = host;
-  this.fetchPin_ = fetchPin;
-  this.fetchThirdPartyToken_ = fetchThirdPartyToken;
-  this.updatePairingInfo(clientPairingId, clientPairedSecret);
-
+  this.credentialsProvider_ = credentialsProvider;
   this.connectSignaling_();
 };
 
@@ -305,9 +260,10 @@
     this.onError_(remoting.Error.INVALID_ACCESS_CODE);
     return;
   }
-
   var hostId = normalizedAccessCode.substring(0, kSupportIdLen);
-  this.passPhrase_ = normalizedAccessCode;
+  this.credentialsProvider_ = new remoting.CredentialsProvider({
+    accessCode: normalizedAccessCode
+  });
   this.connectionMode_ = remoting.DesktopConnectedView.Mode.IT2ME;
   remoting.identity.getToken().then(
       this.connectIT2MeWithToken_.bind(this, hostId),
@@ -325,9 +281,7 @@
     return;
   }
   this.logHostOfflineErrors_ = false;
-  this.connectMe2MeInternal_(this.host_, this.fetchPin_,
-                             this.fetchThirdPartyToken_, this.clientPairingId_,
-                             this.clientPairedSecret_);
+  this.connectInternal_(this.host_, this.credentialsProvider_);
 };
 
 /**
@@ -484,13 +438,9 @@
     this.clientSession_ = null;
   }
 
-  var authenticationMethods =
-     'third_party,spake2_pair,spake2_hmac,spake2_plain';
   this.clientSession_ = new remoting.ClientSession(
-      this.host_, this.signalStrategy_, this.clientContainer_, this.passPhrase_,
-      this.fetchPin_, this.fetchThirdPartyToken_, authenticationMethods,
-      this.connectionMode_, this.clientPairingId_, this.clientPairedSecret_,
-      this.defaultRemapKeys_);
+      this.host_, this.signalStrategy_, this.credentialsProvider_,
+      this.clientContainer_, this.connectionMode_, this.defaultRemapKeys_);
   this.clientSession_.logHostOfflineErrors(this.logHostOfflineErrors_);
   this.clientSession_.addEventListener(
       remoting.ClientSession.Events.stateChanged,
@@ -533,7 +483,10 @@
       break;
 
     case remoting.ClientSession.State.CONNECTING:
-      console.log('Connecting as ' + remoting.identity.getCachedEmail());
+      remoting.identity.getEmail().then(
+          function(/** string */ email) {
+            console.log('Connecting as ' + email);
+          });
       break;
 
     case remoting.ClientSession.State.INITIALIZING:
diff --git a/remoting/webapp/crd/js/xmpp_login_handler.js b/remoting/webapp/crd/js/xmpp_login_handler.js
index 74be464..f91ef55 100644
--- a/remoting/webapp/crd/js/xmpp_login_handler.js
+++ b/remoting/webapp/crd/js/xmpp_login_handler.js
@@ -65,6 +65,12 @@
   this.streamParser_ = null;
 }
 
+/** @return {function(string, remoting.XmppStreamParser):void} */
+remoting.XmppLoginHandler.prototype.getHandshakeDoneCallbackForTesting =
+    function() {
+  return this.onHandshakeDoneCallback_;
+};
+
 /**
  * States the handshake goes through. States are iterated from INIT to DONE
  * sequentially, except for ERROR state which may be accepted at any point.
diff --git a/remoting/webapp/js_proto/chrome_cast_proto.js b/remoting/webapp/js_proto/chrome_cast_proto.js
new file mode 100644
index 0000000..58fa914
--- /dev/null
+++ b/remoting/webapp/js_proto/chrome_cast_proto.js
@@ -0,0 +1,129 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains various hacks needed to inform JSCompiler of various
+// WebKit- and Chrome-specific properties and methods. It is used only with
+// JSCompiler to verify the type-correctness of our code.
+
+/** @type {Object} */
+chrome.cast = {};
+
+/** @constructor */
+chrome.cast.AutoJoinPolicy = function() {};
+
+/** @type {chrome.cast.AutoJoinPolicy} */
+chrome.cast.AutoJoinPolicy.PAGE_SCOPED;
+
+/** @type {chrome.cast.AutoJoinPolicy} */
+chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;
+
+/** @type {chrome.cast.AutoJoinPolicy} */
+chrome.cast.AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED;
+
+/** @constructor */
+chrome.cast.DefaultActionPolicy = function() {};
+
+/** @type {chrome.cast.DefaultActionPolicy} */
+chrome.cast.DefaultActionPolicy.CAST_THIS_TAB;
+
+/** @type {chrome.cast.DefaultActionPolicy} */
+chrome.cast.DefaultActionPolicy.CREATE_SESSION;
+
+/** @constructor */
+chrome.cast.Error = function() {};
+
+/** @constructor */
+chrome.cast.ReceiverAvailability = function() {};
+
+/** @type {chrome.cast.ReceiverAvailability} */
+chrome.cast.ReceiverAvailability.AVAILABLE;
+
+/** @type {chrome.cast.ReceiverAvailability} */
+chrome.cast.ReceiverAvailability.UNAVAILABLE;
+
+/** @type {Object} */
+chrome.cast.media = {};
+
+/** @constructor */
+chrome.cast.media.Media = function() {
+  /** @type {number} */
+  this.mediaSessionId = 0;
+};
+
+/** @constructor */
+chrome.cast.Session = function() {
+  /** @type {Array<chrome.cast.media.Media>} */
+  this.media = [];
+
+  /** @type {string} */
+  this.sessionId = '';
+};
+
+/**
+ * @param {string} namespace
+ * @param {Object} message
+ * @param {function():void} successCallback
+ * @param {function(chrome.cast.Error):void} errorCallback
+ */
+chrome.cast.Session.prototype.sendMessage =
+    function(namespace, message, successCallback, errorCallback) {};
+
+/**
+ * @param {function(chrome.cast.media.Media):void} listener
+ */
+chrome.cast.Session.prototype.addMediaListener = function(listener) {};
+
+/**
+ * @param {function(boolean):void} listener
+ */
+chrome.cast.Session.prototype.addUpdateListener = function(listener) {};
+
+/**
+ * @param {string} namespace
+ * @param {function(string, string):void} listener
+ */
+chrome.cast.Session.prototype.addMessageListener =
+    function(namespace, listener){};
+
+/**
+ * @param {function():void} successCallback
+ * @param {function(chrome.cast.Error):void} errorCallback
+ */
+chrome.cast.Session.prototype.stop =
+    function(successCallback, errorCallback) {};
+
+/**
+ * @constructor
+ * @param {string} applicationID
+ */
+chrome.cast.SessionRequest = function(applicationID) {};
+
+/**
+ * @constructor
+ * @param {chrome.cast.SessionRequest} sessionRequest
+ * @param {function(chrome.cast.Session):void} sessionListener
+ * @param {function(chrome.cast.ReceiverAvailability):void} receiverListener
+ * @param {chrome.cast.AutoJoinPolicy=} opt_autoJoinPolicy
+ * @param {chrome.cast.DefaultActionPolicy=} opt_defaultActionPolicy
+ */
+chrome.cast.ApiConfig = function(sessionRequest,
+                                 sessionListener,
+                                 receiverListener,
+                                 opt_autoJoinPolicy,
+                                 opt_defaultActionPolicy) {};
+
+/**
+ * @param {chrome.cast.ApiConfig} apiConfig
+ * @param {function():void} onInitSuccess
+ * @param {function(chrome.cast.Error):void} onInitError
+ */
+chrome.cast.initialize =
+    function(apiConfig, onInitSuccess, onInitError) {};
+
+/**
+ * @param {function(chrome.cast.Session):void} successCallback
+ * @param {function(chrome.cast.Error):void} errorCallback
+ */
+chrome.cast.requestSession =
+    function(successCallback, errorCallback) {};
diff --git a/remoting/webapp/js_proto/chrome_event_proto.js b/remoting/webapp/js_proto/chrome_event_proto.js
new file mode 100644
index 0000000..317f711f
--- /dev/null
+++ b/remoting/webapp/js_proto/chrome_event_proto.js
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/** @constructor */
+chrome.Event = function() {};
+
+/** @param {Function} callback */
+chrome.Event.prototype.addListener = function(callback) {};
+
+/** @param {Function} callback */
+chrome.Event.prototype.removeListener = function(callback) {};
diff --git a/remoting/webapp/js_proto/chrome_proto.js b/remoting/webapp/js_proto/chrome_proto.js
index afa0d03..6ecead2 100644
--- a/remoting/webapp/js_proto/chrome_proto.js
+++ b/remoting/webapp/js_proto/chrome_proto.js
@@ -6,15 +6,6 @@
 // WebKit- and Chrome-specific properties and methods. It is used only with
 // JSCompiler to verify the type-correctness of our code.
 
-/** @constructor */
-chrome.Event = function() {};
-
-/** @param {Function} callback */
-chrome.Event.prototype.addListener = function(callback) {};
-
-/** @param {Function} callback */
-chrome.Event.prototype.removeListener = function(callback) {};
-
 /** @type {Object} */
 chrome.app = {};
 
@@ -438,128 +429,6 @@
 }
 
 /** @type {Object} */
-chrome.cast = {};
-
-/** @constructor */
-chrome.cast.AutoJoinPolicy = function() {};
-
-/** @type {chrome.cast.AutoJoinPolicy} */
-chrome.cast.AutoJoinPolicy.PAGE_SCOPED;
-
-/** @type {chrome.cast.AutoJoinPolicy} */
-chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;
-
-/** @type {chrome.cast.AutoJoinPolicy} */
-chrome.cast.AutoJoinPolicy.TAB_AND_ORIGIN_SCOPED;
-
-/** @constructor */
-chrome.cast.DefaultActionPolicy = function() {};
-
-/** @type {chrome.cast.DefaultActionPolicy} */
-chrome.cast.DefaultActionPolicy.CAST_THIS_TAB;
-
-/** @type {chrome.cast.DefaultActionPolicy} */
-chrome.cast.DefaultActionPolicy.CREATE_SESSION;
-
-/** @constructor */
-chrome.cast.Error = function() {};
-
-/** @constructor */
-chrome.cast.ReceiverAvailability = function() {};
-
-/** @type {chrome.cast.ReceiverAvailability} */
-chrome.cast.ReceiverAvailability.AVAILABLE;
-
-/** @type {chrome.cast.ReceiverAvailability} */
-chrome.cast.ReceiverAvailability.UNAVAILABLE;
-
-/** @type {Object} */
-chrome.cast.media = {};
-
-/** @constructor */
-chrome.cast.media.Media = function() {
-  /** @type {number} */
-  this.mediaSessionId = 0;
-};
-
-/** @constructor */
-chrome.cast.Session = function() {
-  /** @type {Array<chrome.cast.media.Media>} */
-  this.media = [];
-
-  /** @type {string} */
-  this.sessionId = '';
-};
-
-/**
- * @param {string} namespace
- * @param {Object} message
- * @param {function():void} successCallback
- * @param {function(chrome.cast.Error):void} errorCallback
- */
-chrome.cast.Session.prototype.sendMessage =
-    function(namespace, message, successCallback, errorCallback) {};
-
-/**
- * @param {function(chrome.cast.media.Media):void} listener
- */
-chrome.cast.Session.prototype.addMediaListener = function(listener) {};
-
-/**
- * @param {function(boolean):void} listener
- */
-chrome.cast.Session.prototype.addUpdateListener = function(listener) {};
-
-/**
- * @param {string} namespace
- * @param {function(string, string):void} listener
- */
-chrome.cast.Session.prototype.addMessageListener =
-    function(namespace, listener){};
-
-/**
- * @param {function():void} successCallback
- * @param {function(chrome.cast.Error):void} errorCallback
- */
-chrome.cast.Session.prototype.stop =
-    function(successCallback, errorCallback) {};
-
-/**
- * @constructor
- * @param {string} applicationID
- */
-chrome.cast.SessionRequest = function(applicationID) {};
-
-/**
- * @constructor
- * @param {chrome.cast.SessionRequest} sessionRequest
- * @param {function(chrome.cast.Session):void} sessionListener
- * @param {function(chrome.cast.ReceiverAvailability):void} receiverListener
- * @param {chrome.cast.AutoJoinPolicy=} opt_autoJoinPolicy
- * @param {chrome.cast.DefaultActionPolicy=} opt_defaultActionPolicy
- */
-chrome.cast.ApiConfig = function(sessionRequest,
-                                 sessionListener,
-                                 receiverListener,
-                                 opt_autoJoinPolicy,
-                                 opt_defaultActionPolicy) {};
-
-/**
- * @param {chrome.cast.ApiConfig} apiConfig
- * @param {function():void} onInitSuccess
- * @param {function(chrome.cast.Error):void} onInitError
- */
-chrome.cast.initialize =
-    function(apiConfig, onInitSuccess, onInitError) {};
-
-/**
- * @param {function(chrome.cast.Session):void} successCallback
- * @param {function(chrome.cast.Error):void} errorCallback
- */
-chrome.cast.requestSession =
-    function(successCallback, errorCallback) {};
-
-/** @type {Object} */
 chrome.sockets = {};
 
 /** @type {Object} */
diff --git a/remoting/webapp/js_proto/dom_proto.js b/remoting/webapp/js_proto/dom_proto.js
index 14d8abb3..f8233bd 100644
--- a/remoting/webapp/js_proto/dom_proto.js
+++ b/remoting/webapp/js_proto/dom_proto.js
@@ -45,6 +45,12 @@
 /** @type {string} */
 Element.prototype.localName;
 
+/** @type {number} */
+Element.prototype.offsetRight;
+
+/** @type {number} */
+Element.prototype.offsetBottom;
+
 /** @type {string} */
 Element.prototype.textContent;
 
diff --git a/remoting/webapp/js_proto/qunit_proto.js b/remoting/webapp/js_proto/qunit_proto.js
new file mode 100644
index 0000000..dd5745f
--- /dev/null
+++ b/remoting/webapp/js_proto/qunit_proto.js
@@ -0,0 +1,87 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains various hacks needed to inform JSCompiler of various
+// QUnit-specific properties and methods. It is used only with JSCompiler to
+// verify the type-correctness of our code.
+
+
+/** @type {Object} */
+var QUnit = QUnit || {};
+
+/** @constructor */
+QUnit.Test = function() {};
+
+/** @type {QUnit.Clock} */
+QUnit.Test.prototype.clock = new QUnit.Clock();
+
+/** @constructor */
+QUnit.Clock = function() {};
+
+/** @param {number} ticks */
+QUnit.Clock.prototype.tick = function(ticks) {};
+
+
+/**
+ * @param {string} desc
+ * @param {Function} f
+ */
+QUnit.asyncTest = function(desc, f) {};
+
+/**
+ * @param {*} a
+ * @param {*} b
+ */
+QUnit.deepEqual = function(a, b) {};
+
+/**
+ * @param {*} a
+ * @param {*} b
+ */
+QUnit.equal = function(a, b) {};
+
+/**
+ * @param {*} a
+ */
+QUnit.expect = function(a) {};
+
+/**
+ * @param {string} desc
+ * @param {Object=} dict
+ */
+QUnit.module = function(desc, dict) {};
+
+/**
+ * @param {*} a
+ * @param {*} b
+ * @param {string} desc
+ */
+QUnit.notEqual = function(a, b, desc) {};
+
+/**
+ * @param {boolean} cond
+ * @param {string=} desc
+ * @return {boolean}
+ */
+QUnit.ok = function(cond, desc) {};
+
+QUnit.start = function() {};
+
+/**
+ * @param {string} desc
+ * @param {Function} f
+ */
+QUnit.test = function(desc, f) {};
+
+/** @param {Function} f */
+QUnit.testStart = function(f) {};
+
+
+var deepEqual = QUnit.deepEqual;
+var equal = QUnit.equal;
+var expect = QUnit.expect;
+var module = QUnit.module;
+var notEqual = QUnit.notEqual;
+var ok = QUnit.ok;
+var test = QUnit.test;
diff --git a/remoting/webapp/js_proto/sinon_proto.js b/remoting/webapp/js_proto/sinon_proto.js
new file mode 100644
index 0000000..bc39ea5
--- /dev/null
+++ b/remoting/webapp/js_proto/sinon_proto.js
@@ -0,0 +1,113 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var sinon = sinon || {};
+
+/** @type {Object} */
+sinon.assert = {};
+
+/**
+ * @param {(sinon.Spy|Function)} f
+ */
+sinon.assert.called = function(f) {};
+
+/**
+ * @param {(sinon.Spy|Function)} f
+ */
+sinon.assert.calledOnce = function(f) {};
+
+/**
+ * @param {(sinon.Spy|Function)} f
+ * @param {...} data
+ */
+sinon.assert.calledWith = function(f, data) {};
+
+/**
+ * @param {(sinon.Spy|Function)} f
+ */
+sinon.assert.notCalled = function(f) {};
+
+/** @constructor */
+sinon.Expectation = function() {};
+
+/** @return {sinon.Expectation} */
+sinon.Expectation.prototype.once = function() {};
+
+/**
+ * @param {...} data
+ * @return {sinon.Expectation}
+ */
+sinon.Expectation.prototype.withArgs = function(data) {};
+
+/** @return {boolean} */
+sinon.Expectation.prototype.verify = function() {};
+
+/** @param {...} data */
+sinon.Expectation.prototype.returns = function(data) {};
+
+/**
+ * @param {Object} obj
+ * @return {sinon.Mock}
+ */
+sinon.mock = function(obj) {};
+
+/** @constructor */
+sinon.Mock = function() {};
+
+/**
+ * @param {string} method
+ * @return {sinon.Expectation}
+ */
+sinon.Mock.prototype.expects = function(method) {};
+
+/** @type {function(...):Function} */
+sinon.spy = function() {};
+
+/**
+ * This is a jscompile type that can be OR'ed with the actual type to make
+ * jscompile aware of the sinon.spy functions that are added to the base
+ * type.
+ * Example: Instead of specifying a type of
+ *   {function():void}
+ * the following can be used to add the sinon.spy functions:
+ *   {(sinon.Spy|function():void)}
+ *
+ * @constructor
+ */
+sinon.Spy = function() {};
+
+/** @type {number} */
+sinon.Spy.prototype.callCount;
+
+/** @type {boolean} */
+sinon.Spy.prototype.called = false;
+
+/** @type {function(...):boolean} */
+sinon.Spy.prototype.calledWith = function() {};
+
+/** @type {function(number):{args:Array}} */
+sinon.Spy.prototype.getCall = function(index) {};
+
+sinon.Spy.prototype.reset = function() {};
+
+/**
+ * @param {Object} obj
+ * @param {string} method
+ * @return {sinon.TestStub}
+ */
+sinon.stub = function(obj, method) {};
+
+/** @constructor */
+sinon.TestStub = function() {};
+
+/** @type {function(number):{args:Array}} */
+sinon.TestStub.prototype.getCall = function(index) {};
+
+sinon.TestStub.prototype.restore = function() {};
+
+/** @param {*} a */
+sinon.TestStub.prototype.returns = function(a) {};
+
+/** @type {function(string, (string|Array<string>)=):sinon.Expectation} */
+sinon.TestStub.prototype.withArgs = function(messageName, opt_args) {};
diff --git a/remoting/webapp/js_proto/sinon_stub_proto.js b/remoting/webapp/js_proto/sinon_stub_proto.js
new file mode 100644
index 0000000..28e7d50
--- /dev/null
+++ b/remoting/webapp/js_proto/sinon_stub_proto.js
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// How to create sinon.stubs that work with jscompile.
+//
+// To create the stub:
+//   sinon.$setupStub(<object>, <function-name>)
+//
+// To access the stub in unittests:
+//   <object>.<function-name>.$testStub.<sinon-test>
+//
+// For example:
+//    sinon.$setupStub(chrome.socket, 'create');
+//    chrome.socket.create.$testStub.restore();
+//
+// For jscompile to analyze these corectly, you'll also need to add an entry
+// in this file for any object you stub out this way. For example:
+//    chrome.socket.create.$testStub = new sinon.TestStub();
+
+base.debug.assert.$testStub = new sinon.TestStub();
+base.isAppsV2.$testStub = new sinon.TestStub();
+
+chrome.i18n.getMessage.$testStub = new sinon.TestStub();
+
+chrome.socket.connect.$testStub = new sinon.TestStub();
+chrome.socket.create.$testStub = new sinon.TestStub();
+chrome.socket.destroy.$testStub = new sinon.TestStub();
+chrome.socket.read.$testStub = new sinon.TestStub();
+chrome.socket.secure.$testStub = new sinon.TestStub();
+chrome.socket.write.$testStub = new sinon.TestStub();
diff --git a/remoting/webapp/js_proto/test_proto.js b/remoting/webapp/js_proto/test_proto.js
index 41124ba9..6689cfd 100644
--- a/remoting/webapp/js_proto/test_proto.js
+++ b/remoting/webapp/js_proto/test_proto.js
@@ -9,16 +9,12 @@
 /** @suppress {duplicate} */
 var browserTest = browserTest || {};
 
-/** @suppress {duplicate} */
-var sinon = sinon || {};
-
 /** @interface */
 browserTest.TestableClass = function() {};
 
 /** @param {*} data */
 browserTest.TestableClass.prototype.run = function(data) {};
 
-sinon.spy = function() {};
 
 /** @constructor */
 window.DomAutomationControllerMessage = function() {
diff --git a/remoting/webapp/unittests/apps_v2_migration_unittest.js b/remoting/webapp/unittests/apps_v2_migration_unittest.js
index 6bc8db9..805995aa 100644
--- a/remoting/webapp/unittests/apps_v2_migration_unittest.js
+++ b/remoting/webapp/unittests/apps_v2_migration_unittest.js
@@ -2,10 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
 
+/** @type {sinon.TestStub} */
 var mockIsAppsV2 = null;
 var mockChromeStorage = {};
 
@@ -22,10 +28,10 @@
 /**
  * @param {string} v1UserName
  * @param {string} v1UserEmail
- * @param {string} currentEmail
- * @param {boolean} v1HasHost
+ * @param {boolean} v1HasHosts
  */
 function setMigrationData_(v1UserName, v1UserEmail, v1HasHosts) {
+  /** @return {!Promise} */
   remoting.identity.getUserInfo = function() {
     if (base.isAppsV2()) {
       return Promise.resolve(
@@ -35,10 +41,13 @@
           {email: v1UserEmail, name: v1UserName});
     }
   };
+  /** @return {!Promise} */
   remoting.identity.getEmail = function() {
-    return remoting.identity.getUserInfo().then(function(info) {
-      return info.email;
-    });
+    return remoting.identity.getUserInfo().then(
+        /** @param {{email:string, name:string}} info */
+        function(info) {
+          return info.email;
+        });
   };
 
   mockIsAppsV2.returns(false);
@@ -50,8 +59,8 @@
 module('AppsV2Migration', {
   setup: function() {
     chromeMocks.activate(['storage']);
-    mockIsAppsV2 = sinon.stub(base, 'isAppsV2');
-    remoting.identity = {};
+    mockIsAppsV2 = sinon.$setupStub(base, 'isAppsV2');
+    remoting.identity = new remoting.Identity();
   },
   teardown: function() {
     chromeMocks.restore();
@@ -89,6 +98,7 @@
     setMigrationData_('v1userName', 'v1user@gmail.com', true);
     mockIsAppsV2.returns(true);
     remoting.AppsV2Migration.hasHostsInV1App().then(
+      /** @param {{email:string, name:string}} result */
       function(result) {
         QUnit.equal(result.email, 'v1user@gmail.com');
         QUnit.equal(result.fullName, 'v1userName');
@@ -100,10 +110,9 @@
 QUnit.asyncTest(
   'saveUserInfo() should clear the preferences on v2',
   function() {
-    setMigrationData_('v1userName', 'v1user@gmail.com', 'v2user@gmail.com',
-                      true);
+    setMigrationData_('v1userName', 'v1user@gmail.com', true);
     mockIsAppsV2.returns(true);
-    remoting.AppsV2Migration.saveUserInfo(true);
+    remoting.AppsV2Migration.saveUserInfo();
     remoting.AppsV2Migration.hasHostsInV1App().then(fail, pass);
 });
 
diff --git a/remoting/webapp/unittests/base_unittest.js b/remoting/webapp/unittests/base_unittest.js
index 6ffc8c9..288ff91 100644
--- a/remoting/webapp/unittests/base_unittest.js
+++ b/remoting/webapp/unittests/base_unittest.js
@@ -22,14 +22,14 @@
     var src = { a: 'a', b: 'b'};
     var dest = { a: 'a'};
 
-    sinon.spy(base.debug, 'assert');
+    sinon.$setupStub(base.debug, 'assert');
 
     try {
       base.mix(dest, src);
     } catch (e) {
     } finally {
       sinon.assert.called(base.debug.assert);
-      base.debug.assert.restore();
+      base.debug.assert.$testStub.restore();
     }
 });
 
@@ -72,9 +72,14 @@
 
 test('dispose(obj) should invoke the dispose method on |obj|',
   function() {
-    var obj = {
-      dispose: sinon.spy()
-    };
+    /**
+     * @constructor
+     * @implements {base.Disposable}
+     */
+    base.MockDisposable = function() {};
+    base.MockDisposable.prototype.dispose = sinon.spy();
+
+    var obj = new base.MockDisposable();
     base.dispose(obj);
     sinon.assert.called(obj.dispose);
 });
@@ -111,9 +116,14 @@
 });
 
 QUnit.asyncTest('Promise.sleep(delay) should fulfill the promise after |delay|',
+  /**
+   * 'this' is not defined for jscompile, so it can't figure out the type of
+   * this.clock.
+   * @suppress {reportUnknownTypes|checkVars|checkTypes}
+   */
   function() {
     var isCalled = false;
-    var clock = this.clock;
+    var clock = /** @type {QUnit.Clock} */ (this.clock);
 
     base.Promise.sleep(100).then(function(){
       isCalled = true;
@@ -129,18 +139,18 @@
     window.requestAnimationFrame(function(){
       ok(!isCalled, 'Promise.sleep() should not be fulfilled prematurely.');
       clock.tick(101);
-    }.bind(this));
+    });
 });
 
 QUnit.asyncTest('Promise.negate should fulfill iff the promise does not.',
   function() {
 
     base.Promise.negate(Promise.reject()).then(
-        ok.bind(null, true),
-        ok.bind(null, false));
+        QUnit.ok.bind(null, true),
+        /** @type {Function} */ (QUnit.ok.bind(null, false)));
     base.Promise.negate(Promise.resolve()).then(
-        ok.bind(null, false),
-        ok.bind(null, true));
+        QUnit.ok.bind(null, false),
+        /** @type {Function} */ (QUnit.ok.bind(null, true)));
     window.requestAnimationFrame(function(){
       QUnit.start();
     });
@@ -149,21 +159,25 @@
 module('base.Deferred');
 
 QUnit.asyncTest('resolve() should fulfill the underlying promise.', function() {
+  /** @returns {Promise} */
   function async() {
     var deferred = new base.Deferred();
     deferred.resolve('bar');
     return deferred.promise();
   }
 
-  async().then(function(value){
-    QUnit.equal(value, 'bar');
-    QUnit.start();
-  }, function() {
-    QUnit.ok(false, 'The reject handler should not be invoked.');
-  });
+  async().then(
+      /** @param {string} value */
+      function(value){
+          QUnit.equal(value, 'bar');
+          QUnit.start();
+      }, function() {
+          QUnit.ok(false, 'The reject handler should not be invoked.');
+      });
 });
 
 QUnit.asyncTest('reject() should fail the underlying promise.', function() {
+  /** @returns {Promise} */
   function async() {
     var deferred = new base.Deferred();
     deferred.reject('bar');
@@ -179,6 +193,7 @@
 });
 
 
+/** @type {base.EventSourceImpl} */
 var source = null;
 var listener = null;
 
@@ -229,13 +244,13 @@
 
 test('raiseEvent() should assert when undeclared events are raised',
   function() {
-    sinon.spy(base.debug, 'assert');
+    sinon.$setupStub(base.debug, 'assert');
     try {
       source.raiseEvent('undefined');
     } catch (e) {
     } finally {
       sinon.assert.called(base.debug.assert);
-      base.debug.assert.restore();
+      base.debug.assert.$testStub.restore();
     }
 });
 
@@ -268,6 +283,7 @@
 });
 
 test('encodeUtf8() can encode UTF8 strings', function() {
+  /** @type {function(ArrayBuffer):Array} */
   function toJsArray(arrayBuffer) {
     var result = [];
     var array = new Uint8Array(arrayBuffer);
diff --git a/remoting/webapp/unittests/chrome_mocks.js b/remoting/webapp/unittests/chrome_mocks.js
index be55785..fb65437 100644
--- a/remoting/webapp/unittests/chrome_mocks.js
+++ b/remoting/webapp/unittests/chrome_mocks.js
@@ -9,6 +9,16 @@
 
 var chromeMocks = {};
 
+/** @constructor */
+chrome.Event = function() {};
+
+/** @param {Function} callback */
+chrome.Event.prototype.addListener = function(callback) {};
+
+/** @param {Function} callback */
+chrome.Event.prototype.removeListener = function(callback) {};
+
+
 (function(){
 
 /**
diff --git a/remoting/webapp/unittests/desktop_viewport_unittest.js b/remoting/webapp/unittests/desktop_viewport_unittest.js
index 054bf57..238c925 100644
--- a/remoting/webapp/unittests/desktop_viewport_unittest.js
+++ b/remoting/webapp/unittests/desktop_viewport_unittest.js
@@ -6,16 +6,26 @@
 
 'use strict';
 
-module('DesktopViewport');
-
+/**
+ * @param {number} width
+ * @param {number} height
+ * @return {{width:number, height:number}}
+ */
 function size(width, height) {
   return {width: width, height: height};
 }
 
+/**
+ * @param {number} x
+ * @param {number} y
+ * @return {{x:number, y:number}}
+ */
 function dpi(x, y) {
   return {x: x, y: y};
 }
 
+module('DesktopViewport');
+
 test('choosePluginSize() handles low-DPI client & host',
   function() {
     // 1. Client & host size the same.
diff --git a/remoting/webapp/unittests/dns_blackhole_checker_unittest.js b/remoting/webapp/unittests/dns_blackhole_checker_unittest.js
index d6e7d22..6f5b0b2e 100644
--- a/remoting/webapp/unittests/dns_blackhole_checker_unittest.js
+++ b/remoting/webapp/unittests/dns_blackhole_checker_unittest.js
@@ -2,13 +2,26 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * TODO(garykac): Create interface for SignalStrategy.
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
 
+/** @type {(sinon.Spy|function(remoting.SignalStrategy.State))} */
 var onStateChange = null;
+
+/** @type {(sinon.Spy|function(Element):void)} */
 var onIncomingStanzaCallback = null;
+
+/** @type {remoting.DnsBlackholeChecker} */
 var checker = null;
+
+/** @type {remoting.MockSignalStrategy} */
 var signalStrategy = null;
 var fakeXhrs;
 
@@ -19,7 +32,6 @@
       fakeXhrs.push(xhr);
     };
 
-
     onStateChange = sinon.spy();
     onIncomingStanzaCallback = sinon.spy();
     signalStrategy = new remoting.MockSignalStrategy();
diff --git a/remoting/webapp/unittests/event_hook_unittest.js b/remoting/webapp/unittests/event_hook_unittest.js
index ee67d1f4..15135bde 100644
--- a/remoting/webapp/unittests/event_hook_unittest.js
+++ b/remoting/webapp/unittests/event_hook_unittest.js
@@ -2,19 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * TODO(garykac) Remove suppression once chromeMocks has been replaced.
+ * @suppress {checkTypes|checkVars|reportUnknownTypes}
+ */
+
 (function() {
 
 'use strict';
 
+/** @type {base.EventSourceImpl} */
 var eventSource = null;
+
+/** @type {HTMLElement} */
 var domElement = null;
+
+/** @type {chromeMocks.Event} */
 var myChromeEvent = null;
+
+/** @type {Listener} */
 var listener = null;
 
+/**
+ * @param {HTMLElement} element
+ * @constructor
+ */
 var Listener = function(element) {
-  this.onChromeEvent = sinon.stub();
-  this.onClickEvent = sinon.stub();
-  this.onCustomEvent = sinon.stub();
+  /** @type {(sinon.Spy|function(...?))} */
+  this.onChromeEvent = sinon.spy();
+  /** @type {(sinon.Spy|function(...?))} */
+  this.onClickEvent = sinon.spy();
+  /** @type {(sinon.Spy|function(...?))} */
+  this.onCustomEvent = sinon.spy();
+
   this.eventHooks_ = new base.Disposables(
       new base.DomEventHook(element, 'click', this.onClickEvent.bind(this),
                             false),
@@ -35,7 +56,7 @@
 
 module('base.EventHook', {
   setup: function() {
-    domElement = document.createElement('div');
+    domElement = /** @type {HTMLElement} */ (document.createElement('div'));
     eventSource = new base.EventSourceImpl();
     eventSource.defineEvents(['customEvent']);
     myChromeEvent = new chromeMocks.Event();
diff --git a/remoting/webapp/unittests/fallback_signal_strategy_unittest.js b/remoting/webapp/unittests/fallback_signal_strategy_unittest.js
index 959902ba..9f97a729 100644
--- a/remoting/webapp/unittests/fallback_signal_strategy_unittest.js
+++ b/remoting/webapp/unittests/fallback_signal_strategy_unittest.js
@@ -2,15 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * TODO(garykac): Create interfaces for LogToServer and SignalStrategy.
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
 
-
+/** @constructor */
 var MockLogToServer = function() {
+  /** @type {(sinon.Spy|Function)} */
   this.logSignalStrategyProgress = sinon.spy();
 };
 
+/** @type {function(...)} */
 MockLogToServer.prototype.assertProgress = function() {
   equal(this.logSignalStrategyProgress.callCount * 2, arguments.length);
   for (var i = 0; i < this.logSignalStrategyProgress.callCount; ++i) {
@@ -20,13 +28,29 @@
   }
 };
 
+/** @type {(sinon.Spy|function(remoting.SignalStrategy.State))} */
 var onStateChange = null;
+
+/** @type {(sinon.Spy|function(Element):void)} */
 var onIncomingStanzaCallback = null;
+
+/** @type {remoting.FallbackSignalStrategy} */
 var strategy = null;
+
+/** @type {remoting.SignalStrategy} */
 var primary = null;
+
+/** @type {remoting.SignalStrategy} */
 var secondary = null;
+
+/** @type {MockLogToServer} */
 var logToServer = null;
 
+/**
+ * @param {remoting.MockSignalStrategy} baseSignalStrategy
+ * @param {remoting.SignalStrategy.State} state
+ * @param {boolean} expectCallback
+ */
 function setState(baseSignalStrategy, state, expectCallback) {
   onStateChange.reset();
   baseSignalStrategy.setStateForTesting(state);
diff --git a/remoting/webapp/unittests/ipc_unittest.js b/remoting/webapp/unittests/ipc_unittest.js
index 9434cab..e786147 100644
--- a/remoting/webapp/unittests/ipc_unittest.js
+++ b/remoting/webapp/unittests/ipc_unittest.js
@@ -6,6 +6,7 @@
 
 'use strict';
 
+/** @type {base.Ipc} */
 var ipc_;
 
 function pass() {
@@ -62,7 +63,7 @@
   function() {
     var handler = sinon.spy();
     ipc_.register('foo', handler);
-    ipc_.unregister('foo', handler);
+    ipc_.unregister('foo');
     base.Ipc.invoke('foo', 'hello', 'world').then(fail, function(error) {
       sinon.assert.notCalled(handler);
       QUnit.equal(error, base.Ipc.Error.UNSUPPORTED_REQUEST_TYPE);
diff --git a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js b/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
index 85bee2b..30d060d 100644
--- a/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
+++ b/remoting/webapp/unittests/it2me_helpee_channel_unittest.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
diff --git a/remoting/webapp/unittests/it2me_helper_channel_unittest.js b/remoting/webapp/unittests/it2me_helper_channel_unittest.js
index f0a0fa2..aa25693f 100644
--- a/remoting/webapp/unittests/it2me_helper_channel_unittest.js
+++ b/remoting/webapp/unittests/it2me_helper_channel_unittest.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
diff --git a/remoting/webapp/unittests/it2me_service_unittest.js b/remoting/webapp/unittests/it2me_service_unittest.js
index 1bd66f5..a9a71b0 100644
--- a/remoting/webapp/unittests/it2me_service_unittest.js
+++ b/remoting/webapp/unittests/it2me_service_unittest.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * @suppress {checkTypes|checkVars|reportUnknownTypes|visibility}
+ */
+
 (function() {
 
 'use strict';
@@ -129,4 +134,4 @@
   sinon.assert.called(randomPort.disconnect);
 });
 
-})();
\ No newline at end of file
+})();
diff --git a/remoting/webapp/unittests/l10n_unittest.js b/remoting/webapp/unittests/l10n_unittest.js
index 6ac3680f..043aaab 100644
--- a/remoting/webapp/unittests/l10n_unittest.js
+++ b/remoting/webapp/unittests/l10n_unittest.js
@@ -8,10 +8,10 @@
 
 module('l10n', {
   setup: function() {
-    sinon.stub(chrome.i18n, 'getMessage');
+    sinon.$setupStub(chrome.i18n, 'getMessage');
   },
   teardown: function() {
-    chrome.i18n.getMessage.restore();
+    chrome.i18n.getMessage.$testStub.restore();
   }
 });
 
@@ -23,7 +23,8 @@
 test('localizeElementFromTag() should replace innerText by default',
   function() {
     var element = document.createElement('div');
-    chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>');
+    chrome.i18n.getMessage.$testStub.withArgs('tag')
+          .returns('<b>Hello World</b>');
 
     l10n.localizeElementFromTag(element, 'tag');
 
@@ -33,7 +34,8 @@
 test('localizeElementFromTag() should replace innerHTML if flag is set',
   function() {
     var element = document.createElement('div');
-    chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>');
+    chrome.i18n.getMessage.$testStub.withArgs('tag')
+          .returns('<b>Hello World</b>');
 
     l10n.localizeElementFromTag(element, 'tag', null, true);
 
@@ -46,7 +48,8 @@
   function() {
     var element = document.createElement('div');
     element.setAttribute('i18n-content', 'tag');
-    chrome.i18n.getMessage.withArgs('tag').returns('<b>Hello World</b>');
+    chrome.i18n.getMessage.$testStub.withArgs('tag')
+          .returns('<b>Hello World</b>');
 
     l10n.localizeElement(element);
 
@@ -59,7 +62,7 @@
   function() {
     var fixture = document.getElementById('qunit-fixture');
     fixture.innerHTML = '<div class="target" i18n-title="tag"></div>';
-    chrome.i18n.getMessage.withArgs('tag').returns('localized title');
+    chrome.i18n.getMessage.$testStub.withArgs('tag').returns('localized title');
 
     l10n.localize();
 
@@ -76,7 +79,7 @@
       'i18n-value-2="param2">' +
   '</div>';
 
-  chrome.i18n.getMessage.withArgs('tag', ['param1', 'param2'])
+  chrome.i18n.getMessage.$testStub.withArgs('tag', ['param1', 'param2'])
       .returns('localized');
 
   l10n.localize();
@@ -91,7 +94,7 @@
       '<div class="target" i18n-content="tag"' +
       ' i18n-value-name-1="tag1" i18n-value-name-2="tag2"></div>';
 
-  var getMessage = chrome.i18n.getMessage;
+  var getMessage = chrome.i18n.getMessage.$testStub;
   getMessage.withArgs('tag1').returns('param1');
   getMessage.withArgs('tag2').returns('param2');
   getMessage.withArgs('tag', ['param1', 'param2']).returns('localized');
diff --git a/remoting/webapp/unittests/menu_button_unittest.js b/remoting/webapp/unittests/menu_button_unittest.js
index 7337134..1367b0da 100644
--- a/remoting/webapp/unittests/menu_button_unittest.js
+++ b/remoting/webapp/unittests/menu_button_unittest.js
@@ -6,8 +6,11 @@
 
 'use strict';
 
+/** @type {(sinon.Spy|function():void)} */
 var onShow = null;
+/** @type {(sinon.Spy|function():void)} */
 var onHide = null;
+/** @type {remoting.MenuButton} */
 var menuButton = null;
 
 module('MenuButton', {
@@ -20,11 +23,12 @@
             '<li id="menu-option-1">Option 1</li>' +
           '</ul>' +
         '</span>';
-    onShow = sinon.spy();
-    onHide = sinon.spy();
+    onShow = /** @type {(sinon.Spy|function():void)} */ (sinon.spy());
+    onHide = /** @type {(sinon.Spy|function():void)} */ (sinon.spy());
     menuButton = new remoting.MenuButton(
         document.getElementById('menu-button-container'),
-        onShow, onHide);
+        /** @type {function():void} */ (onShow),
+        /** @type {function():void} */ (onHide));
   },
   teardown: function() {
     onShow = null;
@@ -87,4 +91,4 @@
   ok(style.backgroundImage == 'none');
 });
 
-}());
\ No newline at end of file
+}());
diff --git a/remoting/webapp/unittests/mock_signal_strategy.js b/remoting/webapp/unittests/mock_signal_strategy.js
index 46e27f36..6935b05 100644
--- a/remoting/webapp/unittests/mock_signal_strategy.js
+++ b/remoting/webapp/unittests/mock_signal_strategy.js
@@ -9,8 +9,8 @@
 
 
 /**
- * @param {string} jid
- * @param {remoting.SignalStrategy.Type} type
+ * @param {string=} jid
+ * @param {remoting.SignalStrategy.Type=} type
  *
  * @implements {remoting.SignalStrategy}
  * @constructor
diff --git a/remoting/webapp/unittests/sinon_helpers.js b/remoting/webapp/unittests/sinon_helpers.js
new file mode 100644
index 0000000..763a9391
--- /dev/null
+++ b/remoting/webapp/unittests/sinon_helpers.js
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var sinonHelpers = {};
+
+sinonHelpers.reset = function() {
+
+/**
+ * @param {Object} obj
+ * @param {string} method
+ * @return {sinon.TestStub}
+ * @suppress {reportUnknownTypes}
+ */
+sinon.$setupStub = function(obj, method) {
+  sinon.stub(obj, method);
+  obj[method].$testStub = /** @type {sinon.TestStub} */ (obj[method]);
+  return obj[method].$testStub;
+};
+
+};
diff --git a/remoting/webapp/unittests/test_start.js b/remoting/webapp/unittests/test_start.js
new file mode 100644
index 0000000..8159ce7
--- /dev/null
+++ b/remoting/webapp/unittests/test_start.js
@@ -0,0 +1,12 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Global test setup.
+// This code is run before each test in every module.
+
+QUnit.testStart(
+    /** @param {{module:string, name:string}} details */
+    function(details) {
+      sinonHelpers.reset();
+    });
diff --git a/remoting/webapp/unittests/xhr_unittest.js b/remoting/webapp/unittests/xhr_unittest.js
index 804f7159..ea32042 100644
--- a/remoting/webapp/unittests/xhr_unittest.js
+++ b/remoting/webapp/unittests/xhr_unittest.js
@@ -2,6 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+/**
+ * @fileoverview
+ * @suppress {checkTypes|checkVars|reportUnknownTypes}
+ */
+
 (function() {
 
 'use strict';
diff --git a/remoting/webapp/unittests/xmpp_connection_unittest.js b/remoting/webapp/unittests/xmpp_connection_unittest.js
index a36261f..38aa6c2 100644
--- a/remoting/webapp/unittests/xmpp_connection_unittest.js
+++ b/remoting/webapp/unittests/xmpp_connection_unittest.js
@@ -10,37 +10,44 @@
 var testToken = 'testToken';
 var socketId = 3;
 
-var onStateChange = null;
+/** @type {(sinon.Spy|function(remoting.SignalStrategy.State):void)} */
+var onStateChange = function() {};
+
 var onStanzaStr = null;
+
+/** @type {remoting.XmppConnection} */
 var connection = null;
 
 module('XmppConnection', {
   setup: function() {
     onStateChange = sinon.spy();
     onStanzaStr = sinon.spy();
+    /** @param {Element} stanza */
     function onStanza(stanza) {
       onStanzaStr(new XMLSerializer().serializeToString(stanza));
     }
 
-    sinon.stub(chrome.socket, 'create');
-    sinon.stub(chrome.socket, 'connect');
-    sinon.stub(chrome.socket, 'write');
-    sinon.stub(chrome.socket, 'read');
-    sinon.stub(chrome.socket, 'destroy');
-    sinon.stub(chrome.socket, 'secure');
+    sinon.$setupStub(chrome.socket, 'create');
+    sinon.$setupStub(chrome.socket, 'connect');
+    sinon.$setupStub(chrome.socket, 'write');
+    sinon.$setupStub(chrome.socket, 'read');
+    sinon.$setupStub(chrome.socket, 'destroy');
+    sinon.$setupStub(chrome.socket, 'secure');
 
     connection = new remoting.XmppConnection();
-    connection.setStateChangedCallback(onStateChange);
+    connection.setStateChangedCallback(
+        /** @type {function(remoting.SignalStrategy.State):void} */
+            (onStateChange));
     connection.setIncomingStanzaCallback(onStanza);
   },
 
   teardown: function() {
-    chrome.socket.create.restore();
-    chrome.socket.connect.restore();
-    chrome.socket.write.restore();
-    chrome.socket.read.restore();
-    chrome.socket.destroy.restore();
-    chrome.socket.secure.restore();
+    chrome.socket.create.$testStub.restore();
+    chrome.socket.connect.$testStub.restore();
+    chrome.socket.write.$testStub.restore();
+    chrome.socket.read.$testStub.restore();
+    chrome.socket.destroy.$testStub.restore();
+    chrome.socket.secure.$testStub.restore();
   }
 });
 
@@ -50,11 +57,11 @@
   sinon.assert.calledWith(onStateChange,
                           remoting.SignalStrategy.State.CONNECTING);
   sinon.assert.calledWith(chrome.socket.create, "tcp", {});
-  chrome.socket.create.getCall(0).args[2]({socketId: socketId});
+  chrome.socket.create.$testStub.getCall(0).args[2]({socketId: socketId});
 
   sinon.assert.calledWith(
       chrome.socket.connect, socketId, "xmpp.example.com", 123);
-  chrome.socket.connect.getCall(0).args[3](-1);
+  chrome.socket.connect.$testStub.getCall(0).args[3](-1);
 
   QUnit.equal(connection.getError(), remoting.Error.NETWORK_FAILURE);
 });
@@ -66,11 +73,11 @@
   sinon.assert.calledWith(onStateChange,
                           remoting.SignalStrategy.State.CONNECTING);
   sinon.assert.calledWith(chrome.socket.create, "tcp", {});
-  chrome.socket.create.getCall(0).args[2]({socketId: socketId});
+  chrome.socket.create.$testStub.getCall(0).args[2]({socketId: socketId});
 
   sinon.assert.calledWith(
       chrome.socket.connect, socketId, "xmpp.example.com", 123);
-  chrome.socket.connect.getCall(0).args[3](0);
+  chrome.socket.connect.$testStub.getCall(0).args[3](0);
 
   sinon.assert.calledWith(onStateChange,
                           remoting.SignalStrategy.State.HANDSHAKE);
@@ -78,8 +85,9 @@
   var parser = new remoting.XmppStreamParser();
   var parserMock = sinon.mock(parser);
   var setCallbacksCalled = parserMock.expects('setCallbacks').once();
-  connection.loginHandler_.onHandshakeDoneCallback_('test@example.com/123123',
-                                                    parser);
+  var handshakeDoneCallback =
+      connection.loginHandler_.getHandshakeDoneCallbackForTesting();
+  handshakeDoneCallback('test@example.com/123123', parser);
   sinon.assert.calledWith(onStateChange,
                           remoting.SignalStrategy.State.CONNECTED);
   setCallbacksCalled.verify();
@@ -88,7 +96,7 @@
   var data = base.encodeUtf8('<iq id="1">hello</iq>');
   sinon.assert.calledWith(chrome.socket.read, socketId);
   var appendDataCalled = parserMock.expects('appendData').once().withArgs(data);
-  chrome.socket.read.getCall(0).args[1]({resultCode: 0, data: data});
+  chrome.socket.read.$testStub.getCall(0).args[1]({resultCode: 0, data: data});
   appendDataCalled.verify();
 });
 
diff --git a/remoting/webapp/unittests/xmpp_login_handler_unittest.js b/remoting/webapp/unittests/xmpp_login_handler_unittest.js
index 2b1adfd..1421651 100644
--- a/remoting/webapp/unittests/xmpp_login_handler_unittest.js
+++ b/remoting/webapp/unittests/xmpp_login_handler_unittest.js
@@ -9,22 +9,45 @@
 var testUsername = 'testUsername@gmail.com';
 var testToken = 'testToken';
 
-var sendMessage = null;
-var startTls = null;
-var onHandshakeDone = null;
-var onStanzaStr = null;
-var onError = null;
+/** @type {(sinon.Spy|function(string):void)} */
+var sendMessage_spy = function(msg) {};
+/** @type {function(string):void} */
+var sendMessage = function(msg) {};
+
+/** @type {(sinon.Spy|function():void)} */
+var startTls_spy = function() {};
+/** @type {function():void} */
+var startTls = function() {};
+
+/** @type {(sinon.Spy|function(string, remoting.XmppStreamParser):void)} */
+var onHandshakeDone_spy = function(name, parser) {};
+/** @type {function(string, remoting.XmppStreamParser):void} */
+var onHandshakeDone = function(name, parser) {};
+
+/** @type {(sinon.Spy|function(remoting.Error, string):void)} */
+var onError_spy = function(error, message) {};
+/** @type {function(remoting.Error, string):void} */
+var onError = function(error, message) {};
+
+/** @type {remoting.XmppLoginHandler} */
 var loginHandler = null;
 
 module('XmppLoginHandler', {
   setup: function() {
-    sendMessage = sinon.spy();
-    startTls = sinon.spy();
-    onHandshakeDone = sinon.spy();
-    onError = sinon.spy();
+    sendMessage_spy = sinon.spy();
+    sendMessage = /** @type {function(string):void} */ (sendMessage_spy);
+    startTls_spy = sinon.spy();
+    startTls = /** @type {function():void} */ (startTls_spy);
+    onHandshakeDone_spy = sinon.spy();
+    onHandshakeDone =
+          /** @type {function(string, remoting.XmppStreamParser):void} */
+          (onHandshakeDone_spy);
+    onError_spy = sinon.spy();
+    onError = /** @type {function(remoting.Error, string):void} */(onError_spy);
+
     loginHandler = new remoting.XmppLoginHandler(
-        'google.com', testUsername, testToken, false, sendMessage,
-        startTls, onHandshakeDone, onError);
+        'google.com', testUsername, testToken, false,
+        sendMessage, startTls, onHandshakeDone, onError);
   }
 });
 
@@ -33,7 +56,7 @@
   loginHandler.start();
 
   sinon.assert.calledWith(startTls);
-  startTls.reset();
+  startTls_spy.reset();
 
   loginHandler.onTlsStarted();
   var cookie = window.btoa("\0" + testUsername + "\0" + testToken);
@@ -47,7 +70,7 @@
           'auth:allow-non-google-login="true" ' +
           'xmlns:auth="http://www.google.com/talk/protocol/auth">' + cookie +
       '</auth>');
-  sendMessage.reset();
+  sendMessage_spy.reset();
 
   loginHandler.onDataReceived(base.encodeUtf8(
       '<stream:stream from="google.com" id="DCDDE5171CB2154A" version="1.0" ' +
@@ -79,7 +102,7 @@
         '<iq type="set" id="1">' +
           '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>' +
         '</iq>');
-  sendMessage.reset();
+  sendMessage_spy.reset();
 
   loginHandler.onDataReceived(base.encodeUtf8(
       '<stream:stream from="google.com" id="104FA10576E2AA80" version="1.0" ' +
@@ -110,7 +133,7 @@
       '<stream:stream to="google.com" version="1.0" xmlns="jabber:client" ' +
           'xmlns:stream="http://etherx.jabber.org/streams">' +
           '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
-  sendMessage.reset();
+  sendMessage_spy.reset();
 
   loginHandler.onDataReceived(base.encodeUtf8(
       '<stream:stream from="google.com" id="78A87C70559EF28A" version="1.0" ' +
diff --git a/remoting/webapp/unittests/xmpp_stream_parser_unittest.js b/remoting/webapp/unittests/xmpp_stream_parser_unittest.js
index 21a972e..ec6cc45 100644
--- a/remoting/webapp/unittests/xmpp_stream_parser_unittest.js
+++ b/remoting/webapp/unittests/xmpp_stream_parser_unittest.js
@@ -6,14 +6,20 @@
 
 'use strict';
 
+/** @type {Function} */
 var onStanzaStr = null;
-var onError = null;
+
+/** @type {function(string):void} */
+var onError = function(msg) {};
+
+/** @type {remoting.XmppStreamParser} */
 var parser = null;
 
 module('XmppStreamParser', {
   setup: function() {
     onStanzaStr = sinon.spy();
-    onError = sinon.spy();
+    onError = /** @type {function(string):void} */ (sinon.spy());
+    /** @param {Element} stanza */
     function onStanza(stanza) {
       onStanzaStr(new XMLSerializer().serializeToString(stanza));
     }
diff --git a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
index 2d337c6..8e7e144b 100644
--- a/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
+++ b/sandbox/linux/integration_tests/bpf_dsl_seccomp_unittest.cc
@@ -651,6 +651,10 @@
   return UnsafeTrap(AllowRedirectedSyscall, NULL);
 }
 
+#if !defined(ADDRESS_SANITIZER)
+// ASan does not allow changing the signal handler for SIGBUS, and treats it as
+// a fatal signal.
+
 int bus_handler_fd_ = -1;
 
 void SigBusHandler(int, siginfo_t* info, void* void_context) {
@@ -679,6 +683,7 @@
   BPF_ASSERT(close(fds[1]) == 0);
   BPF_ASSERT(c == 0x55);
 }
+#endif  // !defined(ADDRESS_SANITIZER)
 
 BPF_TEST_C(SandboxBPF, SigMask, RedirectAllSyscallsPolicy) {
   // Signal masks are potentially tricky to handle. For instance, if we
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 8c843c9c..3e3bc0c 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -255,7 +255,6 @@
       "/wd4554",  # 'operator' : check operator precedence for possible error
       "/wd4748",  # compiler will disable optimizations if a function has inline
                   # assembly code contains flow control(jmp or jcc) statements.
-
       "/wd4800",  # forcing value to bool 'true/false'(assigning int to bool).
     ]
   }
@@ -343,7 +342,6 @@
     "//third_party/skia/include/utils/SkLayer.h",
     "//third_party/skia/include/utils/SkMeshUtils.h",
     "//third_party/skia/include/utils/SkNinePatch.h",
-    "//third_party/skia/include/utils/SkParse.h",
     "//third_party/skia/include/utils/SkParsePaint.h",
     "//third_party/skia/include/utils/SkParsePath.h",
     "//third_party/skia/include/utils/SkRandom.h",
@@ -364,8 +362,6 @@
     "//third_party/skia/src/utils/SkMeshUtils.cpp",
     "//third_party/skia/src/utils/SkNinePatch.cpp",
     "//third_party/skia/src/utils/SkOSFile.cpp",
-    "//third_party/skia/src/utils/SkParse.cpp",
-    "//third_party/skia/src/utils/SkParseColor.cpp",
     "//third_party/skia/src/utils/SkParsePath.cpp",
     "//third_party/skia/src/utils/SkPathUtils.cpp",
     "//third_party/skia/src/utils/SkSHA1.cpp",
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi
index 2163a797..04e428a 100644
--- a/skia/skia_library.gypi
+++ b/skia/skia_library.gypi
@@ -102,7 +102,6 @@
   '../third_party/skia/include/utils/SkLayer.h',
   '../third_party/skia/include/utils/SkMeshUtils.h',
   '../third_party/skia/include/utils/SkNinePatch.h',
-  '../third_party/skia/include/utils/SkParse.h',
   '../third_party/skia/include/utils/SkParsePaint.h',
   '../third_party/skia/include/utils/SkParsePath.h',
   '../third_party/skia/include/utils/SkRandom.h',
@@ -124,8 +123,6 @@
   '../third_party/skia/src/utils/SkMeshUtils.cpp',
   '../third_party/skia/src/utils/SkNinePatch.cpp',
   '../third_party/skia/src/utils/SkOSFile.cpp',
-  '../third_party/skia/src/utils/SkParse.cpp',
-  '../third_party/skia/src/utils/SkParseColor.cpp',
   '../third_party/skia/src/utils/SkParsePath.cpp',
   '../third_party/skia/src/utils/SkPathUtils.cpp',
   '../third_party/skia/src/utils/SkSHA1.cpp',
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index 5170ceb3..b673930 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -375,8 +375,8 @@
 bool BlobStorageContext::AppendBlob(
     const std::string& target_blob_uuid,
     const InternalBlobData& blob,
-    size_t offset,
-    size_t length,
+    uint64_t offset,
+    uint64_t length,
     InternalBlobData::Builder* target_blob_builder) {
   DCHECK(length > 0);
 
@@ -395,10 +395,10 @@
   for (; iter != items.end() && length > 0; ++iter) {
     scoped_refptr<ShareableBlobDataItem> shareable_item = iter->get();
     const BlobDataItem& item = *(shareable_item->item());
-    size_t item_length = item.length();
+    uint64_t item_length = item.length();
     DCHECK_GT(item_length, offset);
-    size_t current_length = item_length - offset;
-    size_t new_length = current_length > length ? length : current_length;
+    uint64_t current_length = item_length - offset;
+    uint64_t new_length = current_length > length ? length : current_length;
 
     bool reusing_blob_item = offset == 0 && new_length == item.length();
     UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ReusedItem", reusing_blob_item);
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
index 175e90020..cf73c8a 100644
--- a/storage/browser/blob/blob_storage_context.h
+++ b/storage/browser/blob/blob_storage_context.h
@@ -122,8 +122,8 @@
   // have to split an item.
   bool AppendBlob(const std::string& target_blob_uuid,
                   const InternalBlobData& blob,
-                  size_t offset,
-                  size_t length,
+                  uint64_t offset,
+                  uint64_t length,
                   InternalBlobData::Builder* target_blob_data);
 
   bool IsInUse(const std::string& uuid);
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index 5831f7f2..de068686 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -1,5 +1,11 @@
 {
   "WebKit Linux": {
+    "gtest_tests": [
+      "blink_heap_unittests",
+      "blink_platform_unittests",
+      "webkit_unit_tests",
+      "wtf_unittests"
+    ],
     "scripts": [
       {
         "name": "webkit_lint",
diff --git a/testing/chromoting/chromoting_integration_tests.isolate b/testing/chromoting/chromoting_integration_tests.isolate
index be04bd6..2df2a15 100644
--- a/testing/chromoting/chromoting_integration_tests.isolate
+++ b/testing/chromoting/chromoting_integration_tests.isolate
@@ -30,6 +30,7 @@
           '../../remoting/tools/internal/test-account-host-config.json',
           '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json',
           '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_assistance.json',
+          '<(PRODUCT_DIR)/remoting-me2me-host.deb',
         ],
       },
     }],
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index 84b983f..f1a210d 100644
--- a/third_party/libjingle/README.chromium
+++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@
 Name: libjingle
 URL: http://code.google.com/p/webrtc/
 Version: unknown
-Revision: 8542
+Revision: 8550
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/tools/auto_bisect/bisect_perf_regression.py b/tools/auto_bisect/bisect_perf_regression.py
index 71f701c..746952eb 100755
--- a/tools/auto_bisect/bisect_perf_regression.py
+++ b/tools/auto_bisect/bisect_perf_regression.py
@@ -2645,7 +2645,8 @@
                             '(default), Release_x64 or "Debug".')
     group.add_argument('--builder_type', default=fetch_build.PERF_BUILDER,
                        choices=[fetch_build.PERF_BUILDER,
-                                fetch_build.FULL_BUILDER, ''],
+                                fetch_build.FULL_BUILDER,
+                                fetch_build.ANDROID_CHROME_PERF_BUILDER, ''],
                        help='Type of builder to get build from. This '
                             'determines both the bot that builds and the '
                             'place where archived builds are downloaded from. '
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index fb87ce8..dc36bef 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -315,6 +315,20 @@
     return true;
   }
 
+  bool VisitUnresolvedMemberExpr(UnresolvedMemberExpr* member) {
+    for (Decl* decl : member->decls()) {
+      if (CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl)) {
+        if (method->getParent() == receiver_->record() &&
+            Config::GetTraceMethodType(method) ==
+            Config::TRACE_AFTER_DISPATCH_METHOD) {
+          dispatched_to_receiver_ = true;
+          return true;
+        }
+      }
+    }
+    return true;
+  }
+
  private:
   RecordInfo* receiver_;
   bool dispatched_to_receiver_;
@@ -325,8 +339,12 @@
 // - A base is traced if a base-qualified call to a trace method is found.
 class CheckTraceVisitor : public RecursiveASTVisitor<CheckTraceVisitor> {
  public:
-  CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info)
-      : trace_(trace), info_(info), delegates_to_traceimpl_(false) {}
+  CheckTraceVisitor(CXXMethodDecl* trace, RecordInfo* info, RecordCache* cache)
+      : trace_(trace),
+        info_(info),
+        cache_(cache),
+        delegates_to_traceimpl_(false) {
+  }
 
   bool delegates_to_traceimpl() const { return delegates_to_traceimpl_; }
 
@@ -541,12 +559,48 @@
     if (!IsTraceCallName(func_name))
       return false;
 
-    RecordInfo::Bases::iterator iter = info_->GetBases().find(callee_record);
-    if (iter == info_->GetBases().end())
-      return false;
+    for (auto& base : info_->GetBases()) {
+      // We want to deal with omitted trace() function in an intermediary
+      // class in the class hierarchy, e.g.:
+      //     class A : public GarbageCollected<A> { trace() { ... } };
+      //     class B : public A { /* No trace(); have nothing to trace. */ };
+      //     class C : public B { trace() { B::trace(visitor); } }
+      // where, B::trace() is actually A::trace(), and in some cases we get
+      // A as |callee_record| instead of B. We somehow need to mark B as
+      // traced if we find A::trace() call.
+      //
+      // To solve this, here we keep going up the class hierarchy as long as
+      // they are not required to have a trace method. The implementation is
+      // a simple DFS, where |base_records| represents the set of base classes
+      // we need to visit.
 
-    iter->second.MarkTraced();
-    return true;
+      std::vector<CXXRecordDecl*> base_records;
+      base_records.push_back(base.first);
+
+      while (!base_records.empty()) {
+        CXXRecordDecl* base_record = base_records.back();
+        base_records.pop_back();
+
+        if (base_record == callee_record) {
+          // If we find a matching trace method, pretend the user has written
+          // a correct trace() method of the base; in the example above, we
+          // find A::trace() here and mark B as correctly traced.
+          base.second.MarkTraced();
+          return true;
+        }
+
+        if (RecordInfo* base_info = cache_->Lookup(base_record)) {
+          if (!base_info->RequiresTraceMethod()) {
+            // If this base class is not required to have a trace method, then
+            // the actual trace method may be defined in an ancestor.
+            for (auto& inner_base : base_info->GetBases())
+              base_records.push_back(inner_base.first);
+          }
+        }
+      }
+    }
+
+    return false;
   }
 
   bool CheckTraceFieldCall(CXXMemberCallExpr* call) {
@@ -609,7 +663,8 @@
   };
 
   // Nested checking for weak callbacks.
-  CheckTraceVisitor(RecordInfo* info) : trace_(0), info_(info) {}
+  CheckTraceVisitor(RecordInfo* info)
+      : trace_(nullptr), info_(info), cache_(nullptr) {}
 
   bool IsWeakCallback() { return !trace_; }
 
@@ -643,6 +698,7 @@
 
   CXXMethodDecl* trace_;
   RecordInfo* info_;
+  RecordCache* cache_;
   bool delegates_to_traceimpl_;
 };
 
@@ -1365,7 +1421,8 @@
   // Determine what type of tracing method this is (dispatch or trace).
   void CheckTraceOrDispatchMethod(RecordInfo* parent, CXXMethodDecl* method) {
     Config::TraceMethodType trace_type = Config::GetTraceMethodType(method);
-    if (trace_type != Config::TRACE_METHOD ||
+    if (trace_type == Config::TRACE_AFTER_DISPATCH_METHOD ||
+        trace_type == Config::TRACE_AFTER_DISPATCH_IMPL_METHOD ||
         !parent->GetTraceDispatchMethod()) {
       CheckTraceMethod(parent, method, trace_type);
     }
@@ -1387,7 +1444,7 @@
       }
     }
 
-    CheckTraceVisitor visitor(trace, parent);
+    CheckTraceVisitor visitor(trace, parent, &cache_);
     visitor.TraverseCXXMethodDecl(trace);
 
     // Skip reporting if this trace method is a just delegate to
diff --git a/tools/clang/blink_gc_plugin/CMakeLists.txt b/tools/clang/blink_gc_plugin/CMakeLists.txt
index c511edf..7f1dee3 100644
--- a/tools/clang/blink_gc_plugin/CMakeLists.txt
+++ b/tools/clang/blink_gc_plugin/CMakeLists.txt
@@ -1,6 +1,6 @@
 # This line is read by update.sh and other scripts in tools/clang/scripts
 # Note: The spaces are significant.
-set(LIBRARYNAME BlinkGCPlugin_14)
+set(LIBRARYNAME BlinkGCPlugin)
 
 add_llvm_loadable_module("lib${LIBRARYNAME}"
                          BlinkGCPlugin.cpp
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h
index c2d39b7..02cbee9a 100644
--- a/tools/clang/blink_gc_plugin/Config.h
+++ b/tools/clang/blink_gc_plugin/Config.h
@@ -236,7 +236,7 @@
     if (name == kTraceAfterDispatchName)
       return TRACE_AFTER_DISPATCH_METHOD;
     if (name == kTraceImplName)
-      return TRACE_AFTER_DISPATCH_METHOD;
+      return TRACE_IMPL_METHOD;
     if (name == kTraceAfterDispatchImplName)
       return TRACE_AFTER_DISPATCH_IMPL_METHOD;
 
diff --git a/tools/clang/blink_gc_plugin/Edge.h b/tools/clang/blink_gc_plugin/Edge.h
index d0b78b5..7659968 100644
--- a/tools/clang/blink_gc_plugin/Edge.h
+++ b/tools/clang/blink_gc_plugin/Edge.h
@@ -24,6 +24,7 @@
 // Bare-bones visitor.
 class EdgeVisitor {
  public:
+  virtual ~EdgeVisitor() {}
   virtual void VisitValue(Value*) {}
   virtual void VisitRawPtr(RawPtr*) {}
   virtual void VisitRefPtr(RefPtr*) {}
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp
index 0257415..bda33fa9 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.cpp
+++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -427,39 +427,50 @@
   if (Config::IsGCBase(name_))
     return;
   CXXMethodDecl* trace = nullptr;
+  CXXMethodDecl* trace_impl = nullptr;
   CXXMethodDecl* trace_after_dispatch = nullptr;
   bool has_adjust_and_mark = false;
   bool has_is_heap_object_alive = false;
-  for (CXXRecordDecl::method_iterator it = record_->method_begin();
-       it != record_->method_end();
-       ++it) {
-    switch (Config::GetTraceMethodType(*it)) {
+  for (Decl* decl : record_->decls()) {
+    CXXMethodDecl* method = dyn_cast<CXXMethodDecl>(decl);
+    if (!method) {
+      if (FunctionTemplateDecl* func_template =
+          dyn_cast<FunctionTemplateDecl>(decl))
+        method = dyn_cast<CXXMethodDecl>(func_template->getTemplatedDecl());
+    }
+    if (!method)
+      continue;
+
+    switch (Config::GetTraceMethodType(method)) {
       case Config::TRACE_METHOD:
-        trace = *it;
+        trace = method;
         break;
       case Config::TRACE_AFTER_DISPATCH_METHOD:
-        trace_after_dispatch = *it;
+        trace_after_dispatch = method;
         break;
       case Config::TRACE_IMPL_METHOD:
+        trace_impl = method;
+        break;
       case Config::TRACE_AFTER_DISPATCH_IMPL_METHOD:
         break;
       case Config::NOT_TRACE_METHOD:
-        if (it->getNameAsString() == kFinalizeName) {
-          finalize_dispatch_method_ = *it;
-        } else if (it->getNameAsString() == kAdjustAndMarkName) {
+        if (method->getNameAsString() == kFinalizeName) {
+          finalize_dispatch_method_ = method;
+        } else if (method->getNameAsString() == kAdjustAndMarkName) {
           has_adjust_and_mark = true;
-        } else if (it->getNameAsString() == kIsHeapObjectAliveName) {
+        } else if (method->getNameAsString() == kIsHeapObjectAliveName) {
           has_is_heap_object_alive = true;
         }
         break;
     }
   }
+
   // Record if class defines the two GCMixin methods.
   has_gc_mixin_methods_ =
       has_adjust_and_mark && has_is_heap_object_alive ? kTrue : kFalse;
   if (trace_after_dispatch) {
     trace_method_ = trace_after_dispatch;
-    trace_dispatch_method_ = trace;
+    trace_dispatch_method_ = trace_impl ? trace_impl : trace;
   } else {
     // TODO: Can we never have a dispatch method called trace without the same
     // class defining a traceAfterDispatch method?
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h
index 82fb604..da2f415 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.h
+++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -23,6 +23,7 @@
 class GraphPoint {
  public:
   GraphPoint() : traced_(false) {}
+  virtual ~GraphPoint() {}
   void MarkTraced() { traced_ = true; }
   bool IsProperlyTraced() { return traced_ || !NeedsTracing().IsNeeded(); }
   virtual const TracingStatus NeedsTracing() = 0;
diff --git a/tools/clang/blink_gc_plugin/tests/test.sh b/tools/clang/blink_gc_plugin/tests/test.sh
index 02c7477..95bb261 100755
--- a/tools/clang/blink_gc_plugin/tests/test.sh
+++ b/tools/clang/blink_gc_plugin/tests/test.sh
@@ -29,6 +29,7 @@
     flags="$(cat "${3}")"
   fi
   local output="$("${CLANG_PATH}" -c -Wno-c++11-extensions \
+      -Wno-inaccessible-base \
       -Xclang -load -Xclang "${PLUGIN_PATH}" \
       -Xclang -add-plugin -Xclang blink-gc-plugin ${flags} ${1} 2>&1)"
   local json="${input%cpp}graph.json"
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp
index 706624d..53a6855 100644
--- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.cpp
@@ -6,9 +6,11 @@
 
 namespace blink {
 
-void TraceAfterDispatchInlinedBase::trace(Visitor* visitor) {
-  // Implement a simple form of manual dispatching, because BlinkGCPlugin gets
-  // angry if dispatching statements are missing.
+template <typename VisitorDispatcher>
+inline void TraceAfterDispatchInlinedBase::traceImpl(
+    VisitorDispatcher visitor) {
+  // Implement a simple form of manual dispatching, because BlinkGCPlugin
+  // checks if the tracing is dispatched to all derived classes.
   //
   // This function has to be implemented out-of-line, since we need to know the
   // definition of derived classes here.
@@ -21,6 +23,15 @@
 }
 
 void TraceAfterDispatchExternBase::trace(Visitor* visitor) {
+  traceImpl(visitor);
+}
+
+void TraceAfterDispatchExternBase::trace(InlinedGlobalMarkingVisitor visitor) {
+  traceImpl(visitor);
+}
+
+template <typename VisitorDispatcher>
+inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) {
   if (tag_ == DERIVED) {
     static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch(
         visitor);
@@ -33,6 +44,11 @@
   traceAfterDispatchImpl(visitor);
 }
 
+void TraceAfterDispatchExternBase::traceAfterDispatch(
+    InlinedGlobalMarkingVisitor visitor) {
+  traceAfterDispatchImpl(visitor);
+}
+
 template <typename VisitorDispatcher>
 inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl(
     VisitorDispatcher visitor) {
@@ -43,6 +59,11 @@
   traceAfterDispatchImpl(visitor);
 }
 
+void TraceAfterDispatchExternDerived::traceAfterDispatch(
+    InlinedGlobalMarkingVisitor visitor) {
+  traceAfterDispatchImpl(visitor);
+}
+
 template <typename VisitorDispatcher>
 inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl(
     VisitorDispatcher visitor) {
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h
index e55c06e..fe25279 100644
--- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl.h
@@ -23,12 +23,19 @@
  public:
   explicit TraceAfterDispatchInlinedBase(ClassTag tag) : tag_(tag) {}
 
-  void trace(Visitor* visitor);
+  void trace(Visitor* visitor) { traceImpl(visitor); }
+  void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); }
 
   void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); }
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) {
+    traceAfterDispatchImpl(visitor);
+  }
 
  private:
   template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor);
+
+  template <typename VisitorDispatcher>
   void traceAfterDispatchImpl(VisitorDispatcher visitor) {
     visitor->trace(x_base_);
   }
@@ -42,6 +49,9 @@
   TraceAfterDispatchInlinedDerived() : TraceAfterDispatchInlinedBase(DERIVED) {}
 
   void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); }
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) {
+    traceAfterDispatchImpl(visitor);
+  }
 
  private:
   template <typename VisitorDispatcher>
@@ -59,11 +69,16 @@
   explicit TraceAfterDispatchExternBase(ClassTag tag) : tag_(tag) {}
 
   void trace(Visitor* visitor);
+  void trace(InlinedGlobalMarkingVisitor visitor);
 
   void traceAfterDispatch(Visitor* visitor);
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor);
 
  private:
   template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor);
+
+  template <typename VisitorDispatcher>
   void traceAfterDispatchImpl(VisitorDispatcher visitor);
 
   ClassTag tag_;
@@ -75,6 +90,7 @@
   TraceAfterDispatchExternDerived() : TraceAfterDispatchExternBase(DERIVED) {}
 
   void traceAfterDispatch(Visitor* visitor);
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor);
 
  private:
   template <typename VisitorDispatcher>
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp
index 1ea19364..23798f7 100644
--- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.cpp
@@ -6,24 +6,37 @@
 
 namespace blink {
 
-void TraceAfterDispatchInlinedBase::trace(Visitor* visitor) {
-  // Implement a simple form of manual dispatching, because BlinkGCPlugin gets
-  // angry if dispatching statements are missing.
+template <typename VisitorDispatcher>
+inline void TraceAfterDispatchInlinedBase::traceImpl(
+    VisitorDispatcher visitor) {
+  // Implement a simple form of manual dispatching, because BlinkGCPlugin
+  // checks if the tracing is dispatched to all derived classes.
   //
   // This function has to be implemented out-of-line, since we need to know the
   // definition of derived classes here.
   if (tag_ == DERIVED) {
-    static_cast<TraceAfterDispatchInlinedDerived*>(this)->traceAfterDispatch(
-        visitor);
+    // Missing dispatch call:
+    // static_cast<TraceAfterDispatchInlinedDerived*>(this)->traceAfterDispatch(
+    //     visitor);
   } else {
     traceAfterDispatch(visitor);
   }
 }
 
 void TraceAfterDispatchExternBase::trace(Visitor* visitor) {
+  traceImpl(visitor);
+}
+
+void TraceAfterDispatchExternBase::trace(InlinedGlobalMarkingVisitor visitor) {
+  traceImpl(visitor);
+}
+
+template <typename VisitorDispatcher>
+inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) {
   if (tag_ == DERIVED) {
-    static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch(
-        visitor);
+    // Missing dispatch call:
+    // static_cast<TraceAfterDispatchExternDerived*>(this)->traceAfterDispatch(
+    //     visitor);
   } else {
     traceAfterDispatch(visitor);
   }
@@ -33,6 +46,11 @@
   traceAfterDispatchImpl(visitor);
 }
 
+void TraceAfterDispatchExternBase::traceAfterDispatch(
+    InlinedGlobalMarkingVisitor visitor) {
+  traceAfterDispatchImpl(visitor);
+}
+
 template <typename VisitorDispatcher>
 inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl(
     VisitorDispatcher visitor) {
@@ -43,6 +61,11 @@
   traceAfterDispatchImpl(visitor);
 }
 
+void TraceAfterDispatchExternDerived::traceAfterDispatch(
+    InlinedGlobalMarkingVisitor visitor) {
+  traceAfterDispatchImpl(visitor);
+}
+
 template <typename VisitorDispatcher>
 inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl(
     VisitorDispatcher visitor) {
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h
index 441ef32..b480e39 100644
--- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.h
@@ -23,12 +23,19 @@
  public:
   explicit TraceAfterDispatchInlinedBase(ClassTag tag) : tag_(tag) {}
 
-  void trace(Visitor* visitor);
+  void trace(Visitor* visitor) { traceImpl(visitor); }
+  void trace(InlinedGlobalMarkingVisitor visitor) { traceImpl(visitor); }
 
   void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); }
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) {
+    traceAfterDispatchImpl(visitor);
+  }
 
  private:
   template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor);
+
+  template <typename VisitorDispatcher>
   void traceAfterDispatchImpl(VisitorDispatcher visitor) {
     // No trace call; should get a warning.
   }
@@ -42,6 +49,9 @@
   TraceAfterDispatchInlinedDerived() : TraceAfterDispatchInlinedBase(DERIVED) {}
 
   void traceAfterDispatch(Visitor* visitor) { traceAfterDispatchImpl(visitor); }
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor) {
+    traceAfterDispatchImpl(visitor);
+  }
 
  private:
   template <typename VisitorDispatcher>
@@ -58,11 +68,16 @@
   explicit TraceAfterDispatchExternBase(ClassTag tag) : tag_(tag) {}
 
   void trace(Visitor* visitor);
+  void trace(InlinedGlobalMarkingVisitor visitor);
 
   void traceAfterDispatch(Visitor* visitor);
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor);
 
  private:
   template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor);
+
+  template <typename VisitorDispatcher>
   void traceAfterDispatchImpl(VisitorDispatcher visitor);
 
   ClassTag tag_;
@@ -74,6 +89,7 @@
   TraceAfterDispatchExternDerived() : TraceAfterDispatchExternBase(DERIVED) {}
 
   void traceAfterDispatch(Visitor* visitor);
+  void traceAfterDispatch(InlinedGlobalMarkingVisitor visitor);
 
  private:
   template <typename VisitorDispatcher>
diff --git a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt
index 68b5a72..058fccb8 100644
--- a/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt
+++ b/tools/clang/blink_gc_plugin/tests/trace_after_dispatch_impl_error.txt
@@ -1,28 +1,34 @@
+trace_after_dispatch_impl_error.cpp:10:1: warning: [blink-gc] Missing dispatch to class 'TraceAfterDispatchInlinedDerived' in manual trace dispatch.
+inline void TraceAfterDispatchInlinedBase::traceImpl(
+^
+trace_after_dispatch_impl_error.cpp:35:1: warning: [blink-gc] Missing dispatch to class 'TraceAfterDispatchExternDerived' in manual trace dispatch.
+inline void TraceAfterDispatchExternBase::traceImpl(VisitorDispatcher visitor) {
+^
 In file included from trace_after_dispatch_impl_error.cpp:5:
-./trace_after_dispatch_impl_error.h:32:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedBase' has untraced fields that require tracing.
+./trace_after_dispatch_impl_error.h:39:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedBase' has untraced fields that require tracing.
   void traceAfterDispatchImpl(VisitorDispatcher visitor) {
   ^
-./trace_after_dispatch_impl_error.h:37:3: note: [blink-gc] Untraced field 'x_base_' declared here:
+./trace_after_dispatch_impl_error.h:44:3: note: [blink-gc] Untraced field 'x_base_' declared here:
   Member<X> x_base_;
   ^
-./trace_after_dispatch_impl_error.h:48:3: warning: [blink-gc] Base class 'TraceAfterDispatchInlinedBase' of derived class 'TraceAfterDispatchInlinedDerived' requires tracing.
+./trace_after_dispatch_impl_error.h:58:3: warning: [blink-gc] Base class 'TraceAfterDispatchInlinedBase' of derived class 'TraceAfterDispatchInlinedDerived' requires tracing.
   void traceAfterDispatchImpl(VisitorDispatcher visitor) {
   ^
-./trace_after_dispatch_impl_error.h:48:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedDerived' has untraced fields that require tracing.
-./trace_after_dispatch_impl_error.h:52:3: note: [blink-gc] Untraced field 'x_derived_' declared here:
+./trace_after_dispatch_impl_error.h:58:3: warning: [blink-gc] Class 'TraceAfterDispatchInlinedDerived' has untraced fields that require tracing.
+./trace_after_dispatch_impl_error.h:62:3: note: [blink-gc] Untraced field 'x_derived_' declared here:
   Member<X> x_derived_;
   ^
-trace_after_dispatch_impl_error.cpp:37:1: warning: [blink-gc] Class 'TraceAfterDispatchExternBase' has untraced fields that require tracing.
+trace_after_dispatch_impl_error.cpp:55:1: warning: [blink-gc] Class 'TraceAfterDispatchExternBase' has untraced fields that require tracing.
 inline void TraceAfterDispatchExternBase::traceAfterDispatchImpl(
 ^
-./trace_after_dispatch_impl_error.h:69:3: note: [blink-gc] Untraced field 'x_base_' declared here:
+./trace_after_dispatch_impl_error.h:84:3: note: [blink-gc] Untraced field 'x_base_' declared here:
   Member<X> x_base_;
   ^
-trace_after_dispatch_impl_error.cpp:47:1: warning: [blink-gc] Base class 'TraceAfterDispatchExternBase' of derived class 'TraceAfterDispatchExternDerived' requires tracing.
+trace_after_dispatch_impl_error.cpp:70:1: warning: [blink-gc] Base class 'TraceAfterDispatchExternBase' of derived class 'TraceAfterDispatchExternDerived' requires tracing.
 inline void TraceAfterDispatchExternDerived::traceAfterDispatchImpl(
 ^
-trace_after_dispatch_impl_error.cpp:47:1: warning: [blink-gc] Class 'TraceAfterDispatchExternDerived' has untraced fields that require tracing.
-./trace_after_dispatch_impl_error.h:82:3: note: [blink-gc] Untraced field 'x_derived_' declared here:
+trace_after_dispatch_impl_error.cpp:70:1: warning: [blink-gc] Class 'TraceAfterDispatchExternDerived' has untraced fields that require tracing.
+./trace_after_dispatch_impl_error.h:98:3: note: [blink-gc] Untraced field 'x_derived_' declared here:
   Member<X> x_derived_;
   ^
-6 warnings generated.
+8 warnings generated.
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp
new file mode 100644
index 0000000..b6dc2dff
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.cpp
@@ -0,0 +1,7 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "traceimpl_omitted_trace.h"
+
+// Nothing to define here.
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h
new file mode 100644
index 0000000..3c5e955
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.h
@@ -0,0 +1,47 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TRACEIMPL_OMITTED_TRACE_H_
+#define TRACEIMPL_OMITTED_TRACE_H_
+
+#include "heap/stubs.h"
+
+namespace blink {
+
+class A : public GarbageCollected<A> {
+ public:
+  virtual void trace(Visitor* visitor) { traceImpl(visitor); }
+  virtual void trace(InlinedGlobalMarkingVisitor visitor) {
+    traceImpl(visitor);
+  }
+
+ private:
+  template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor) {}
+};
+
+class B : public A {
+  // trace() isn't necessary because we've got nothing to trace here.
+};
+
+class C : public B {
+ public:
+  void trace(Visitor* visitor) override { traceImpl(visitor); }
+  void trace(InlinedGlobalMarkingVisitor visitor) override {
+    traceImpl(visitor);
+  }
+
+ private:
+  template <typename VisitorDispatcher>
+  void traceImpl(VisitorDispatcher visitor) {
+    // B::trace() is actually A::trace(), and in certain cases we only get
+    // limited information like "there is a function call that will be resolved
+    // to A::trace()". We still want to mark B as traced.
+    B::trace(visitor);
+  }
+};
+
+}
+
+#endif  // TRACEIMPL_OMITTED_TRACE_H_
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_omitted_trace.txt
@@ -0,0 +1 @@
+
diff --git a/tools/clang/scripts/blink_gc_plugin_flags.sh b/tools/clang/scripts/blink_gc_plugin_flags.sh
index 3654808..38ea72d 100755
--- a/tools/clang/scripts/blink_gc_plugin_flags.sh
+++ b/tools/clang/scripts/blink_gc_plugin_flags.sh
@@ -13,9 +13,6 @@
 else
   LIBSUFFIX=so
 fi
-LIBNAME=\
-$(grep 'set(LIBRARYNAME' "$SRC_DIR"/tools/clang/blink_gc_plugin/CMakeLists.txt \
-    | cut -d ' ' -f 2 | tr -d ')')
 
 FLAGS=""
 PREFIX="-Xclang -plugin-arg-blink-gc-plugin -Xclang"
@@ -31,5 +28,5 @@
   fi
 done
 
-echo -Xclang -load -Xclang $CLANG_LIB_PATH/lib$LIBNAME.$LIBSUFFIX \
+echo -Xclang -load -Xclang $CLANG_LIB_PATH/libBlinkGCPlugin.$LIBSUFFIX \
   -Xclang -add-plugin -Xclang blink-gc-plugin $FLAGS
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh
index e0c0fcc4..453a166 100755
--- a/tools/clang/scripts/package.sh
+++ b/tools/clang/scripts/package.sh
@@ -52,6 +52,7 @@
 LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build"
 LLVM_BIN_DIR="${LLVM_BUILD_DIR}/Release+Asserts/bin"
 LLVM_LIB_DIR="${LLVM_BUILD_DIR}/Release+Asserts/lib"
+STAMP_FILE="${LLVM_DIR}/../llvm-build/cr_build_revision"
 
 echo "Diff in llvm:" | tee buildlog.txt
 svn stat "${LLVM_DIR}" 2>&1 | tee -a buildlog.txt
@@ -86,8 +87,7 @@
 "${THIS_DIR}"/update.sh --bootstrap --force-local-build --run-tests \
     ${extra_flags} 2>&1 | tee -a buildlog.txt
 
-R=$("${LLVM_BIN_DIR}/clang" --version | \
-     sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p')
+R=$(cat "${STAMP_FILE}")
 
 PDIR=clang-$R
 rm -rf $PDIR
@@ -122,11 +122,7 @@
 # Copy plugins. Some of the dylibs are pretty big, so copy only the ones we
 # care about.
 cp "${LLVM_LIB_DIR}/libFindBadConstructs.${SO_EXT}" $PDIR/lib
-
-BLINKGCPLUGIN_LIBNAME=\
-$(grep 'set(LIBRARYNAME' "$THIS_DIR"/../blink_gc_plugin/CMakeLists.txt \
-    | cut -d ' ' -f 2 | tr -d ')')
-cp "${LLVM_LIB_DIR}/lib${BLINKGCPLUGIN_LIBNAME}.${SO_EXT}" $PDIR/lib
+cp "${LLVM_LIB_DIR}/libBlinkGCPlugin.${SO_EXT}" $PDIR/lib
 
 if [[ -n "${gcc_toolchain}" ]]; then
   # Copy the stdlibc++.so.6 we linked Clang against so it can run.
@@ -182,3 +178,5 @@
 echo To upload, run:
 echo gsutil cp -a public-read $PDIR.tgz \
      gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz
+
+# FIXME: Warn if the file already exists on the server.
diff --git a/tools/clang/scripts/plugin_flags.sh b/tools/clang/scripts/plugin_flags.sh
index 81fe0f1d..41c25c8 100755
--- a/tools/clang/scripts/plugin_flags.sh
+++ b/tools/clang/scripts/plugin_flags.sh
@@ -17,6 +17,4 @@
 fi
 
 echo -Xclang -load -Xclang $CLANG_LIB_PATH/libFindBadConstructs.$LIBSUFFIX \
-  -Xclang -add-plugin -Xclang find-bad-constructs \
-  -Xclang -plugin-arg-find-bad-constructs -Xclang check-weak-ptr-factory-order \
-  -Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
+  -Xclang -add-plugin -Xclang find-bad-constructs
diff --git a/tools/clang/scripts/repackage.sh b/tools/clang/scripts/repackage.sh
deleted file mode 100755
index e19ab7e8..0000000
--- a/tools/clang/scripts/repackage.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/bash
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This script will check out llvm and clang, build a full package
-# with the latest plugin revisions and then repackage an existing
-# clang-package with the new plugin revisions.
-
-# The new package can be uploaded to replace the existing clang
-# package at the same clang revision.
-
-THIS_DIR="$(dirname "${0}")"
-LLVM_BUILD_DIR="${THIS_DIR}/../../../third_party/llvm-build"
-LLVM_TAR_DIR="${LLVM_BUILD_DIR}/Release+Asserts"
-LLVM_BIN_DIR="${LLVM_TAR_DIR}/bin"
-LLVM_LIB_DIR="${LLVM_TAR_DIR}/lib"
-
-set -eu
-
-if [ "$(uname -s)" = "Darwin" ]; then
-  PLATFORM=Mac
-  SO_EXT="dylib"
-else
-  PLATFORM=Linux_x64
-  SO_EXT="so"
-fi
-
-# Build clang with the new plugin revisions.
-"$THIS_DIR"/package.sh $@
-
-R=$("${LLVM_BIN_DIR}/clang" --version | \
-     sed -ne 's/clang version .*(trunk \([0-9]*\))/\1/p')
-PDIR=clang-$R
-
-if [ ! -f "$PDIR.tgz" ]; then
-    echo "Could not find package archive $PDIR.tgz generated by package.sh"
-    exit 1
-fi
-
-# We don't want to change the clang binary, so fetch the current clang
-# package and add the plugin shared-libraries to the existing package.
-rm -rf $LLVM_BUILD_DIR
-"$THIS_DIR"/update.sh
-
-LIBNAME=\
-$(grep 'set(LIBRARYNAME' "$THIS_DIR"/../blink_gc_plugin/CMakeLists.txt \
-    | cut -d ' ' -f 2 | tr -d ')')
-LIBFILE=lib$LIBNAME.$SO_EXT
-
-# Check that we are actually creating the plugin at a new revision.
-if [ -f "$LLVM_LIB_DIR/$LIBFILE" ]; then
-    echo "The plugin revision $LIBNAME is already in the existing package."
-    exit 1
-fi
-
-cp $PDIR/lib/$LIBFILE "$LLVM_LIB_DIR/"
-if [ "$(uname -s)" = "Darwin" ]; then
-  tar zcf ${PDIR}_repack.tgz -C "$LLVM_TAR_DIR" bin include lib buildlog.txt
-else
-  tar zcf ${PDIR}_repack.tgz -C "$LLVM_TAR_DIR" bin lib buildlog.txt
-fi
-
-echo The clang package has been repackaged with $LIBNAME
-echo To upload, run:
-echo gsutil cp -a public-read ${PDIR}_repack.tgz \
-     gs://chromium-browser-clang/$PLATFORM/$PDIR.tgz
diff --git a/tools/clang/scripts/update.sh b/tools/clang/scripts/update.sh
index e8b929f..798f7d2 100755
--- a/tools/clang/scripts/update.sh
+++ b/tools/clang/scripts/update.sh
@@ -8,7 +8,12 @@
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
 # Reverting problematic clang rolls is safe, though.
-CLANG_REVISION=223108
+CLANG_REVISION=230914
+
+# This is incremented when pushing a new build of Clang at the same revision.
+CLANG_SUB_REVISION=1
+
+PACKAGE_VERSION="${CLANG_REVISION}-${CLANG_SUB_REVISION}"
 
 THIS_DIR="$(dirname "${0}")"
 LLVM_DIR="${THIS_DIR}/../../../third_party/llvm"
@@ -88,7 +93,7 @@
       force_local_build=yes
       ;;
     --print-revision)
-      echo $CLANG_REVISION
+      echo $PACKAGE_VERSION
       exit 0
       ;;
     --run-tests)
@@ -198,8 +203,8 @@
   PREVIOUSLY_BUILT_REVISON=$(cat "${STAMP_FILE}")
   if [[ -z "$force_local_build" ]] && \
        [[ "${PREVIOUSLY_BUILT_REVISON}" = \
-          "${CLANG_AND_PLUGINS_REVISION}" ]]; then
-    echo "Clang already at ${CLANG_AND_PLUGINS_REVISION}"
+          "${PACKAGE_VERSION}" ]]; then
+    echo "Clang already at ${PACKAGE_VERSION}"
     exit 0
   fi
 fi
@@ -211,7 +216,7 @@
   # Check if there's a prebuilt binary and if so just fetch that. That's faster,
   # and goma relies on having matching binary hashes on client and server too.
   CDS_URL=https://commondatastorage.googleapis.com/chromium-browser-clang
-  CDS_FILE="clang-${CLANG_REVISION}.tgz"
+  CDS_FILE="clang-${PACKAGE_VERSION}.tgz"
   CDS_OUT_DIR=$(mktemp -d -t clang_download.XXXXXX)
   CDS_OUTPUT="${CDS_OUT_DIR}/${CDS_FILE}"
   if [ "${OS}" = "Linux" ]; then
@@ -233,12 +238,12 @@
     rm -rf "${LLVM_BUILD_DIR}"
     mkdir -p "${LLVM_BUILD_DIR}"
     tar -xzf "${CDS_OUTPUT}" -C "${LLVM_BUILD_DIR}"
-    echo clang "${CLANG_REVISION}" unpacked
-    echo "${CLANG_AND_PLUGINS_REVISION}" > "${STAMP_FILE}"
+    echo clang "${PACKAGE_VERSION}" unpacked
+    echo "${PACKAGE_VERSION}" > "${STAMP_FILE}"
     rm -rf "${CDS_OUT_DIR}"
     exit 0
   else
-    echo Did not find prebuilt clang at r"${CLANG_REVISION}", building
+    echo Did not find prebuilt clang "${PACKAGE_VERSION}", building
   fi
 fi
 
@@ -282,6 +287,8 @@
       "${CLANG_DIR}/lib/Sema/SemaExprCXX.cpp" \
       "${CLANG_DIR}/test/SemaCXX/default2.cpp" \
       "${CLANG_DIR}/test/SemaCXX/typo-correction-delayed.cpp" \
+      "${COMPILER_RT_DIR}/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc" \
+      "${COMPILER_RT_DIR}/test/tsan/signal_segv_handler.cc" \
       ; do
   if [[ -e "${i}" ]]; then
     rm -f "${i}"  # For unversioned files.
@@ -364,349 +371,6 @@
   patch -p0
   popd
 
-  # Apply r223211: "Revert r222997."
-  pushd "${LLVM_DIR}"
-  cat << 'EOF' |
---- a/lib/Transforms/Instrumentation/MemorySanitizer.cpp
-+++ b/lib/Transforms/Instrumentation/MemorySanitizer.cpp
-@@ -921,8 +921,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
-             Value *OriginPtr =
-                 getOriginPtrForArgument(&FArg, EntryIRB, ArgOffset);
-             setOrigin(A, EntryIRB.CreateLoad(OriginPtr));
--          } else {
--            setOrigin(A, getCleanOrigin());
-           }
-         }
-         ArgOffset += RoundUpToAlignment(Size, kShadowTLSAlignment);
-@@ -942,13 +940,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
-   /// \brief Get the origin for a value.
-   Value *getOrigin(Value *V) {
-     if (!MS.TrackOrigins) return nullptr;
--    if (!PropagateShadow) return getCleanOrigin();
--    if (isa<Constant>(V)) return getCleanOrigin();
--    assert((isa<Instruction>(V) || isa<Argument>(V)) &&
--           "Unexpected value type in getOrigin()");
--    Value *Origin = OriginMap[V];
--    assert(Origin && "Missing origin");
--    return Origin;
-+    if (isa<Instruction>(V) || isa<Argument>(V)) {
-+      Value *Origin = OriginMap[V];
-+      if (!Origin) {
-+        DEBUG(dbgs() << "NO ORIGIN: " << *V << "\n");
-+        Origin = getCleanOrigin();
-+      }
-+      return Origin;
-+    }
-+    return getCleanOrigin();
-   }
- 
-   /// \brief Get the origin for i-th argument of the instruction I.
-@@ -1088,7 +1088,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
-     IRB.CreateStore(getCleanShadow(&I), ShadowPtr);
- 
-     setShadow(&I, getCleanShadow(&I));
--    setOrigin(&I, getCleanOrigin());
-   }
- 
-   void visitAtomicRMWInst(AtomicRMWInst &I) {
-EOF
-  patch -p1
-  popd
-
-  # Apply r223219: "Preserve LD_LIBRARY_PATH when using the 'env' command"
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/test/Driver/env.c
-+++ b/test/Driver/env.c
-@@ -5,12 +5,14 @@
- // REQUIRES: shell
- //
- // The PATH variable is heavily used when trying to find a linker.
--// RUN: env -i LC_ALL=C %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-+// RUN: env -i LC_ALL=C LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
-+// RUN:   %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
- // RUN:     --target=i386-unknown-linux \
- // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
- // RUN:   | FileCheck --check-prefix=CHECK-LD-32 %s
- //
--// RUN: env -i LC_ALL=C PATH="" %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
-+// RUN: env -i LC_ALL=C PATH="" LD_LIBRARY_PATH="$LD_LIBRARY_PATH" \
-+// RUN:   %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
- // RUN:     --target=i386-unknown-linux \
- // RUN:     --sysroot=%S/Inputs/basic_linux_tree \
- // RUN:   | FileCheck --check-prefix=CHECK-LD-32 %s
-EOF
-  patch -p1
-  popd
-
-  # Revert r220714: "Frontend: Define __EXCEPTIONS if -fexceptions is passed"
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Frontend/InitPreprocessor.cpp
-+++ b/lib/Frontend/InitPreprocessor.cpp
-@@ -566,7 +566,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
-     Builder.defineMacro("__BLOCKS__");
-   }
- 
--  if (!LangOpts.MSVCCompat && LangOpts.Exceptions)
-+  if (!LangOpts.MSVCCompat && LangOpts.CXXExceptions)
-     Builder.defineMacro("__EXCEPTIONS");
-   if (!LangOpts.MSVCCompat && LangOpts.RTTI)
-     Builder.defineMacro("__GXX_RTTI");
-diff --git a/test/Frontend/exceptions.c b/test/Frontend/exceptions.c
-index 981b5b9..4bbaaa3 100644
---- a/test/Frontend/exceptions.c
-+++ b/test/Frontend/exceptions.c
-@@ -1,9 +1,6 @@
--// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -DMS_MODE -verify %s
-+// RUN: %clang_cc1 -fms-compatibility -fexceptions -fcxx-exceptions -verify %s
- // expected-no-diagnostics
- 
--// RUN: %clang_cc1 -fms-compatibility -fexceptions -verify %s
--// expected-no-diagnostics
--
--#if defined(MS_MODE) && defined(__EXCEPTIONS)
-+#if defined(__EXCEPTIONS)
- #error __EXCEPTIONS should not be defined.
- #endif
-diff --git a/test/Preprocessor/predefined-exceptions.m b/test/Preprocessor/predefined-exceptions.m
-index 0791075..c13f429 100644
---- a/test/Preprocessor/predefined-exceptions.m
-+++ b/test/Preprocessor/predefined-exceptions.m
-@@ -1,6 +1,6 @@
- // RUN: %clang_cc1 -x objective-c -fobjc-exceptions -fexceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-NOCXX %s 
- // CHECK-OBJC-NOCXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
--// CHECK-OBJC-NOCXX: #define __EXCEPTIONS 1
-+// CHECK-OBJC-NOCXX-NOT: #define __EXCEPTIONS 1
- 
- // RUN: %clang_cc1 -x objective-c++ -fobjc-exceptions -fexceptions -fcxx-exceptions -E -dM %s | FileCheck -check-prefix=CHECK-OBJC-CXX %s 
- // CHECK-OBJC-CXX: #define OBJC_ZEROCOST_EXCEPTIONS 1
-EOF
-  patch -p1
-  popd
-
-  # Apply r223177: "Ensure typos in the default values of template parameters get diagnosed."
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Parse/ParseTemplate.cpp
-+++ b/lib/Parse/ParseTemplate.cpp
-@@ -676,7 +676,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
-     GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
-     EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
- 
--    DefaultArg = ParseAssignmentExpression();
-+    DefaultArg = Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression());
-     if (DefaultArg.isInvalid())
-       SkipUntil(tok::comma, tok::greater, StopAtSemi | StopBeforeMatch);
-   }
-diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
-index 1626044..c4d40b4 100644
---- a/test/SemaCXX/default2.cpp
-+++ b/test/SemaCXX/default2.cpp
-@@ -122,3 +122,9 @@ class XX {
-   void A(int length = -1 ) {  } 
-   void B() { A(); }
- };
-+
-+template <int I = (1 * I)> struct S {};  // expected-error-re {{use of undeclared identifier 'I'{{$}}}}
-+S<1> s;
-+
-+template <int I1 = I2, int I2 = 1> struct T {};  // expected-error-re {{use of undeclared identifier 'I2'{{$}}}}
-+T<0, 1> t;
-diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
-index bff1d76..7bf9258 100644
---- a/test/SemaCXX/typo-correction-delayed.cpp
-+++ b/test/SemaCXX/typo-correction-delayed.cpp
-@@ -102,3 +102,7 @@ void f(int *i) {
-   __atomic_load(i, i, something_something);  // expected-error-re {{use of undeclared identifier 'something_something'{{$}}}}
- }
- }
-+
-+const int DefaultArg = 9;  // expected-note {{'DefaultArg' declared here}}
-+template <int I = defaultArg> struct S {};  // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}}
-+S<1> s;
-EOF
-  patch -p1
-  popd
-
-  # Apply r223209: "Handle delayed corrections in a couple more error paths in ParsePostfixExpressionSuffix."
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Parse/ParseExpr.cpp
-+++ b/lib/Parse/ParseExpr.cpp
-@@ -1390,6 +1390,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
-         SourceLocation OpenLoc = ConsumeToken();
- 
-         if (ParseSimpleExpressionList(ExecConfigExprs, ExecConfigCommaLocs)) {
-+          (void)Actions.CorrectDelayedTyposInExpr(LHS);
-           LHS = ExprError();
-         }
- 
-@@ -1440,6 +1441,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
-         if (Tok.isNot(tok::r_paren)) {
-           if (ParseExpressionList(ArgExprs, CommaLocs, &Sema::CodeCompleteCall,
-                                   LHS.get())) {
-+            (void)Actions.CorrectDelayedTyposInExpr(LHS);
-             LHS = ExprError();
-           }
-         }
-diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
-index 7bf9258..f7ef015 100644
---- a/test/SemaCXX/typo-correction-delayed.cpp
-+++ b/test/SemaCXX/typo-correction-delayed.cpp
-@@ -106,3 +106,9 @@ void f(int *i) {
- const int DefaultArg = 9;  // expected-note {{'DefaultArg' declared here}}
- template <int I = defaultArg> struct S {};  // expected-error {{use of undeclared identifier 'defaultArg'; did you mean 'DefaultArg'?}}
- S<1> s;
-+
-+namespace foo {}
-+void test_paren_suffix() {
-+  foo::bar({5, 6});  // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \
-+                     // expected-error {{expected expression}}
-+}
-EOF
-  patch -p1
-  popd
-
-  # Apply r223705: "Handle possible TypoExprs in member initializers."
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Sema/SemaDeclCXX.cpp
-+++ b/lib/Sema/SemaDeclCXX.cpp
-@@ -2813,6 +2813,11 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
-                           SourceLocation IdLoc,
-                           Expr *Init,
-                           SourceLocation EllipsisLoc) {
-+  ExprResult Res = CorrectDelayedTyposInExpr(Init);
-+  if (!Res.isUsable())
-+    return true;
-+  Init = Res.get();
-+
-   if (!ConstructorD)
-     return true;
- 
-diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
-index f7ef015..d303b58 100644
---- a/test/SemaCXX/typo-correction-delayed.cpp
-+++ b/test/SemaCXX/typo-correction-delayed.cpp
-@@ -112,3 +112,10 @@ void test_paren_suffix() {
-   foo::bar({5, 6});  // expected-error-re {{no member named 'bar' in namespace 'foo'{{$}}}} \
-                      // expected-error {{expected expression}}
- }
-+
-+const int kNum = 10;  // expected-note {{'kNum' declared here}}
-+class SomeClass {
-+  int Kind;
-+public:
-+  explicit SomeClass() : Kind(kSum) {}  // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}}
-+};
-EOF
-  patch -p1
-  popd
-
-  # Apply r224172: "Typo correction: Ignore temporary binding exprs after overload resolution"
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Sema/SemaExprCXX.cpp
-+++ b/lib/Sema/SemaExprCXX.cpp
-@@ -6105,8 +6105,13 @@ public:
-     auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args,
-                                                  RParenLoc, ExecConfig);
-     if (auto *OE = dyn_cast<OverloadExpr>(Callee)) {
--      if (!Result.isInvalid() && Result.get())
--        OverloadResolution[OE] = cast<CallExpr>(Result.get())->getCallee();
-+      if (!Result.isInvalid() && Result.get()) {
-+        Expr *ResultCall = Result.get();
-+        if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall))
-+          ResultCall = BE->getSubExpr();
-+        if (auto *CE = dyn_cast<CallExpr>(ResultCall))
-+          OverloadResolution[OE] = CE->getCallee();
-+      }
-     }
-     return Result;
-   }
-diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
-index d303b58..d42888f 100644
---- a/test/SemaCXX/typo-correction-delayed.cpp
-+++ b/test/SemaCXX/typo-correction-delayed.cpp
-@@ -119,3 +119,23 @@ class SomeClass {
- public:
-   explicit SomeClass() : Kind(kSum) {}  // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}}
- };
-+
-+extern "C" int printf(const char *, ...);
-+
-+// There used to be an issue with typo resolution inside overloads.
-+struct AssertionResult {
-+  ~AssertionResult();
-+  operator bool();
-+  int val;
-+};
-+AssertionResult Compare(const char *a, const char *b);
-+AssertionResult Compare(int a, int b);
-+int main() {
-+  // expected-note@+1 {{'result' declared here}}
-+  const char *result;
-+  // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}}
-+  if (AssertionResult ar = (Compare("value1", resulta)))
-+    ;
-+  else
-+    printf("ar: %d\n", ar.val);
-+}
-EOF
-  patch -p1
-  popd
-
-  # Apply r224173: "Implement feedback on r224172 in PR21899"
-  pushd "${CLANG_DIR}"
-  cat << 'EOF' |
---- a/lib/Sema/SemaExprCXX.cpp
-+++ b/lib/Sema/SemaExprCXX.cpp
-@@ -6105,7 +6105,7 @@ public:
-     auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args,
-                                                  RParenLoc, ExecConfig);
-     if (auto *OE = dyn_cast<OverloadExpr>(Callee)) {
--      if (!Result.isInvalid() && Result.get()) {
-+      if (Result.isUsable()) {
-         Expr *ResultCall = Result.get();
-         if (auto *BE = dyn_cast<CXXBindTemporaryExpr>(ResultCall))
-           ResultCall = BE->getSubExpr();
-diff --git a/test/SemaCXX/typo-correction-delayed.cpp b/test/SemaCXX/typo-correction-delayed.cpp
-index d42888f..7879d29 100644
---- a/test/SemaCXX/typo-correction-delayed.cpp
-+++ b/test/SemaCXX/typo-correction-delayed.cpp
-@@ -120,22 +120,13 @@ public:
-   explicit SomeClass() : Kind(kSum) {}  // expected-error {{use of undeclared identifier 'kSum'; did you mean 'kNum'?}}
- };
- 
--extern "C" int printf(const char *, ...);
--
- // There used to be an issue with typo resolution inside overloads.
--struct AssertionResult {
--  ~AssertionResult();
--  operator bool();
--  int val;
--};
--AssertionResult Compare(const char *a, const char *b);
--AssertionResult Compare(int a, int b);
--int main() {
-+struct AssertionResult { ~AssertionResult(); };
-+AssertionResult Overload(const char *a);
-+AssertionResult Overload(int a);
-+void UseOverload() {
-   // expected-note@+1 {{'result' declared here}}
-   const char *result;
-   // expected-error@+1 {{use of undeclared identifier 'resulta'; did you mean 'result'?}}
--  if (AssertionResult ar = (Compare("value1", resulta)))
--    ;
--  else
--    printf("ar: %d\n", ar.val);
-+  Overload(resulta);
- }
-EOF
-  patch -p1
-  popd
-
   # This Go bindings test doesn't work after the bootstrap build on Linux. (PR21552)
   pushd "${LLVM_DIR}"
   cat << 'EOF' |
@@ -723,6 +387,7 @@
   patch -p0
   popd
 
+
 fi
 
 # Echo all commands.
@@ -975,4 +640,4 @@
 fi
 
 # After everything is done, log success for this revision.
-echo "${CLANG_AND_PLUGINS_REVISION}" > "${STAMP_FILE}"
+echo "${PACKAGE_VERSION}" > "${STAMP_FILE}"
diff --git a/tools/gn/c_include_iterator.h b/tools/gn/c_include_iterator.h
index 86c5ede..94ebca14 100644
--- a/tools/gn/c_include_iterator.h
+++ b/tools/gn/c_include_iterator.h
@@ -52,4 +52,4 @@
   DISALLOW_COPY_AND_ASSIGN(CIncludeIterator);
 };
 
-#endif  // TOOLS_GN_INCLUDE_ITERATOR_H_
+#endif  // TOOLS_GN_C_INCLUDE_ITERATOR_H_
diff --git a/tools/gn/commands.h b/tools/gn/commands.h
index dd2cb1b..239c07b5 100644
--- a/tools/gn/commands.h
+++ b/tools/gn/commands.h
@@ -173,4 +173,4 @@
 
 }  // namespace commands
 
-#endif  // TOOLS_GN_COMMANDS_H
+#endif  // TOOLS_GN_COMMANDS_H_
diff --git a/tools/gn/example/hello_shared.h b/tools/gn/example/hello_shared.h
index f62b5ee..7af804b3 100644
--- a/tools/gn/example/hello_shared.h
+++ b/tools/gn/example/hello_shared.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef HELLO_SHARED_H_
-#define HELLO_SHARED_H_
+#ifndef TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
+#define TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
 
 #if defined(WIN32)
 
@@ -17,16 +17,16 @@
 
 #else
 
-#if defined(HELLO_IMPLEMENTATION)
+#if defined(HELLO_SHARED_IMPLEMENTATION)
 #define HELLO_EXPORT __attribute__((visibility("default")))
 #define HELLO_EXPORT_PRIVATE __attribute__((visibility("default")))
 #else
 #define HELLO_EXPORT
 #define HELLO_EXPORT_PRIVATE
-#endif  // defined(HELLO_IMPLEMENTATION)
+#endif  // defined(HELLO_SHARED_IMPLEMENTATION)
 
 #endif
 
 HELLO_EXPORT const char* GetSharedText();
 
-#endif  // HELLO_SHARED_H_
+#endif  // TOOLS_GN_EXAMPLE_HELLO_SHARED_H_
diff --git a/tools/gn/example/hello_static.h b/tools/gn/example/hello_static.h
index 248ca050..f15a633 100644
--- a/tools/gn/example/hello_static.h
+++ b/tools/gn/example/hello_static.h
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef HELLO_STATIC_H_
-#define HELLO_STATIC_H_
+#ifndef TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
+#define TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
 
 const char* GetStaticText();
 
-#endif  // HELLO_STATIC_H_
+#endif  // TOOLS_GN_EXAMPLE_HELLO_STATIC_H_
diff --git a/tools/gn/ninja_build_writer.h b/tools/gn/ninja_build_writer.h
index 427b54e..6f7bf38 100644
--- a/tools/gn/ninja_build_writer.h
+++ b/tools/gn/ninja_build_writer.h
@@ -58,5 +58,5 @@
   DISALLOW_COPY_AND_ASSIGN(NinjaBuildWriter);
 };
 
-#endif  // TOOLS_GN_NINJA_BUILD_GENERATOR_H_
+#endif  // TOOLS_GN_NINJA_BUILD_WRITER_H_
 
diff --git a/tools/gn/substitution_list.h b/tools/gn/substitution_list.h
index 3a45ba8..f3e3c01 100644
--- a/tools/gn/substitution_list.h
+++ b/tools/gn/substitution_list.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef TOOLS_GN_SUBSTUTITION_LIST_H
-#define TOOLS_GN_SUBSTUTITION_LIST_H
+#ifndef TOOLS_GN_SUBSTITUTION_LIST_H_
+#define TOOLS_GN_SUBSTITUTION_LIST_H_
 
 #include <string>
 #include <vector>
@@ -43,4 +43,4 @@
   std::vector<SubstitutionType> required_types_;
 };
 
-#endif  // TOOLS_GN_SUBSTUTITION_LIST_H
+#endif  // TOOLS_GN_SUBSTITUTION_LIST_H_
diff --git a/tools/ipc_fuzzer/mutate/generate.cc b/tools/ipc_fuzzer/mutate/generate.cc
index ba3dc997..aa4b09b 100644
--- a/tools/ipc_fuzzer/mutate/generate.cc
+++ b/tools/ipc_fuzzer/mutate/generate.cc
@@ -992,7 +992,8 @@
   static bool Generate(content::SyntheticGesturePacket* p,
                        Generator* generator) {
     scoped_ptr<content::SyntheticGestureParams> gesture_params;
-    switch (RandInRange(3)) {
+    switch (RandInRange(
+        content::SyntheticGestureParams::SYNTHETIC_GESTURE_TYPE_MAX + 1)) {
       case content::SyntheticGestureParams::GestureType::
           SMOOTH_SCROLL_GESTURE: {
         content::SyntheticSmoothScrollGestureParams* params =
@@ -1008,6 +1009,18 @@
         gesture_params.reset(params);
         break;
       }
+      case content::SyntheticGestureParams::GestureType::SMOOTH_DRAG_GESTURE: {
+        content::SyntheticSmoothDragGestureParams* params =
+            new content::SyntheticSmoothDragGestureParams();
+        if (!GenerateParam(&params->start_point, generator))
+          return false;
+        if (!GenerateParam(&params->distances, generator))
+          return false;
+        if (!GenerateParam(&params->speed_in_pixels_s, generator))
+          return false;
+        gesture_params.reset(params);
+        break;
+      }
       case content::SyntheticGestureParams::GestureType::PINCH_GESTURE: {
         content::SyntheticPinchGestureParams* params =
             new content::SyntheticPinchGestureParams();
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 79775fa..469d2a6d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -6488,6 +6488,80 @@
   </summary>
 </histogram>
 
+<histogram name="EasyUnlock.AuthProximity.RemoteDeviceModelHash"
+    enum="EasyUnlockDeviceModelHash">
+  <owner>tengs@chromium.org</owner>
+  <owner>xiaowenx@chromium.org</owner>
+  <summary>
+    The hash of the phone model used to successfully sign in or unlock using
+    Smart Lock.
+  </summary>
+  <details>
+    This hash is calculated by taking the first 4 bytes of the MD5 hash of the
+    device model.
+  </details>
+</histogram>
+
+<histogram name="EasyUnlock.AuthProximity.RollingRssi" units="dBm">
+  <owner>tengs@chromium.org</owner>
+  <owner>xiaowenx@chromium.org</owner>
+  <summary>
+    Measures the exponentially weighted rolling average of the received signal
+    strength indicator (RSSI) of the phone when the user successfully unlocks or
+    signs in using Smart Lock.
+  </summary>
+  <details>
+    The exponentially weighted averaging formula is:
+
+      rollingRssi = (1 - weight) * rollingRssi + weight * currentRssi;
+
+    RSSI readings are inherently noisy, so this averaging gives a smoothed RSSI
+    value to work with as a heuristic for proximity.
+
+    If no RSSI was read, then a sentinel value of 127 will be recorded.
+  </details>
+</histogram>
+
+<histogram name="EasyUnlock.AuthProximity.TimeSinceLastZeroRssi"
+    units="milliseconds">
+  <owner>tengs@chromium.org</owner>
+  <owner>xiaowenx@chromium.org</owner>
+  <summary>
+    Measures the time delta in milliseconds since the last zero RSSI value was
+    read to when the user successfully unlocks or signs in using Smart Lock.
+  </summary>
+  <details>
+    A zero RSSI value is special because both Bluetooth devices in a connection
+    attempt to maintain by adjusting their transmit power levels. This time
+    delta can be used as a possible heuristic to determine that the phone is
+    close to the local device.
+
+    If no RSSI was read, then an overflow value will be recorded.
+  </details>
+</histogram>
+
+<histogram name="EasyUnlock.AuthProximity.TransmitPowerDelta" units="dBm">
+  <owner>tengs@chromium.org</owner>
+  <owner>xiaowenx@chromium.org</owner>
+  <summary>
+    Measures the difference between the current transmit power and the maximum
+    transmit power of the local device when the user successfully unlocks or
+    signs in using Smart Lock.
+  </summary>
+  <details>
+    Devices connected using classic Bluetooth adjust their transmit power
+    dynamically to optimize power and signal strength. The difference between
+    the current transmit power and maximum transmit power can be used as a
+    heurstic to determine if the phone is close to the local device.
+
+    According to the Bluetooth specs, there are three classes of devices, with a
+    maximum transmit power of 20, 4, and 0 dBm respectively.
+
+    If no transmit power was read, then a sentinel value of 127 will be
+    recorded.
+  </details>
+</histogram>
+
 <histogram name="EasyUnlock.ClickedButton" enum="EasyUnlockButton">
   <owner>joshwoodward@google.com</owner>
   <owner>tbarzic@chromium.org</owner>
@@ -8368,6 +8442,16 @@
   </summary>
 </histogram>
 
+<histogram name="Extensions.BadMessageFunctionName" enum="ExtensionFunctions">
+  <owner>kalman@chromium.org</owner>
+  <summary>
+    The number of times each Extension function call sends a bad message,
+    killing the renderer. This may indicate a bug in that API's implementation
+    on the renderer. Note a similar, aggregate metric is BadMessageTerminate_EFD
+    which counts the number of bad messages that are sent overall.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.CheckForExternalUpdatesTime">
   <owner>rkaplow@chromium.org</owner>
   <summary>
@@ -33448,6 +33532,14 @@
   </summary>
 </histogram>
 
+<histogram name="Session.TotalDuration" units="milliseconds">
+  <owner>mariakhomenko@chromium.org</owner>
+  <owner>fqian@chromium.org</owner>
+  <summary>
+    The length of a session (launch/foregrounding to backgrounding) on mobile.
+  </summary>
+</histogram>
+
 <histogram name="SessionCrashed.Bubble" enum="SessionCrashedBubbleUserAction">
   <owner>yiyaoliu@chromium.org</owner>
   <summary>How did the user interact with the SessionCrashed Bubble?</summary>
@@ -37644,6 +37736,33 @@
   </summary>
 </histogram>
 
+<histogram name="Startup.PreMainMessageLoopRunImplStep1Time"
+    units="milliseconds">
+  <owner>rkaplow@chromium.org</owner>
+  <summary>
+    The amount of time that elapsed during the first untracked section of
+    ChromeBrowserMainParts::PreMainMessageLoopRunImpl.
+  </summary>
+</histogram>
+
+<histogram name="Startup.PreMainMessageLoopRunImplStep2Time"
+    units="milliseconds">
+  <owner>rkaplow@chromium.org</owner>
+  <summary>
+    The amount of time that elapsed during the second untracked section of
+    ChromeBrowserMainParts::PreMainMessageLoopRunImpl. Not written for Android.
+  </summary>
+</histogram>
+
+<histogram name="Startup.PreMainMessageLoopRunImplStep3Time"
+    units="milliseconds">
+  <owner>rkaplow@chromium.org</owner>
+  <summary>
+    The amount of time that elapsed during the third untracked section of
+    ChromeBrowserMainParts::PreMainMessageLoopRunImpl. Not written for Android.
+  </summary>
+</histogram>
+
 <histogram name="Startup.PreMainMessageLoopRunImplTime" units="milliseconds">
   <obsolete>
     Deprecated as of 2/2015.
@@ -41145,8 +41264,8 @@
   <owner>ulan@chromium.org</owner>
   <summary>
     Number of garbage collections that a detached global context survives,
-    recorded after each major garbage collection.
-    Values greater than 7 indicate a memory leak.
+    recorded after each major garbage collection. Values greater than 7 indicate
+    a memory leak.
   </summary>
 </histogram>
 
@@ -43706,6 +43825,16 @@
   <summary>Number of times that each menu item is clicked.</summary>
 </histogram>
 
+<histogram name="WrenchMenu.OpeningAnimationFrameTimes" units="milliseconds">
+  <owner>kkimlabs@chromium.org</owner>
+  <summary>
+    Frame times of Android wrench menu opening animation. For example, if the
+    menu opening animation ran exactly at 60fps for a second, then each frame
+    time is 16ms. Therefore total ~60 number of 16ms value will be recorded. If
+    the anmation was janky, we will see >16ms data points in the histogram.
+  </summary>
+</histogram>
+
 <histogram name="WrenchMenu.RecentTabsSubMenu" enum="RecentTabsAction">
   <owner>rpop@chromium.org</owner>
   <summary>
@@ -43723,7 +43852,7 @@
 </histogram>
 
 <histogram name="WrenchMenu.TouchDuration" units="milliseconds">
-  <owner>kkimlabs@google.com</owner>
+  <owner>kkimlabs@chromium.org</owner>
   <summary>
     Time difference between touch down and touch up on Android wrench button.
   </summary>
@@ -46615,6 +46744,13 @@
   <int value="9" label="No recent updates"/>
 </enum>
 
+<enum name="EasyUnlockDeviceModelHash" type="int">
+  <int value="-1168032746" label="Motorola Nexus 6"/>
+  <int value="-617422855" label="LGE Nexus 4"/>
+  <int value="1286382027" label="Motorola XT1095"/>
+  <int value="1881443083" label="LGE Nexus 5"/>
+</enum>
+
 <enum name="EasyUnlockHasSecureScreenLock" type="int">
   <int value="0" label="Lacks secure screen lock"/>
   <int value="1" label="Has secure screen lock"/>
diff --git a/tools/perf/benchmarks/draw_properties.py b/tools/perf/benchmarks/draw_properties.py
index 9ac9ff2..aa0e12d0 100644
--- a/tools/perf/benchmarks/draw_properties.py
+++ b/tools/perf/benchmarks/draw_properties.py
@@ -8,6 +8,7 @@
 import page_sets
 
 
+@benchmark.Disabled()  # http://crbug.com/463111
 class DrawPropertiesToughScrolling(benchmark.Benchmark):
   test = draw_properties.DrawProperties
   page_set = page_sets.ToughScrollingCasesPageSet
@@ -15,6 +16,8 @@
   def Name(cls):
     return 'draw_properties.tough_scrolling'
 
+
+@benchmark.Disabled()  # http://crbug.com/463111
 class DrawPropertiesTop25(benchmark.Benchmark):
   """Measures the relative performance of CalcDrawProperties vs computing draw
   properties from property trees.
diff --git a/tools/perf/benchmarks/page_cycler.py b/tools/perf/benchmarks/page_cycler.py
index c4837d0f..7655255 100644
--- a/tools/perf/benchmarks/page_cycler.py
+++ b/tools/perf/benchmarks/page_cycler.py
@@ -195,7 +195,7 @@
     return 'page_cycler.tough_layout_cases'
 
 
-# crbug.com/273986: This test is really flakey on xp.
+# crbug.com/273986: This test is flakey on Windows.
 @benchmark.Disabled('win')
 class PageCyclerTypical25(_PageCycler):
   """Page load time benchmark for a 25 typical web pages.
@@ -211,6 +211,21 @@
   def CreatePageSet(self, options):
     return page_sets.Typical25PageSet(run_no_page_interactions=True)
 
+# crbug.com/273986: This test is flakey on Windows.
+@benchmark.Disabled  # crbug.com/463346: Test is crashing Chrome.
+class PageCyclerOopifTypical25(_PageCycler):
+  """ A varation of the benchmark above, but running in --site-per-process
+  to allow measuring performance of out-of-process iframes.
+  """
+  @classmethod
+  def Name(cls):
+    return 'page_cycler_oopif.typical_25'
+
+  def CustomizeBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs(['--site-per-process'])
+
+  def CreatePageSet(self, options):
+    return page_sets.Typical25PageSet(run_no_page_interactions=True)
 
 @benchmark.Disabled # crbug.com/443730
 class PageCyclerBigJs(_PageCycler):
@@ -218,4 +233,3 @@
   @classmethod
   def Name(cls):
     return 'page_cycler.big_js'
-
diff --git a/tools/perf/benchmarks/rasterize_and_record_micro.py b/tools/perf/benchmarks/rasterize_and_record_micro.py
index 81b450ec..88ddaad2 100644
--- a/tools/perf/benchmarks/rasterize_and_record_micro.py
+++ b/tools/perf/benchmarks/rasterize_and_record_micro.py
@@ -46,7 +46,7 @@
   """Measures rasterize and record performance on the top 25 web pages.
 
   http://www.chromium.org/developers/design-documents/rendering-benchmarks"""
-  page_set = page_sets.Top25SmoothPageSet
+  page_set = page_sets.Top25PageSet
 
   @classmethod
   def Name(cls):
diff --git a/tools/perf/page_sets/data/top_25_smooth.json b/tools/perf/page_sets/data/top_25_smooth.json
new file mode 100644
index 0000000..59fb8ed
--- /dev/null
+++ b/tools/perf/page_sets/data/top_25_smooth.json
@@ -0,0 +1,40 @@
+{
+    "description": "Describes the Web Page Replay archives for a page set. Don't edit by hand! Use record_wpr for updating.", 
+    "archives": {
+        "top_25_003.wpr": [
+            "Facebook"
+        ], 
+        "top_25_001.wpr": [
+            "https://plus.google.com/110031535020051778989/posts"
+        ], 
+        "top_25_002.wpr": [
+            "https://www.google.com/search?q=cats&tbm=isch"
+        ], 
+        "top_25_000.wpr": [
+            "https://www.google.com/#hl=en&q=barack+obama", 
+            "https://mail.google.com/mail/", 
+            "https://www.google.com/calendar/", 
+            "https://drive.google.com", 
+            "https://docs.google.com/document/d/1X-IKNjtEnx-WW5JIKRLsyhz5sbsat3mfTpAPUSX3_s4/view", 
+            "http://www.youtube.com", 
+            "http://googlewebmastercentral.blogspot.com/", 
+            "http://en.blog.wordpress.com/2012/09/04/freshly-pressed-editors-picks-for-august-2012/", 
+            "http://www.facebook.com/barackobama", 
+            "http://www.linkedin.com/in/linustorvalds", 
+            "http://en.wikipedia.org/wiki/Wikipedia", 
+            "https://twitter.com/katyperry", 
+            "http://pinterest.com", 
+            "http://espn.go.com", 
+            "http://news.yahoo.com", 
+            "http://www.cnn.com", 
+            "http://www.weather.com/weather/right-now/Mountain+View+CA+94043", 
+            "http://www.amazon.com", 
+            "http://www.ebay.com", 
+            "http://games.yahoo.com", 
+            "http://booking.com", 
+            "http://answers.yahoo.com", 
+            "http://sports.yahoo.com/", 
+            "http://techcrunch.com"
+        ]
+    }
+}
\ No newline at end of file
diff --git a/tools/perf/page_sets/top_25_pages.py b/tools/perf/page_sets/top_25_pages.py
new file mode 100644
index 0000000..c6ba4cd
--- /dev/null
+++ b/tools/perf/page_sets/top_25_pages.py
@@ -0,0 +1,59 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+from telemetry.page import page
+from telemetry.page import page_set
+
+from page_sets import top_pages
+
+
+class Top25PageSet(page_set.PageSet):
+
+  """ Page set consists of top 25 pages with only navigation actions. """
+
+  def __init__(self):
+    super(Top25PageSet, self).__init__(
+        user_agent_type='desktop',
+        archive_data_file='data/top_25.json',
+        bucket=page_set.PARTNER_BUCKET)
+
+    self.AddUserStory(top_pages.GoogleWebSearchPage(self))
+    self.AddUserStory(top_pages.GmailPage(self))
+    self.AddUserStory(top_pages.GoogleCalendarPage(self))
+    self.AddUserStory(top_pages.GoogleImageSearchPage(self))
+    self.AddUserStory(top_pages.GoogleDocPage(self))
+    self.AddUserStory(top_pages.GooglePlusPage(self))
+    self.AddUserStory(top_pages.YoutubePage(self))
+    self.AddUserStory(top_pages.BlogspotPage(self))
+    self.AddUserStory(top_pages.WordpressPage(self))
+    self.AddUserStory(top_pages.FacebookPage(self))
+    self.AddUserStory(top_pages.LinkedinPage(self))
+    self.AddUserStory(top_pages.WikipediaPage(self))
+    self.AddUserStory(top_pages.TwitterPage(self))
+    self.AddUserStory(top_pages.PinterestPage(self))
+    self.AddUserStory(top_pages.ESPNPage(self))
+    self.AddUserStory(top_pages.WeatherPage(self))
+    self.AddUserStory(top_pages.YahooGamesPage(self))
+
+    other_urls = [
+        # Why: #1 news worldwide (Alexa global)
+        'http://news.yahoo.com',
+        # Why: #2 news worldwide
+        'http://www.cnn.com',
+        # Why: #1 world commerce website by visits; #3 commerce in the US by
+        # time spent
+        'http://www.amazon.com',
+        # Why: #1 commerce website by time spent by users in US
+        'http://www.ebay.com',
+        # Why: #1 Alexa recreation
+        'http://booking.com',
+        # Why: #1 Alexa reference
+        'http://answers.yahoo.com',
+        # Why: #1 Alexa sports
+        'http://sports.yahoo.com/',
+        # Why: top tech blog
+        'http://techcrunch.com'
+    ]
+
+    for url in other_urls:
+      self.AddUserStory(page.Page(url, self))
diff --git a/tools/perf/page_sets/top_25_smooth.py b/tools/perf/page_sets/top_25_smooth.py
index cf5d8fc0..5088a82 100644
--- a/tools/perf/page_sets/top_25_smooth.py
+++ b/tools/perf/page_sets/top_25_smooth.py
@@ -93,7 +93,7 @@
   def __init__(self):
     super(Top25SmoothPageSet, self).__init__(
         user_agent_type='desktop',
-        archive_data_file='data/top_25.json',
+        archive_data_file='data/top_25_smooth.json',
         bucket=page_set_module.PARTNER_BUCKET)
 
     self.AddUserStory(_CreatePageClassWithSmoothInteractions(
diff --git a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
index b8483be1..59cc374 100644
--- a/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome_inspector/inspector_backend.py
@@ -17,7 +17,6 @@
 from telemetry.core.backends.chrome_inspector import inspector_runtime
 from telemetry.core.backends.chrome_inspector import inspector_websocket
 from telemetry.core.backends.chrome_inspector import websocket
-from telemetry.core.heap import model as heap_model_module
 from telemetry.image_processing import image_util
 from telemetry.timeline import model as timeline_model_module
 from telemetry.timeline import trace_data as trace_data_module
@@ -240,25 +239,3 @@
       self._page.CollectGarbage()
     except (socket.error, websocket.WebSocketException) as e:
       self._HandleError(e)
-
-  def TakeJSHeapSnapshot(self, timeout=120):
-    snapshot = []
-
-    def OnNotification(res):
-      if res['method'] == 'HeapProfiler.addHeapSnapshotChunk':
-        snapshot.append(res['params']['chunk'])
-
-    try:
-      self._websocket.RegisterDomain('HeapProfiler', OnNotification)
-
-      self._websocket.SyncRequest({'method': 'Page.getResourceTree'}, timeout)
-      self._websocket.SyncRequest({'method': 'Debugger.enable'}, timeout)
-      self._websocket.SyncRequest(
-          {'method': 'HeapProfiler.takeHeapSnapshot'}, timeout)
-    except (socket.error, websocket.WebSocketException) as e:
-      self._HandleError(e)
-
-    snapshot = ''.join(snapshot)
-
-    self.UnregisterDomain('HeapProfiler')
-    return heap_model_module.Model(snapshot)
diff --git a/tools/telemetry/telemetry/core/heap/__init__.py b/tools/telemetry/telemetry/core/heap/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tools/telemetry/telemetry/core/heap/__init__.py
+++ /dev/null
diff --git a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py b/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py
deleted file mode 100644
index 9706dad..0000000
--- a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser.py
+++ /dev/null
@@ -1,248 +0,0 @@
-# Copyright 2013 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 json
-
-from telemetry.core.heap import live_heap_object
-from telemetry.core.heap import retaining_edge
-
-
-class ChromeJsHeapSnapshotParser(object):
-  """ Parser for the heap snapshot.
-
-  The heap snapshot JSON format is defined by HeapSnapshotJSONSerializer in V8.
-
-  The snapshot contains a list of integers describing nodes (types, names, etc.)
-  and a list of integers describing edges (types, the node the edge points to,
-  etc.) and a string table. All strings are expressed as indices to the string
-  table.
-
-  In addition, the snapshot contains meta information describing the data fields
-  for nodes and the data fields for edges.
-
-  Attributes:
-    _node_dict: {int -> LiveHeapObject}, maps integer ids to LiveHeapObject
-        objects.
-    _node_list: [int], the raw node data of the heap snapshot.
-    _edge_list: [int], the raw edge data of the heap snapshot.
-    _node_types: [str], the possible node types in the heap snapshot.
-    _edge_types: [str], the possible edge types in the heap snapshot.
-    _node_fields: [str], the fields present in the heap snapshot for each node.
-    _edge_fields: [str], the fields present in the heap snapshot for each node.
-    _node_type_ix: int, index of the node type field.
-    _node_name_ix: int, index of the node name field.
-    _node_id_ix: int, index of the node id field.
-    _node_edge_count_ix: int, index of the node edge count field.
-    _node_field_count: int, number of node fields.
-    _edge_type_ix: int, index of the edge type field.
-    _edge_name_or_ix_ix: int, index of the "edge name or index" field.
-    _edge_to_node_ix: int, index of the "to node for an edge" field.
-    _edge_field_count: int, number of edge fields.
-  """
-
-  def __init__(self, raw_data):
-    heap = json.loads(raw_data)
-    self._node_dict = {}
-
-    # Read the snapshot components (nodes, edges, strings, metadata).
-    self._node_list = heap['nodes']
-    self._edge_list = heap['edges']
-    self._strings = heap['strings']
-
-    self._node_types = heap['snapshot']['meta']['node_types'][0]
-    self._edge_types = heap['snapshot']['meta']['edge_types'][0]
-    node_fields = heap['snapshot']['meta']['node_fields']
-    edge_fields = heap['snapshot']['meta']['edge_fields']
-
-    # Find the indices of the required node and edge fields based on the
-    # metadata.
-    self._node_type_ix = node_fields.index('type')
-    self._node_name_ix = node_fields.index('name')
-    self._node_id_ix = node_fields.index('id')
-    self._node_edge_count_ix = node_fields.index('edge_count')
-    self._node_field_count = len(node_fields)
-
-    self._edge_type_ix = edge_fields.index('type')
-    self._edge_name_or_ix_ix = edge_fields.index('name_or_index')
-    self._edge_to_node_ix = edge_fields.index('to_node')
-    self._edge_field_count = len(edge_fields)
-
-    self._ParseSnapshot()
-
-  @staticmethod
-  def CanImport(raw_data):
-    heap = json.loads(raw_data)
-    if ('nodes' not in heap or 'edges' not in heap or 'strings' not in heap or
-        'snapshot' not in heap or 'meta' not in heap['snapshot']):
-      return False
-    meta = heap['snapshot']['meta']
-    if ('node_types' not in meta or 'edge_types' not in meta or
-        'node_fields' not in meta or 'edge_fields' not in meta):
-      return False
-    node_fields = meta['node_fields']
-    edge_fields = meta['edge_fields']
-    if ('type' not in node_fields or 'name' not in node_fields or
-        'id' not in node_fields or 'edge_count' not in node_fields):
-      return False
-    if ('type' not in edge_fields or 'name_or_index' not in edge_fields or
-        'to_node' not in edge_fields):
-      return False
-    return True
-
-  def GetAllLiveHeapObjects(self):
-    return self._node_dict.values()
-
-  @staticmethod
-  def LiveHeapObjectToJavaScript(heap_object):
-    return heap_object.name or str(heap_object)
-
-  @staticmethod
-  def RetainingEdgeToJavaScript(edge):
-    if edge.type_string == 'property':
-      return '.' + edge.name_string
-    if edge.type_string == 'element':
-      return '[' + edge.name_string + ']'
-    return str(edge)
-
-  def _ParseSnapshot(self):
-    """Parses the stored JSON snapshot data.
-
-    Fills in self._node_dict with LiveHeapObject objects constructed based on
-    the heap snapshot. The LiveHeapObject objects contain the associated
-    RetainingEdge objects.
-    """
-    edge_start_ix = 0
-    for ix in xrange(0, len(self._node_list), self._node_field_count):
-      edge_start_ix = self._ReadNodeFromIndex(ix, edge_start_ix)
-
-    # Add pointers to the endpoints to the edges, and associate the edges with
-    # the "to" nodes.
-    for node_id in self._node_dict:
-      n = self._node_dict[node_id]
-      for e in n.edges_from:
-        self._node_dict[e.to_object_id].AddEdgeTo(e)
-        e.SetFromObject(n)
-        e.SetToObject(self._node_dict[e.to_object_id])
-
-  def _ReadNodeFromIndex(self, ix, edges_start):
-    """Reads the data for a node from the heap snapshot.
-
-    If the index contains an interesting node, constructs a Node object and adds
-    it to self._node_dict.
-
-    Args:
-      ix: int, index into the self._node_list array.
-      edges_start: int, the index of the edge array where the edges for the node
-          start.
-    Returns:
-      int, the edge start index for the next node.
-
-    Raises:
-      Exception: The node list of the snapshot is malformed.
-    """
-    if ix + self._node_field_count > len(self._node_list):
-      raise Exception('Snapshot node list too short')
-
-    type_ix = self._node_list[ix + self._node_type_ix]
-    type_string = self._node_types[int(type_ix)]
-
-    # edges_end is noninclusive (the index of the first edge that is not part of
-    # this node).
-    edge_count = self._node_list[ix + self._node_edge_count_ix]
-    edges_end = edges_start + edge_count * self._edge_field_count
-
-    if ChromeJsHeapSnapshotParser._IsNodeTypeUninteresting(type_string):
-      return edges_end
-
-    name_ix = self._node_list[ix + self._node_name_ix]
-    node_id = self._node_list[ix + self._node_id_ix]
-
-    def ConstructorName(type_string, node_name_ix):
-      if type_string == 'object':
-        return self._strings[int(node_name_ix)]
-      return '(%s)' % type_string
-
-    ctor_name = ConstructorName(type_string, name_ix)
-    n = live_heap_object.LiveHeapObject(node_id, type_string, ctor_name)
-    if type_string == 'string':
-      n.string = self._strings[int(name_ix)]
-
-    for edge_ix in xrange(edges_start, edges_end, self._edge_field_count):
-      edge = self._ReadEdgeFromIndex(node_id, edge_ix)
-      if edge:
-        # The edge will be associated with the other endpoint when all the data
-        # has been read.
-        n.AddEdgeFrom(edge)
-
-    self._node_dict[node_id] = n
-    return edges_end
-
-  @staticmethod
-  def _IsNodeTypeUninteresting(type_string):
-    """Helper function for filtering out nodes from the heap snapshot.
-
-    Args:
-      type_string: str, type of the node.
-    Returns:
-      bool, True if the node is of an uninteresting type and shouldn't be
-          included in the heap snapshot analysis.
-    """
-    uninteresting_types = ('hidden', 'code', 'number', 'native', 'synthetic')
-    return type_string in uninteresting_types
-
-  @staticmethod
-  def _IsEdgeTypeUninteresting(edge_type_string):
-    """Helper function for filtering out edges from the heap snapshot.
-
-    Args:
-      edge_type_string: str, type of the edge.
-    Returns:
-      bool, True if the edge is of an uninteresting type and shouldn't be
-          included in the heap snapshot analysis.
-    """
-    uninteresting_types = ('weak', 'hidden', 'internal')
-    return edge_type_string in uninteresting_types
-
-  def _ReadEdgeFromIndex(self, node_id, edge_ix):
-    """Reads the data for an edge from the heap snapshot.
-
-    Args:
-      node_id: int, id of the node which is the starting point of the edge.
-      edge_ix: int, index into the self._edge_list array.
-    Returns:
-      Edge, if the index contains an interesting edge, otherwise None.
-    Raises:
-      Exception: The node list of the snapshot is malformed.
-    """
-    if edge_ix + self._edge_field_count > len(self._edge_list):
-      raise Exception('Snapshot edge list too short')
-
-    edge_type_ix = self._edge_list[edge_ix + self._edge_type_ix]
-    edge_type_string = self._edge_types[int(edge_type_ix)]
-
-    if ChromeJsHeapSnapshotParser._IsEdgeTypeUninteresting(edge_type_string):
-      return None
-
-    child_name_or_ix = self._edge_list[edge_ix + self._edge_name_or_ix_ix]
-    child_node_ix = self._edge_list[edge_ix + self._edge_to_node_ix]
-
-    # The child_node_ix is an index into the node list. Read the actual
-    # node information.
-    child_node_type_ix = self._node_list[child_node_ix + self._node_type_ix]
-    child_node_type_string = self._node_types[int(child_node_type_ix)]
-    child_node_id = self._node_list[child_node_ix + self._node_id_ix]
-
-    if ChromeJsHeapSnapshotParser._IsNodeTypeUninteresting(
-        child_node_type_string):
-      return None
-
-    child_name_string = ''
-    # For element nodes, the child has no name (only an index).
-    if (edge_type_string == 'element' or
-        int(child_name_or_ix) >= len(self._strings)):
-      child_name_string = str(child_name_or_ix)
-    else:
-      child_name_string = self._strings[int(child_name_or_ix)]
-    return retaining_edge.RetainingEdge(node_id, child_node_id,
-                                        edge_type_string, child_name_string)
diff --git a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py b/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py
deleted file mode 100644
index 94bb49a..0000000
--- a/tools/telemetry/telemetry/core/heap/chrome_js_heap_snapshot_parser_unittest.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2013 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 json
-import unittest
-
-from telemetry.core.heap import chrome_js_heap_snapshot_parser
-
-
-class ChromeJsHeapSnapshotParserUnittest(unittest.TestCase):
-  def _HeapSnapshotData(self, node_types, edge_types, node_fields, edge_fields,
-                        node_list, edge_list, strings):
-    """Helper for creating heap snapshot data."""
-    return {'snapshot': {'meta': {'node_types': [node_types],
-                                  'edge_types': [edge_types],
-                                  'node_fields': node_fields,
-                                  'edge_fields': edge_fields}},
-            'nodes': node_list,
-            'edges': edge_list,
-            'strings': strings}
-
-  def testParseSimpleSnapshot(self):
-    # Create a snapshot containing 2 nodes and an edge between them.
-    node_types = ['object']
-    edge_types = ['property']
-    node_fields = ['type', 'name', 'id', 'edge_count']
-    edge_fields = ['type', 'name_or_index', 'to_node']
-    node_list = [0, 0, 0, 1,
-                 0, 1, 1, 0]
-    edge_list = [0, 2, 4]
-    strings = ['node1', 'node2', 'edge1']
-    heap = self._HeapSnapshotData(node_types, edge_types, node_fields,
-                                  edge_fields, node_list, edge_list, strings)
-    objects = list(chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser(
-        json.dumps(heap)).GetAllLiveHeapObjects())
-    self.assertEqual(2, len(objects))
-    if objects[0].edges_from:
-      from_ix = 0
-      to_ix = 1
-    else:
-      from_ix = 1
-      to_ix = 0
-    self.assertEqual('node1', objects[from_ix].class_name)
-    self.assertEqual('node2', objects[to_ix].class_name)
-    self.assertEqual(1, len(objects[from_ix].edges_from))
-    self.assertEqual(0, len(objects[from_ix].edges_to))
-    self.assertEqual(0, len(objects[to_ix].edges_from))
-    self.assertEqual(1, len(objects[to_ix].edges_to))
-    self.assertEqual('node1',
-                     objects[from_ix].edges_from[0].from_object.class_name)
-    self.assertEqual('node2',
-                     objects[from_ix].edges_from[0].to_object.class_name)
-    self.assertEqual('edge1', objects[from_ix].edges_from[0].name_string)
-    self.assertEqual('node1', objects[to_ix].edges_to[0].from_object.class_name)
-    self.assertEqual('node2', objects[to_ix].edges_to[0].to_object.class_name)
-    self.assertEqual('edge1', objects[to_ix].edges_to[0].name_string)
diff --git a/tools/telemetry/telemetry/core/heap/live_heap_object.py b/tools/telemetry/telemetry/core/heap/live_heap_object.py
deleted file mode 100644
index c8be3df..0000000
--- a/tools/telemetry/telemetry/core/heap/live_heap_object.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2013 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.
-
-class LiveHeapObject(object):
-  """Data structure for representing an object in the heap snapshot.
-
-  Attributes:
-    object_id: int, identifier for the object.
-    type_string: str, describes the type of the node.
-    class_name: str, describes the class of the JavaScript object
-        represented by this LiveHeapObject.
-    edges_to: [RetainingEdge], edges whose end point this LiveHeapObject is.
-    edges_from: [RetainingEdge], edges whose start point this LiveHeapObject is.
-    string: str, for string LiveHeapObjects, contains the string the
-        LiveHeapObject represents. Empty string for LiveHeapObjects which are
-        not strings.
-    name: str, how to refer to this LiveHeapObject.
-  """
-
-  def __init__(self, object_id, type_string, class_name):
-    """Initializes the LiveHeapObject object.
-
-    Args:
-      object_id: int, identifier for the LiveHeapObject.
-      type_string: str, the type of the node.
-      class_name: str, the class of the object this LiveHeapObject represents.
-    """
-    self.object_id = object_id
-    self.type_string = type_string
-    self.class_name = class_name
-    self.edges_to = []
-    self.edges_from = []
-    self.string = ''
-    self.name = ''
-
-  def AddEdgeTo(self, edge):
-    """Associates an Edge with the LiveHeapObject (the end point).
-
-    Args:
-      edge: Edge, an edge whose end point this LiveHeapObject is.
-    """
-    self.edges_to.append(edge)
-
-  def AddEdgeFrom(self, edge):
-    """Associates an Edge with the LiveHeapObject (the start point).
-
-    Args:
-      edge: Edge, an edge whose start point this LiveHeapObject is.
-    """
-    self.edges_from.append(edge)
-
-  def __str__(self):
-    prefix = 'LiveHeapObject(' + str(self.object_id) + ' '
-    if self.type_string == 'object':
-      return prefix + self.class_name + ')'
-    return prefix + self.type_string + ')'
diff --git a/tools/telemetry/telemetry/core/heap/model.py b/tools/telemetry/telemetry/core/heap/model.py
deleted file mode 100644
index 551716e6..0000000
--- a/tools/telemetry/telemetry/core/heap/model.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2013 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.
-
-from telemetry.core.heap import chrome_js_heap_snapshot_parser
-
-
-class Model(object):
-  """ The heap snapshot model is a set of LiveHeapObjects. The LiveHeapObjects
-  contain the RetainingEdge objects describing the relationships between the
-  LiveHeapObjects."""
-
-  def __init__(self, raw_data):
-    if not chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser.CanImport(
-        raw_data):
-      raise ValueError("Cannot import snapshot data")
-    parser = chrome_js_heap_snapshot_parser.ChromeJsHeapSnapshotParser(raw_data)
-    self._all_live_heap_objects = parser.GetAllLiveHeapObjects()
-
-  @property
-  def all_live_heap_objects(self):
-    return self._all_live_heap_objects
diff --git a/tools/telemetry/telemetry/core/heap/retaining_edge.py b/tools/telemetry/telemetry/core/heap/retaining_edge.py
deleted file mode 100644
index d6b9978c..0000000
--- a/tools/telemetry/telemetry/core/heap/retaining_edge.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2013 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.
-
-class RetainingEdge(object):
-  """Data structure for representing a retainer relationship between objects.
-
-  Attributes:
-    from_object_id: int, id of the object which is the start point of this
-        RetainingEdge.  Used when the corresponding LiveHeapObject object is not
-        yet contstructed.
-    to_object_id: int, id of the object which is the end point of this
-        RetainingEdge. Used when the corresponding LiveHeapObject object is not
-        yet contstructed.
-    from_object: LiveHeapObject, the start point of this RetainingEdge.
-    to_object: LiveHeapObject, the end point of this RetainingEdge.
-    type_string: str, the type of the RetainingEdge.
-    name_string: str, the JavaScript attribute name this RetainingEdge
-        represents.
-  """
-
-  def __init__(self, from_object_id, to_object_id, type_string, name_string):
-    """Initializes the RetainingEdge object.
-
-    Args:
-      from_object_id: int, id of the object which is the start point of this
-          RetainingEdge. Used when the corresponding LiveHeapObject object is
-          not yet contstructed.
-      to_object_id: int, id of the object which is the end point of this
-          RetainingEdge. Used when the corresponding LiveHeapObject object is
-          not yet contstructed.
-      type_string: str, the type of the RetainingEdge.
-      name_string: str, the JavaScript attribute name this RetainingEdge
-          represents.
-    """
-    self.from_object_id = from_object_id
-    self.to_object_id = to_object_id
-    self.from_object = {}
-    self.to_object = {}
-    self.type_string = type_string
-    self.name_string = name_string
-
-  def SetFromObject(self, obj):
-    self.from_object = obj
-    return self
-
-  def SetToObject(self, obj):
-    self.to_object = obj
-    return self
-
-  def __str__(self):
-    return 'RetainingEdge(' + self.type_string + ' ' + self.name_string + ')'
diff --git a/tools/telemetry/telemetry/core/web_contents.py b/tools/telemetry/telemetry/core/web_contents.py
index 38232360..71a5c76 100644
--- a/tools/telemetry/telemetry/core/web_contents.py
+++ b/tools/telemetry/telemetry/core/web_contents.py
@@ -174,9 +174,6 @@
   def StopTimelineRecording(self):
     self._inspector_backend.StopTimelineRecording()
 
-  def TakeJSHeapSnapshot(self, timeout=120):
-    return self._inspector_backend.TakeJSHeapSnapshot(timeout)
-
   def IsAlive(self):
     """Whether the WebContents is still operating normally.
 
diff --git a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py b/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
index eb3a1223..c7f66fd3 100644
--- a/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
+++ b/tools/telemetry/telemetry/results/csv_pivot_table_output_formatter.py
@@ -45,8 +45,8 @@
     for run in page_test_results.all_page_runs:
       run_index = page_test_results.all_page_runs.index(run)
       page_dict = {
-          'page': run.page.display_name,
-          'page_set': run.page.page_set.Name(),
+          'page': run.user_story.display_name,
+          'page_set': run.user_story.page_set.Name(),
           'run_index': run_index,
       }
       for value in run.values:
diff --git a/tools/telemetry/telemetry/results/gtest_progress_reporter.py b/tools/telemetry/telemetry/results/gtest_progress_reporter.py
index 26b2d6c..87c03f7 100644
--- a/tools/telemetry/telemetry/results/gtest_progress_reporter.py
+++ b/tools/telemetry/telemetry/results/gtest_progress_reporter.py
@@ -81,7 +81,7 @@
           (len(page_test_results.failures), unit))
       for failed_run in failed_runs:
         print >> self._output_stream, '[  FAILED  ]  %s' % (
-            failed_run.page.display_name)
+            failed_run.user_story.display_name)
       print >> self._output_stream
       count = len(failed_runs)
       unit = 'TEST' if count == 1 else 'TESTS'
diff --git a/tools/telemetry/telemetry/results/json_output_formatter.py b/tools/telemetry/telemetry/results/json_output_formatter.py
index db7b13b..7ef539d 100644
--- a/tools/telemetry/telemetry/results/json_output_formatter.py
+++ b/tools/telemetry/telemetry/results/json_output_formatter.py
@@ -36,7 +36,7 @@
 
 
 def _GetAllPages(page_test_results):
-  pages = set(page_run.page for page_run in
+  pages = set(page_run.user_story for page_run in
               page_test_results.all_page_runs)
   return pages
 
diff --git a/tools/telemetry/telemetry/results/page_run_unittest.py b/tools/telemetry/telemetry/results/page_run_unittest.py
deleted file mode 100644
index 23ce506..0000000
--- a/tools/telemetry/telemetry/results/page_run_unittest.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import unittest
-
-from telemetry import page as page_module
-from telemetry.page import page_set
-from telemetry.results import page_run
-from telemetry.value import failure
-from telemetry.value import scalar
-from telemetry.value import skip
-
-
-class PageRunTest(unittest.TestCase):
-  def setUp(self):
-    self.page_set = page_set.PageSet(file_path=os.path.dirname(__file__))
-    self.page_set.AddUserStory(page_module.Page(
-        'http://www.bar.com/', self.page_set, self.page_set.base_dir))
-
-  @property
-  def pages(self):
-    return self.page_set.pages
-
-  def testPageRunFailed(self):
-    run = page_run.PageRun(self.pages[0])
-    run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test'))
-    self.assertFalse(run.ok)
-    self.assertTrue(run.failed)
-    self.assertFalse(run.skipped)
-
-    run = page_run.PageRun(self.pages[0])
-    run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1))
-    run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test'))
-    self.assertFalse(run.ok)
-    self.assertTrue(run.failed)
-    self.assertFalse(run.skipped)
-
-  def testPageRunSkipped(self):
-    run = page_run.PageRun(self.pages[0])
-    run.AddValue(failure.FailureValue.FromMessage(self.pages[0], 'test'))
-    run.AddValue(skip.SkipValue(self.pages[0], 'test'))
-    self.assertFalse(run.ok)
-    self.assertFalse(run.failed)
-    self.assertTrue(run.skipped)
-
-    run = page_run.PageRun(self.pages[0])
-    run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1))
-    run.AddValue(skip.SkipValue(self.pages[0], 'test'))
-    self.assertFalse(run.ok)
-    self.assertFalse(run.failed)
-    self.assertTrue(run.skipped)
-
-  def testPageRunSucceeded(self):
-    run = page_run.PageRun(self.pages[0])
-    self.assertTrue(run.ok)
-    self.assertFalse(run.failed)
-    self.assertFalse(run.skipped)
-
-    run = page_run.PageRun(self.pages[0])
-    run.AddValue(scalar.ScalarValue(self.pages[0], 'a', 's', 1))
-    self.assertTrue(run.ok)
-    self.assertFalse(run.failed)
-    self.assertFalse(run.skipped)
diff --git a/tools/telemetry/telemetry/results/page_test_results.py b/tools/telemetry/telemetry/results/page_test_results.py
index 819684f..497a3ae 100644
--- a/tools/telemetry/telemetry/results/page_test_results.py
+++ b/tools/telemetry/telemetry/results/page_test_results.py
@@ -12,8 +12,8 @@
 import traceback
 
 from telemetry import value as value_module
-from telemetry.results import page_run
 from telemetry.results import progress_reporter as progress_reporter_module
+from telemetry.results import user_story_run
 from telemetry.util import cloud_storage
 from telemetry.value import failure
 from telemetry.value import skip
@@ -94,7 +94,7 @@
   @property
   def current_page(self):
     assert self._current_page_run, 'Not currently running test.'
-    return self._current_page_run.page
+    return self._current_page_run.user_story
 
   @property
   def current_page_run(self):
@@ -108,7 +108,7 @@
   @property
   def pages_that_succeeded(self):
     """Returns the set of pages that succeeded."""
-    pages = set(run.page for run in self.all_page_runs)
+    pages = set(run.user_story for run in self.all_page_runs)
     pages.difference_update(self.pages_that_failed)
     return pages
 
@@ -118,7 +118,7 @@
     failed_pages = set()
     for run in self.all_page_runs:
       if run.failed:
-        failed_pages.add(run.page)
+        failed_pages.add(run.user_story)
     return failed_pages
 
   @property
@@ -150,7 +150,7 @@
 
   def WillRunPage(self, page):
     assert not self._current_page_run, 'Did not call DidRunPage.'
-    self._current_page_run = page_run.PageRun(page)
+    self._current_page_run = user_story_run.UserStoryRun(page)
     self._progress_reporter.WillRunPage(self)
 
   def DidRunPage(self, page, discard_run=False):  # pylint: disable=W0613
diff --git a/tools/telemetry/telemetry/results/page_test_results_unittest.py b/tools/telemetry/telemetry/results/page_test_results_unittest.py
index 21006a1..b9022b0 100644
--- a/tools/telemetry/telemetry/results/page_test_results_unittest.py
+++ b/tools/telemetry/telemetry/results/page_test_results_unittest.py
@@ -55,7 +55,7 @@
     results.DidRunPage(self.pages[1])
 
     self.assertTrue(results.all_page_runs[0].skipped)
-    self.assertEqual(self.pages[0], results.all_page_runs[0].page)
+    self.assertEqual(self.pages[0], results.all_page_runs[0].user_story)
     self.assertEqual(set([self.pages[0], self.pages[1]]),
                      results.pages_that_succeeded)
 
diff --git a/tools/telemetry/telemetry/results/page_run.py b/tools/telemetry/telemetry/results/user_story_run.py
similarity index 79%
rename from tools/telemetry/telemetry/results/page_run.py
rename to tools/telemetry/telemetry/results/user_story_run.py
index 72bd4084..eafa1d3f 100644
--- a/tools/telemetry/telemetry/results/page_run.py
+++ b/tools/telemetry/telemetry/results/user_story_run.py
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
@@ -6,21 +6,21 @@
 from telemetry.value import skip
 
 
-class PageRun(object):
-  def __init__(self, page):
-    self._page = page
+class UserStoryRun(object):
+  def __init__(self, user_story):
+    self._user_story = user_story
     self._values = []
 
   def AddValue(self, value):
     self._values.append(value)
 
   @property
-  def page(self):
-    return self._page
+  def user_story(self):
+    return self._user_story
 
   @property
   def values(self):
-    """The values that correspond to this page run."""
+    """The values that correspond to this user_story run."""
     return self._values
 
   @property
diff --git a/tools/telemetry/telemetry/results/user_story_run_unittest.py b/tools/telemetry/telemetry/results/user_story_run_unittest.py
new file mode 100644
index 0000000..4aa3cf6
--- /dev/null
+++ b/tools/telemetry/telemetry/results/user_story_run_unittest.py
@@ -0,0 +1,74 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import unittest
+
+from telemetry import user_story as user_story_module
+from telemetry.results import user_story_run
+from telemetry.user_story import shared_user_story_state
+from telemetry.user_story import user_story_set
+from telemetry.value import failure
+from telemetry.value import scalar
+from telemetry.value import skip
+
+
+# pylint: disable=abstract-method
+class SharedUserStoryStateBar(shared_user_story_state.SharedUserStoryState):
+  pass
+
+class UserStoryFoo(user_story_module.UserStory):
+  def __init__(self, name='', labels=None):
+    super(UserStoryFoo, self).__init__(
+        SharedUserStoryStateBar, name, labels)
+
+class UserStoryRunTest(unittest.TestCase):
+  def setUp(self):
+    self.user_story_set = user_story_set.UserStorySet()
+    self.user_story_set.AddUserStory(UserStoryFoo())
+
+  @property
+  def user_stories(self):
+    return self.user_story_set.user_stories
+
+  def testUserStoryRunFailed(self):
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test'))
+    self.assertFalse(run.ok)
+    self.assertTrue(run.failed)
+    self.assertFalse(run.skipped)
+
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1))
+    run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test'))
+    self.assertFalse(run.ok)
+    self.assertTrue(run.failed)
+    self.assertFalse(run.skipped)
+
+  def testUserStoryRunSkipped(self):
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    run.AddValue(failure.FailureValue.FromMessage(self.user_stories[0], 'test'))
+    run.AddValue(skip.SkipValue(self.user_stories[0], 'test'))
+    self.assertFalse(run.ok)
+    self.assertFalse(run.failed)
+    self.assertTrue(run.skipped)
+
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1))
+    run.AddValue(skip.SkipValue(self.user_stories[0], 'test'))
+    self.assertFalse(run.ok)
+    self.assertFalse(run.failed)
+    self.assertTrue(run.skipped)
+
+  def testUserStoryRunSucceeded(self):
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    self.assertTrue(run.ok)
+    self.assertFalse(run.failed)
+    self.assertFalse(run.skipped)
+
+    run = user_story_run.UserStoryRun(self.user_stories[0])
+    run.AddValue(scalar.ScalarValue(self.user_stories[0], 'a', 's', 1))
+    self.assertTrue(run.ok)
+    self.assertFalse(run.failed)
+    self.assertFalse(run.skipped)
diff --git a/tools/telemetry/telemetry/unittest_util/run_tests.py b/tools/telemetry/telemetry/unittest_util/run_tests.py
index 8539e5d3..b4f6b8db 100644
--- a/tools/telemetry/telemetry/unittest_util/run_tests.py
+++ b/tools/telemetry/telemetry/unittest_util/run_tests.py
@@ -141,16 +141,9 @@
 def GetClassifier(args, possible_browser):
   def ClassifyTest(test_set, test):
     name = test.id()
-    if args.positional_args:
-      if _MatchesSelectedTest(name, args.positional_args,
-                              args.exact_test_filter):
-        assert hasattr(test, '_testMethodName')
-        method = getattr(test, test._testMethodName) # pylint: disable=W0212
-        if decorators.ShouldBeIsolated(method, possible_browser):
-          test_set.isolated_tests.append(typ.TestInput(name))
-        else:
-          test_set.parallel_tests.append(typ.TestInput(name))
-    else:
+    if (not args.positional_args
+        or _MatchesSelectedTest(name, args.positional_args,
+                                args.exact_test_filter)):
       assert hasattr(test, '_testMethodName')
       method = getattr(test, test._testMethodName) # pylint: disable=W0212
       should_skip, reason = decorators.ShouldSkip(method, possible_browser)
diff --git a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
index 5f9278d5..ed39e53 100644
--- a/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
+++ b/tools/telemetry/telemetry/web_perf/metrics/rendering_stats.py
@@ -20,7 +20,7 @@
 FORWARD_SCROLL_UPDATE_COMP_NAME = (
     'INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT')
 # This is when the input event has reached swap buffer.
-END_COMP_NAME = 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT'
+END_COMP_NAME = 'INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT'
 
 # Name for a main thread scroll update latency event.
 SCROLL_UPDATE_EVENT_NAME = 'InputLatency:ScrollUpdate'
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index d6f60966..c429a9f1 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -742,3 +742,20 @@
 *!content::ContentMainRunnerImpl::Run
 *!content::ContentMain
 *!content::LaunchTests
+
+UNINITIALIZED READ
+name=http://crbug.com/463204
+skia.dll!_ltod3
+skia.dll!SkPaint::measure_text
+skia.dll!SkPaint::measureText
+content.dll!content::DoPreSandboxWarmupForTypeface
+content.dll!content::`anonymous namespace'::WarmupDirectWrite
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/463261
+...
+blink_web.dll!blink::WebFrameWidgetImpl::selectionBounds
+content.dll!content::RenderWidget::GetSelectionBounds
+content.dll!content::RenderWidget::UpdateSelectionBounds
+content.dll!content::RenderWidget::willBeginCompositorFrame
+cc.dll!base::internal::InvokeHelper<>::MakeItSo
diff --git a/ui/accessibility/ax_tree_serializer.h b/ui/accessibility/ax_tree_serializer.h
index f1cbfce..53e515a 100644
--- a/ui/accessibility/ax_tree_serializer.h
+++ b/ui/accessibility/ax_tree_serializer.h
@@ -292,36 +292,39 @@
   // with the LCA.
   AXSourceNode lca = LeastCommonAncestor(node);
 
-  if (client_root_) {
-    bool need_delete = false;
-    if (tree_->IsValid(lca)) {
-      // Check for any reparenting within this subtree - if there is
-      // any, we need to delete and reserialize the whole subtree
-      // that contains the old and new parents of the reparented node.
-      if (AnyDescendantWasReparented(lca, &lca))
-        need_delete = true;
-    }
-
-    if (!tree_->IsValid(lca)) {
-      // If there's no LCA, just tell the client to destroy the whole
-      // tree and then we'll serialize everything from the new root.
-      out_update->node_id_to_clear = client_root_->id;
-      Reset();
-    } else if (need_delete) {
-      // Otherwise, if we need to reserialize a subtree, first we need
-      // to delete those nodes in our client tree so that
-      // SerializeChangedNodes() will be sure to send them again.
-      out_update->node_id_to_clear = tree_->GetId(lca);
-      ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
-      CHECK(client_lca);
-      for (size_t i = 0; i < client_lca->children.size(); ++i) {
-        client_id_map_.erase(client_lca->children[i]->id);
-        DeleteClientSubtree(client_lca->children[i]);
-        delete client_lca->children[i];
+  // This loop computes the least common ancestor that includes the old
+  // and new parents of any nodes that have been reparented, and clears the
+  // whole client subtree of that LCA if necessary. If we do end up clearing
+  // any client nodes, keep looping because we have to search for more
+  // nodes that may have been reparented from this new LCA.
+  bool need_delete;
+  do {
+    need_delete = false;
+    if (client_root_) {
+      if (tree_->IsValid(lca)) {
+        // Check for any reparenting within this subtree - if there is
+        // any, we need to delete and reserialize the whole subtree
+        // that contains the old and new parents of the reparented node.
+        if (AnyDescendantWasReparented(lca, &lca))
+          need_delete = true;
       }
-      client_lca->children.clear();
+
+      if (!tree_->IsValid(lca)) {
+        // If there's no LCA, just tell the client to destroy the whole
+        // tree and then we'll serialize everything from the new root.
+        out_update->node_id_to_clear = client_root_->id;
+        Reset();
+      } else if (need_delete) {
+        // Otherwise, if we need to reserialize a subtree, first we need
+        // to delete those nodes in our client tree so that
+        // SerializeChangedNodes() will be sure to send them again.
+        out_update->node_id_to_clear = tree_->GetId(lca);
+        ClientTreeNode* client_lca = ClientTreeNodeById(tree_->GetId(lca));
+        CHECK(client_lca);
+        DeleteClientSubtree(client_lca);
+      }
     }
-  }
+  } while (need_delete);
 
   // Serialize from the LCA, or from the root if there isn't one.
   if (!tree_->IsValid(lca))
diff --git a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
index d03c1650..f8647ec 100644
--- a/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
+++ b/ui/android/java/src/org/chromium/ui/picker/MultiFieldTimePickerDialog.java
@@ -155,11 +155,14 @@
             mMinuteSpinner.setMaxValue(59);
         }
 
-        if (step >= HOUR_IN_MILLIS) {
+        mMinuteSpinner.setValue(minute);
+        if (step % HOUR_IN_MILLIS == 0) {
             mMinuteSpinner.setEnabled(false);
+            // TODO(tkent): We should set minutes value of
+            // WebDateTimeChooserParams::stepBase.
+            mMinuteSpinner.setValue(minMinute);
         }
 
-        mMinuteSpinner.setValue(minute);
         mMinuteSpinner.setFormatter(twoDigitPaddingFormatter);
 
         if (step >= MINUTE_IN_MILLIS) {
diff --git a/ui/app_list/BUILD.gn b/ui/app_list/BUILD.gn
index f1fae35..8758ad4 100644
--- a/ui/app_list/BUILD.gn
+++ b/ui/app_list/BUILD.gn
@@ -218,69 +218,67 @@
   ]
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("app_list_unittests") {
-    sources = [
-      "app_list_item_list_unittest.cc",
-      "app_list_model_unittest.cc",
-      "folder_image_unittest.cc",
-      "pagination_model_unittest.cc",
-      "search/history_data_store_unittest.cc",
-      "search/mixer_unittest.cc",
-      "search/term_break_iterator_unittest.cc",
-      "search/tokenized_string_char_iterator_unittest.cc",
-      "search/tokenized_string_match_unittest.cc",
-      "search/tokenized_string_unittest.cc",
-      "test/run_all_unittests.cc",
+test("app_list_unittests") {
+  sources = [
+    "app_list_item_list_unittest.cc",
+    "app_list_model_unittest.cc",
+    "folder_image_unittest.cc",
+    "pagination_model_unittest.cc",
+    "search/history_data_store_unittest.cc",
+    "search/mixer_unittest.cc",
+    "search/term_break_iterator_unittest.cc",
+    "search/tokenized_string_char_iterator_unittest.cc",
+    "search/tokenized_string_match_unittest.cc",
+    "search/tokenized_string_unittest.cc",
+    "test/run_all_unittests.cc",
+  ]
+
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+  deps = [
+    ":app_list",
+    ":test_support",
+    "//base",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/base",
+    "//ui/compositor",
+    "//ui/events",
+    "//ui/events:test_support",
+    "//ui/gl",
+    "//ui/resources",
+    "//ui/resources:ui_test_pak",
+  ]
+
+  if (toolkit_views) {
+    sources += [
+      "views/app_list_main_view_unittest.cc",
+      "views/app_list_view_unittest.cc",
+      "views/apps_grid_view_unittest.cc",
+      "views/contents_view_unittest.cc",
+      "views/folder_header_view_unittest.cc",
+      "views/search_box_view_unittest.cc",
+      "views/search_result_list_view_unittest.cc",
+      "views/speech_view_unittest.cc",
+      "views/test/apps_grid_view_test_api.cc",
+      "views/test/apps_grid_view_test_api.h",
     ]
-
-    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
-
-    deps = [
-      ":app_list",
-      ":test_support",
-      "//base",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/base",
-      "//ui/compositor",
-      "//ui/events",
-      "//ui/events:test_support",
-      "//ui/gl",
-      "//ui/resources",
-      "//ui/resources:ui_test_pak",
+    deps += [
+      "//ui/views",
+      "//ui/views:test_support",
     ]
+  }
 
-    if (toolkit_views) {
-      sources += [
-        "views/app_list_main_view_unittest.cc",
-        "views/app_list_view_unittest.cc",
-        "views/apps_grid_view_unittest.cc",
-        "views/contents_view_unittest.cc",
-        "views/folder_header_view_unittest.cc",
-        "views/search_box_view_unittest.cc",
-        "views/search_result_list_view_unittest.cc",
-        "views/speech_view_unittest.cc",
-        "views/test/apps_grid_view_test_api.cc",
-        "views/test/apps_grid_view_test_api.h",
-      ]
-      deps += [
-        "//ui/views",
-        "//ui/views:test_support",
-      ]
-    }
-
-    if (is_mac) {
-      sources += [
-        "cocoa/app_list_view_controller_unittest.mm",
-        "cocoa/app_list_window_controller_unittest.mm",
-        "cocoa/apps_grid_controller_unittest.mm",
-        "cocoa/apps_search_box_controller_unittest.mm",
-        "cocoa/apps_search_results_controller_unittest.mm",
-        "cocoa/test/apps_grid_controller_test_helper.h",
-        "cocoa/test/apps_grid_controller_test_helper.mm",
-      ]
-    }
+  if (is_mac) {
+    sources += [
+      "cocoa/app_list_view_controller_unittest.mm",
+      "cocoa/app_list_window_controller_unittest.mm",
+      "cocoa/apps_grid_controller_unittest.mm",
+      "cocoa/apps_search_box_controller_unittest.mm",
+      "cocoa/apps_search_results_controller_unittest.mm",
+      "cocoa/test/apps_grid_controller_test_helper.h",
+      "cocoa/test/apps_grid_controller_test_helper.mm",
+    ]
   }
 }
diff --git a/ui/app_list/PRESUBMIT.py b/ui/app_list/PRESUBMIT.py
index 3e3d954e..73df615 100644
--- a/ui/app_list/PRESUBMIT.py
+++ b/ui/app_list/PRESUBMIT.py
@@ -23,7 +23,7 @@
   sources = lambda x: input_api.FilterSourceFile(
     x, white_list = INCLUDE_CPP_FILES_ONLY, black_list = black_list)
   return input_api.canned_checks.CheckChangeLintsClean(
-      input_api, output_api, sources, [])
+      input_api, output_api, sources, lint_filters=[], verbose_level=1)
 
 def CheckChangeOnUpload(input_api, output_api):
   results = []
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index c1bdb1ed..216abf4 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -83,6 +83,25 @@
   return true;
 }
 
+// This view forwards the focus to the search box widget by providing it as a
+// FocusTraversable when a focus search is provided.
+class SearchBoxFocusHost : public views::View {
+ public:
+  explicit SearchBoxFocusHost(views::Widget* search_box_widget)
+      : search_box_widget_(search_box_widget) {}
+
+  ~SearchBoxFocusHost() override {}
+
+  views::FocusTraversable* GetFocusTraversable() override {
+    return search_box_widget_;
+  }
+
+ private:
+  views::Widget* search_box_widget_;
+
+  DISALLOW_COPY_AND_ASSIGN(SearchBoxFocusHost);
+};
+
 // The view for the App List overlay, which appears as a white rounded
 // rectangle with the given radius.
 class AppListOverlayView : public views::View {
@@ -182,6 +201,7 @@
     : delegate_(delegate),
       app_list_main_view_(nullptr),
       speech_view_(nullptr),
+      search_box_focus_host_(nullptr),
       search_box_widget_(nullptr),
       search_box_view_(nullptr),
       overlay_view_(nullptr),
@@ -463,6 +483,15 @@
   search_box_widget_->Init(search_box_widget_params);
   search_box_widget_->SetContentsView(search_box_view_);
 
+  // The search box will not naturally receive focus by itself (because it is in
+  // a separate widget). Create this SearchBoxFocusHost in the main widget to
+  // forward the focus search into to the search box.
+  search_box_focus_host_ = new SearchBoxFocusHost(search_box_widget_);
+  AddChildView(search_box_focus_host_);
+  search_box_widget_->SetFocusTraversableParentView(search_box_focus_host_);
+  search_box_widget_->SetFocusTraversableParent(
+      GetWidget()->GetFocusTraversable());
+
 #if defined(USE_AURA)
   // Mouse events on the search box shadow should not be captured.
   aura::Window* window = search_box_widget_->GetNativeWindow();
diff --git a/ui/app_list/views/app_list_view.h b/ui/app_list/views/app_list_view.h
index 1634cef..b62f9d35 100644
--- a/ui/app_list/views/app_list_view.h
+++ b/ui/app_list/views/app_list_view.h
@@ -173,6 +173,7 @@
   AppListMainView* app_list_main_view_;
   SpeechView* speech_view_;
 
+  views::View* search_box_focus_host_;  // Owned by the views hierarchy.
   views::Widget* search_box_widget_;  // Owned by the app list's widget.
   SearchBoxView* search_box_view_;    // Owned by |search_box_widget_|.
 
diff --git a/ui/app_list/views/search_result_page_view.cc b/ui/app_list/views/search_result_page_view.cc
index 04c9443..2af6d583 100644
--- a/ui/app_list/views/search_result_page_view.cc
+++ b/ui/app_list/views/search_result_page_view.cc
@@ -4,6 +4,8 @@
 
 #include "ui/app_list/views/search_result_page_view.h"
 
+#include <algorithm>
+
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_switches.h"
 #include "ui/app_list/app_list_view_delegate.h"
diff --git a/ui/app_list/views/start_page_view.cc b/ui/app_list/views/start_page_view.cc
index c546b2d..401aae1 100644
--- a/ui/app_list/views/start_page_view.cc
+++ b/ui/app_list/views/start_page_view.cc
@@ -4,6 +4,8 @@
 
 #include "ui/app_list/views/start_page_view.h"
 
+#include <string>
+
 #include "base/i18n/rtl.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn
index 9a330fb..bcf1065 100644
--- a/ui/aura/BUILD.gn
+++ b/ui/aura/BUILD.gn
@@ -243,63 +243,61 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  executable("bench") {
-    output_name = "aura_bench"
-    testonly = true
+executable("bench") {
+  output_name = "aura_bench"
+  testonly = true
 
-    sources = [
-      "bench/bench_main.cc",
-    ]
+  sources = [
+    "bench/bench_main.cc",
+  ]
 
-    deps = [
-      ":test_support",
-      "//base",
-      "//base:i18n",
-      "//cc",
-      "//gpu/command_buffer/client:gles2_interface",
-      "//skia",
-      "//third_party/icu",
-      "//ui/base",
-      "//ui/compositor",
-      "//ui/compositor:test_support",
-      "//ui/events",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-    ]
+  deps = [
+    ":test_support",
+    "//base",
+    "//base:i18n",
+    "//cc",
+    "//gpu/command_buffer/client:gles2_interface",
+    "//skia",
+    "//third_party/icu",
+    "//ui/base",
+    "//ui/compositor",
+    "//ui/compositor:test_support",
+    "//ui/events",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+  ]
 
-    if (use_x11) {
-      deps += [ "//ui/gfx/x" ]
-    }
+  if (use_x11) {
+    deps += [ "//ui/gfx/x" ]
   }
+}
 
-  test("aura_unittests") {
-    sources = [
-      "gestures/gesture_recognizer_unittest.cc",
-      "test/run_all_unittests.cc",
-      "window_event_dispatcher_unittest.cc",
-      "window_targeter_unittest.cc",
-      "window_unittest.cc",
-    ]
+test("aura_unittests") {
+  sources = [
+    "gestures/gesture_recognizer_unittest.cc",
+    "test/run_all_unittests.cc",
+    "window_event_dispatcher_unittest.cc",
+    "window_targeter_unittest.cc",
+    "window_unittest.cc",
+  ]
 
-    deps = [
-      ":test_support",
-      "//base/allocator",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/base:test_support",
-      "//ui/compositor:test_support",
-      "//ui/events:test_support",
-      "//ui/events:gesture_detection",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-    ]
+  deps = [
+    ":test_support",
+    "//base/allocator",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/base:test_support",
+    "//ui/compositor:test_support",
+    "//ui/events:test_support",
+    "//ui/events:gesture_detection",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+  ]
 
-    if (is_linux) {
-      deps += [ "//third_party/mesa" ]
-    }
+  if (is_linux) {
+    deps += [ "//third_party/mesa" ]
   }
 }
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc
index c589824..e7ed3680 100644
--- a/ui/aura/demo/demo_main.cc
+++ b/ui/aura/demo/demo_main.cc
@@ -23,6 +23,7 @@
 #include "ui/events/event.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gl/gl_surface.h"
 
 #if defined(USE_X11)
@@ -63,6 +64,14 @@
   void OnCaptureLost() override {}
   void OnPaint(gfx::Canvas* canvas) override {
     canvas->DrawColor(color_, SkXfermode::kSrc_Mode);
+    gfx::Rect r;
+    canvas->GetClipBounds(&r);
+    // Fill with a non-solid color so that the compositor will exercise its
+    // texture upload path.
+    while (!r.IsEmpty()) {
+      r.Inset(2, 2);
+      canvas->FillRect(r, color_, SkXfermode::kXor_Mode);
+    }
   }
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
   void OnWindowDestroying(aura::Window* window) override {}
diff --git a/ui/aura/env.cc b/ui/aura/env.cc
index d205ae98..4d2db40d 100644
--- a/ui/aura/env.cc
+++ b/ui/aura/env.cc
@@ -43,6 +43,11 @@
 }
 
 // static
+Env* Env::GetInstanceDontCreate() {
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+// static
 void Env::DeleteInstance() {
   delete lazy_tls_ptr.Pointer()->Get();
 }
diff --git a/ui/aura/env.h b/ui/aura/env.h
index 4ae2d694..9b84c3b 100644
--- a/ui/aura/env.h
+++ b/ui/aura/env.h
@@ -37,6 +37,7 @@
   // nativeviewportservice lives in the same process as the viewmanager.
   static void CreateInstance(bool create_event_source);
   static Env* GetInstance();
+  static Env* GetInstanceDontCreate();
   static void DeleteInstance();
 
   void AddObserver(EnvObserver* observer);
diff --git a/ui/events/ozone/evdev/input_device_factory_evdev.cc b/ui/events/ozone/evdev/input_device_factory_evdev.cc
index e2140f66..bb5dbe7 100644
--- a/ui/events/ozone/evdev/input_device_factory_evdev.cc
+++ b/ui/events/ozone/evdev/input_device_factory_evdev.cc
@@ -229,7 +229,7 @@
   base::WorkerPool::PostTask(FROM_HERE,
                              base::Bind(&OpenInputDevice, base::Passed(&params),
                                         task_runner_, reply_callback),
-                             true /* task_is_slow */);
+                             false /* task_is_slow */);
 }
 
 void InputDeviceFactoryEvdev::RemoveInputDevice(const base::FilePath& path) {
diff --git a/ui/file_manager/audio_player/audio_player.html b/ui/file_manager/audio_player/audio_player.html
index 3d95596..0b225f9 100644
--- a/ui/file_manager/audio_player/audio_player.html
+++ b/ui/file_manager/audio_player/audio_player.html
@@ -40,10 +40,11 @@
 
     <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script>
     <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/file_system_metadata.js"></script>
     <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script>
     <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script>
     <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script>
+    <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script>
+    <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script>
     <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script>
 
     <script src="js/audio_player.js"></script>
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index f5e172d..a4d81ef 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -17,8 +17,7 @@
   this.container_ = container;
   this.volumeManager_ = new VolumeManagerWrapper(
       VolumeManagerWrapper.DriveEnabledStatus.DRIVE_ENABLED);
-  this.fileSystemMetadata_ = FileSystemMetadata.create(
-      new MetadataProviderCache(), this.volumeManager_);
+  this.metadataModel_ = new MetadataModel.create(this.volumeManager_);
   this.selectedEntry_ = null;
 
   this.model_ = new AudioPlayerModel();
@@ -238,7 +237,7 @@
  * @private
  */
 AudioPlayer.prototype.fetchMetadata_ = function(entry, callback) {
-  this.fileSystemMetadata_.get(
+  this.metadataModel_.get(
       [entry], ['mediaTitle', 'mediaArtist', 'present']).then(
       function(generation, metadata) {
         // Do nothing if another load happened since the metadata request.
diff --git a/ui/file_manager/audio_player/js/audio_player_scripts.js b/ui/file_manager/audio_player/js/audio_player_scripts.js
index a4d5a978..db67180 100644
--- a/ui/file_manager/audio_player/js/audio_player_scripts.js
+++ b/ui/file_manager/audio_player/js/audio_player_scripts.js
@@ -35,10 +35,11 @@
 
 <include src="../../file_manager/foreground/js/metadata/content_metadata_provider.js">
 <include src="../../file_manager/foreground/js/metadata/external_metadata_provider.js">
-<include src="../../file_manager/foreground/js/metadata/file_system_metadata.js">
 <include src="../../file_manager/foreground/js/metadata/file_system_metadata_provider.js">
 <include src="../../file_manager/foreground/js/metadata/metadata_cache_item.js">
 <include src="../../file_manager/foreground/js/metadata/metadata_item.js">
+<include src="../../file_manager/foreground/js/metadata/metadata_model.js">
+<include src="../../file_manager/foreground/js/metadata/multi_metadata_provider.js">
 <include src="../../file_manager/foreground/js/metadata/thumbnail_model.js">
 
 <include src="audio_player.js"/>
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 3f48669..a4b785b 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -1247,6 +1247,15 @@
   }
 }
 
+@-webkit-keyframes fadeOut {
+  from {
+    opacity: 1;
+  }
+  to {
+    opacity: 0;
+  }
+}
+
 /* Table splitter element */
 .table-header-splitter {
   background-image: -webkit-image-set(
@@ -1370,24 +1379,32 @@
 }
 
 #list-container list li .detail-thumbnail {
+  height: 28px;
+  overflow: hidden;
+  position: absolute;
+  width: 28px;
+}
+
+#list-container list li .detail-thumbnail > .thumbnail {
   -webkit-user-drag: none;
   background-color: rgb(245, 245, 245);
   background-position: center;
   background-size: cover;
   border-radius: 14px;
-  height: 28px;
-  opacity: 0;
-  overflow: hidden;
-  position: absolute;
-  transition: opacity 220ms ease;
-  width: 28px;
-}
-
-#list-container list li .detail-thumbnail.loaded {
+  height: 100%;
   opacity: 1;
+  position: absolute;
+  width: 100%;
 }
 
-body.check-select #list-container list li[selected] .detail-thumbnail.loaded {
+#list-container list li .detail-thumbnail > .thumbnail.animate {
+  -webkit-animation: fadeIn 220ms ease;
+}
+
+body.check-select #list-container list li[selected] .detail-thumbnail
+> .thumbnail {
+  /* Fade out after checkmark fades in. */
+  -webkit-animation: fadeOut 0ms 220ms ease backwards;
   opacity: 0;
 }
 
diff --git a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
index 1a651b4..684ad36 100644
--- a/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/compiled_resources.gyp
@@ -89,12 +89,13 @@
           './launch_param.js',
           './metadata/content_metadata_provider.js',
           './metadata/external_metadata_provider.js',
-          './metadata/file_system_metadata.js',
           './metadata/file_system_metadata_provider.js',
           './metadata/metadata_cache.js',
           './metadata/metadata_cache_item.js',
           './metadata/metadata_cache_set.js',
           './metadata/metadata_item.js',
+          './metadata/metadata_model.js',
+          './metadata/multi_metadata_provider.js',
           './metadata/new_metadata_provider.js',
           './metadata/thumbnail_model.js',
           './metadata_update_controller.js',
diff --git a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
index 0505c5d3..aa49006 100644
--- a/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/dialog_action_controller.js
@@ -9,7 +9,7 @@
  * @param {DialogType} dialogType Dialog type.
  * @param {!DialogFooter} dialogFooter Dialog footer.
  * @param {!DirectoryModel} directoryModel Directory model.
- * @param {!FileSystemMetadata} fileSystemMetadata Metadata cache.
+ * @param {!MetadataModel} metadataModel Metadata cache.
  * @param {!VolumeManagerWrapper} volumeManager Volume manager.
  * @param {!FileFilter} fileFilter File filter model.
  * @param {!NamingController} namingController Naming controller.
@@ -23,7 +23,7 @@
     dialogType,
     dialogFooter,
     directoryModel,
-    fileSystemMetadata,
+    metadataModel,
     volumeManager,
     fileFilter,
     namingController,
@@ -51,11 +51,11 @@
   this.directoryModel_ = directoryModel;
 
   /**
-   * @type {!FileSystemMetadata}
+   * @type {!MetadataModel}
    * @const
    * @private
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   /**
    * @type {!VolumeManagerWrapper}
@@ -369,7 +369,7 @@
 
   // TODO(mtomasz): Use Entry instead of URLs, if possible.
   util.URLsToEntries(selection.urls, function(entries) {
-    this.fileSystemMetadata_.get(entries, ['present']).then(onProperties);
+    this.metadataModel_.get(entries, ['present']).then(onProperties);
   }.bind(this));
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index 9fbab186..a0b2405f 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -393,18 +393,18 @@
 
 /**
  * File list.
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @constructor
  * @extends {cr.ui.ArrayDataModel}
  */
-function FileListModel(fileSystemMetadata) {
+function FileListModel(metadataModel) {
   cr.ui.ArrayDataModel.call(this, []);
 
   /**
-   * @private {!FileSystemMetadata}
+   * @private {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   // Initialize compare functions.
   this.setCompareFunction('name',
@@ -483,7 +483,7 @@
     return a.isDirectory === this.isDescendingOrder_ ? 1 : -1;
 
   var properties =
-      this.fileSystemMetadata_.getCache([a, b], ['modificationTime']);
+      this.metadataModel_.getCache([a, b], ['modificationTime']);
   var aTime = properties[0].modificationTime || 0;
   var bTime = properties[1].modificationTime || 0;
 
@@ -508,7 +508,7 @@
   if (a.isDirectory !== b.isDirectory)
     return a.isDirectory === this.isDescendingOrder_ ? 1 : -1;
 
-  var properties = this.fileSystemMetadata_.getCache([a, b], ['size']);
+  var properties = this.metadataModel_.getCache([a, b], ['size']);
   var aSize = properties[0].size || 0;
   var bSize = properties[1].size || 0;
 
@@ -539,20 +539,20 @@
  * TODO(yoshiki): remove this. crbug.com/224869.
  *
  * @param {FileFilter} fileFilter The file-filter context.
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @constructor
  */
-function FileListContext(fileFilter, fileSystemMetadata) {
+function FileListContext(fileFilter, metadataModel) {
   /**
    * @type {FileListModel}
    */
-  this.fileList = new FileListModel(fileSystemMetadata);
+  this.fileList = new FileListModel(metadataModel);
 
   /**
-   * @public {!FileSystemMetadata}
+   * @public {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata = fileSystemMetadata;
+  this.metadataModel = metadataModel;
 
   /**
    * @type {FileFilter}
@@ -656,7 +656,7 @@
 DirectoryContents.prototype.createMetadataSnapshot = function() {
   var snapshot = {};
   var entries = /** @type {!Array<!Entry>} */ (this.fileList_.slice());
-  var metadata = this.context_.fileSystemMetadata.getCache(
+  var metadata = this.context_.metadataModel.getCache(
       entries, ['modificationTime']);
   for (var i = 0; i < entries.length; i++) {
     snapshot[entries[i].toURL()] = metadata[i];
@@ -693,7 +693,7 @@
     if (this.metadataSnapshot_) {
       var updatedIndexes = [];
       var entries = /** @type {!Array<!Entry>} */ (this.fileList_.slice());
-      var newMetadatas = this.context_.fileSystemMetadata.getCache(
+      var newMetadatas = this.context_.metadataModel.getCache(
           entries, ['modificationTime']);
 
       for (var i = 0; i < entries.length; i++) {
@@ -789,6 +789,7 @@
   }
 
   var updatedList = [];
+  var updatedIndexes = [];
   for (var i = 0; i < this.fileList_.length; i++) {
     var url = this.fileList_.item(i).toURL();
 
@@ -800,17 +801,21 @@
 
     if (url in updatedMap) {
       updatedList.push(updatedMap[url]);
+      updatedIndexes.push(i);
       delete updatedMap[url];
     }
   }
 
+  if (updatedIndexes.length > 0)
+    this.fileList_.updateIndexes(updatedIndexes);
+
   var addedList = [];
   for (var url in updatedMap) {
     addedList.push(updatedMap[url]);
   }
 
   if (removedUrls.length > 0)
-    this.context_.fileSystemMetadata.notifyEntriesRemoved(removedUrls);
+    this.context_.metadataModel.notifyEntriesRemoved(removedUrls);
 
   this.prefetchMetadata(updatedList, true, function() {
     this.onNewEntries_(true, addedList);
@@ -975,8 +980,8 @@
 DirectoryContents.prototype.prefetchMetadata =
     function(entries, refresh, callback) {
   if (refresh)
-    this.context_.fileSystemMetadata.notifyEntriesChanged(entries);
-  this.context_.fileSystemMetadata.get(
+    this.context_.metadataModel.notifyEntriesChanged(entries);
+  this.context_.metadataModel.get(
       entries, this.context_.prefetchPropertyNames).then(callback);
 };
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_model.js b/ui/file_manager/file_manager/foreground/js/directory_model.js
index 188499b..bb014b7 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_model.js
@@ -14,8 +14,7 @@
  * @param {boolean} singleSelection True if only one file could be selected
  *                                  at the time.
  * @param {FileFilter} fileFilter Instance of FileFilter.
- * @param {!MetadataProviderCache} metadataProviderCache Metadata cache.
- * @param {!FileSystemMetadata} fileSystemMetadata Metadata model.
+ * @param {!MetadataModel} metadataModel Metadata model.
  *     service.
  * @param {VolumeManagerWrapper} volumeManager The volume manager.
  * @param {!FileOperationManager} fileOperationManager File operation manager.
@@ -23,7 +22,7 @@
  * @extends {cr.EventTarget}
  */
 function DirectoryModel(singleSelection, fileFilter,
-                        metadataProviderCache, fileSystemMetadata,
+                        metadataModel,
                         volumeManager, fileOperationManager) {
   this.fileListSelection_ = singleSelection ?
       new FileListSingleSelectionModel() : new FileListSelectionModel();
@@ -43,12 +42,11 @@
                                     this.onFilterChanged_.bind(this));
 
   this.currentFileListContext_ =
-      new FileListContext(fileFilter,  fileSystemMetadata);
+      new FileListContext(fileFilter,  metadataModel);
   this.currentDirContents_ =
       DirectoryContents.createForDirectory(this.currentFileListContext_, null);
 
-  this.metadataProviderCache_ = metadataProviderCache;
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   this.volumeManager_ = volumeManager;
   this.volumeManager_.volumeInfoList.addEventListener(
@@ -496,7 +494,7 @@
   }.bind(this);
 
   // Clear the table, and start scanning.
-  this.metadataProviderCache_.clearAll();
+  this.metadataModel_.clearAllCache();
   cr.dispatchSimpleEvent(this, 'scan-started');
   var fileList = this.getFileList();
   fileList.splice(0, fileList.length);
@@ -846,7 +844,7 @@
 
       then(function(newEntry) {
         // Refresh the cache.
-        this.fileSystemMetadata_.notifyEntriesCreated([newEntry]);
+        this.metadataModel_.notifyEntriesCreated([newEntry]);
         return new Promise(function(onFulfilled, onRejected) {
           dirContents.prefetchMetadata(
               [newEntry], false, onFulfilled.bind(null, newEntry));
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index 1d00a42..aa993f4a 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -54,15 +54,9 @@
   this.mediaImportHandler_ = null;
 
   /**
-   * @private {!MetadataProviderCache}
-   * @const
+   * @private {MetadataModel}
    */
-  this.metadataProviderCache_ = new MetadataProviderCache();
-
-  /**
-   * @private {FileSystemMetadata}
-   */
-  this.fileSystemMetadata_ = null;
+  this.metadataModel_ = null;
 
   /**
    * @private {ThumbnailModel}
@@ -490,7 +484,7 @@
         this.ui_.multiProfileShareDialog,
         assert(this.backgroundPage_.background.progressCenter),
         assert(this.fileOperationManager_),
-        assert(this.fileSystemMetadata_),
+        assert(this.metadataModel_),
         assert(this.thumbnailModel_),
         assert(this.directoryModel_),
         assert(this.volumeManager_),
@@ -694,10 +688,8 @@
 
     // Create the metadata cache.
     assert(this.volumeManager_);
-    this.fileSystemMetadata_ = FileSystemMetadata.create(
-        this.metadataProviderCache_,
-        this.volumeManager_);
-    this.thumbnailModel_ = new ThumbnailModel(this.fileSystemMetadata_);
+    this.metadataModel_ = MetadataModel.create(this.volumeManager_);
+    this.thumbnailModel_ = new ThumbnailModel(this.metadataModel_);
 
     // Create the root view of FileManager.
     assert(this.dialogDom_);
@@ -722,11 +714,11 @@
    * @private
    */
   FileManager.prototype.initAdditionalUI_ = function(callback) {
-    assert(this.fileSystemMetadata_);
+    assert(this.metadataModel_);
     assert(this.volumeManager_);
     assert(this.historyLoader_);
     assert(this.dialogDom_);
-    assert(this.fileSystemMetadata_);
+    assert(this.metadataModel_);
 
     // Cache nodes we'll be manipulating.
     var dom = this.dialogDom_;
@@ -741,14 +733,14 @@
     table.importEnabled = false;
     FileTable.decorate(
         table,
-        this.fileSystemMetadata_,
+        this.metadataModel_,
         this.volumeManager_,
         this.historyLoader_,
         this.dialogType == DialogType.FULL_PAGE);
     var grid = queryRequiredElement(dom, '.thumbnail-grid');
     FileGrid.decorate(
         grid,
-        this.fileSystemMetadata_,
+        this.metadataModel_,
         this.volumeManager_,
         this.historyLoader_);
 
@@ -839,12 +831,11 @@
 
     assert(this.volumeManager_);
     assert(this.fileOperationManager_);
-    assert(this.fileSystemMetadata_);
+    assert(this.metadataModel_);
     this.directoryModel_ = new DirectoryModel(
         singleSelection,
         this.fileFilter_,
-        this.metadataProviderCache_,
-        this.fileSystemMetadata_,
+        this.metadataModel_,
         this.volumeManager_,
         this.fileOperationManager_);
 
@@ -887,14 +878,13 @@
     this.metadataUpdateController_ = new MetadataUpdateController(
         this.ui_.listContainer,
         this.directoryModel_,
-        this.metadataProviderCache_,
-        this.fileSystemMetadata_);
+        this.metadataModel_);
 
     // Create task controller.
     this.taskController_ = new TaskController(
         this.dialogType,
         this.ui_,
-        this.fileSystemMetadata_,
+        this.metadataModel_,
         this.selectionHandler_,
         this.metadataUpdateController_,
         function() { return new FileTasks(this); }.bind(this));
@@ -929,7 +919,7 @@
         this.dialogType,
         this.ui_.dialogFooter,
         this.directoryModel_,
-        this.fileSystemMetadata_,
+        this.metadataModel_,
         this.volumeManager_,
         this.fileFilter_,
         this.namingController_,
@@ -948,7 +938,7 @@
     DirectoryTree.decorate(directoryTree,
                            assert(this.directoryModel_),
                            assert(this.volumeManager_),
-                           assert(this.fileSystemMetadata_),
+                           assert(this.metadataModel_),
                            fakeEntriesVisible);
     directoryTree.dataModel = new NavigationListModel(
         this.volumeManager_, this.folderShortcutsModel_);
@@ -1282,10 +1272,10 @@
   };
 
   /**
-   * @return {!FileSystemMetadata}
+   * @return {!MetadataModel}
    */
-  FileManager.prototype.getFileSystemMetadata = function() {
-    return assert(this.fileSystemMetadata_);
+  FileManager.prototype.getMetadataModel = function() {
+    return assert(this.metadataModel_);
   };
 
   /**
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 5443c9fa..5786fe70 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -133,7 +133,7 @@
     hasDirectory = hasDirectory || entry.isDirectory;
     if (!entry || hasDirectory)
       return false;
-    var metadata = fileManager.getFileSystemMetadata().getCache(
+    var metadata = fileManager.getMetadataModel().getCache(
         [entry], ['hosted', 'pinned'])[0];
     if (metadata.hosted)
       return false;
@@ -892,7 +892,7 @@
       return;
     var currentEntry;
     var error = false;
-    var fileSystemMetadata = fileManager.getFileSystemMetadata();
+    var metadataModel = fileManager.getMetadataModel();
     var steps = {
       // Pick an entry and pin it.
       start: function() {
@@ -911,14 +911,14 @@
         // Convert to boolean.
         error = !!chrome.runtime.lastError;
         if (error && pin) {
-          fileSystemMetadata.get([currentEntry], ['size']).then(
+          metadataModel.get([currentEntry], ['size']).then(
               function(results) {
                 steps.showError(results[0].size);
               });
           return;
         }
-        fileSystemMetadata.notifyEntriesChanged([currentEntry]);
-        fileSystemMetadata.get([currentEntry], ['pinned']).then(steps.updateUI);
+        metadataModel.notifyEntriesChanged([currentEntry]);
+        metadataModel.get([currentEntry], ['pinned']).then(steps.updateUI);
       },
 
       // Update the user interface according to the cache state.
diff --git a/ui/file_manager/file_manager/foreground/js/file_selection.js b/ui/file_manager/file_manager/foreground/js/file_selection.js
index edbf40e..3d2f852 100644
--- a/ui/file_manager/file_manager/foreground/js/file_selection.js
+++ b/ui/file_manager/file_manager/foreground/js/file_selection.js
@@ -109,7 +109,7 @@
  */
 FileSelection.prototype.completeInit = function() {
   if (!this.asyncInitPromise_) {
-    this.asyncInitPromise_ = this.fileManager_.getFileSystemMetadata().get(
+    this.asyncInitPromise_ = this.fileManager_.getMetadataModel().get(
         this.entries, ['availableOffline', 'contentMimeType']
     ).then(function(props) {
       var present = props.filter(function(p) { return p.availableOffline; });
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 5b405aa..b8459df9 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -504,14 +504,14 @@
   };
 
   var fm = this.fileManager_;
-  var fileSystemMetadata = this.fileManager_.getFileSystemMetadata();
+  var metadataModel = this.fileManager_.getMetadataModel();
   var entries = assert(this.entries_);
 
   var isDriveOffline = fm.volumeManager.getDriveConnectionState().type ===
       VolumeManagerCommon.DriveConnectionType.OFFLINE;
 
   if (fm.isOnDrive() && isDriveOffline) {
-    fileSystemMetadata.get(entries, ['availableOffline', 'hosted']).then(
+    metadataModel.get(entries, ['availableOffline', 'hosted']).then(
         function(props) {
           if (areAll(props, 'availableOffline')) {
             callback();
@@ -539,7 +539,7 @@
       VolumeManagerCommon.DriveConnectionType.METERED;
 
   if (fm.isOnDrive() && isOnMetered) {
-    fileSystemMetadata.get(entries, ['availableWhenMetered', 'size']).then(
+    metadataModel.get(entries, ['availableWhenMetered', 'size']).then(
         function(props) {
           if (areAll(props, 'availableWhenMetered')) {
             callback();
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index 6d5bb8d..f5e4809 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -55,7 +55,7 @@
       openSuggestAppsDialog: function(
           entry, onSuccess, onCancelled, onFailure) {}
     },
-    getFileSystemMetadata: function() {}
+    getMetadataModel: function() {}
   };
 }
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
index adc9be54..5ef1622 100644
--- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -24,7 +24,7 @@
  * @param {!ProgressCenter} progressCenter To notify starting copy operation.
  * @param {!FileOperationManager} fileOperationManager File operation manager
  *     instance.
- * @param {!FileSystemMetadata} fileSystemMetadata Metadata cache service.
+ * @param {!MetadataModel} metadataModel Metadata cache service.
  * @param {!ThumbnailModel} thumbnailModel
  * @param {!DirectoryModel} directoryModel Directory model instance.
  * @param {!VolumeManagerWrapper} volumeManager Volume manager instance.
@@ -38,7 +38,7 @@
                                 multiProfileShareDialog,
                                 progressCenter,
                                 fileOperationManager,
-                                fileSystemMetadata,
+                                metadataModel,
                                 thumbnailModel,
                                 directoryModel,
                                 volumeManager,
@@ -65,11 +65,11 @@
   this.fileOperationManager_ = fileOperationManager;
 
   /**
-   * @type {!FileSystemMetadata}
+   * @type {!MetadataModel}
    * @private
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   /**
    * @type {!ThumbnailModel}
@@ -1106,7 +1106,7 @@
     this.preloadThumbnailImage_(entries[0]);
   }
 
-  this.fileSystemMetadata_.get(entries, ['externalFileUrl']).then(
+  this.metadataModel_.get(entries, ['externalFileUrl']).then(
       function(metadataList) {
         // |Copy| is the only menu item affected by allDriveFilesAvailable_.
         // It could be open right now, update its UI.
diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js
index fdc23be..4ac3b91fe 100644
--- a/ui/file_manager/file_manager/foreground/js/main_scripts.js
+++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js
@@ -109,11 +109,12 @@
 //<include src="launch_param.js">
 //<include src="metadata/content_metadata_provider.js">
 //<include src="metadata/external_metadata_provider.js">
-//<include src="metadata/file_system_metadata.js">
 //<include src="metadata/file_system_metadata_provider.js">
 //<include src="metadata/metadata_cache.js">
 //<include src="metadata/metadata_cache_item.js">
 //<include src="metadata/metadata_item.js">
+//<include src="metadata/metadata_model.js">
+//<include src="metadata/multi_metadata_provider.js">
 //<include src="metadata/thumbnail_model.js">
 //<include src="metadata_update_controller.js">
 //<include src="naming_controller.js">
diff --git a/ui/file_manager/file_manager/foreground/js/main_window_component.js b/ui/file_manager/file_manager/foreground/js/main_window_component.js
index 754d3363..1a33690 100644
--- a/ui/file_manager/file_manager/foreground/js/main_window_component.js
+++ b/ui/file_manager/file_manager/foreground/js/main_window_component.js
@@ -282,7 +282,7 @@
             selection.indexes[0]);
         // If the item is in renaming process, we don't allow to change
         // directory.
-        if (!item.hasAttribute('renaming')) {
+        if (item && !item.hasAttribute('renaming')) {
           event.preventDefault();
           this.directoryModel_.changeDirectoryEntry(selection.entries[0]);
         }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp b/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp
index 669a54c..15bcbaf 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp
+++ b/ui/file_manager/file_manager/foreground/js/metadata/compiled_resources.gyp
@@ -18,6 +18,7 @@
 	  'function_parallel.js',
 	],
 	'externs': [
+          '../../../../externs/exif_entry.js',
           '../../../../externs/platform_worker.js',
 	]
       },
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
index d245b95..b263a90 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider.js
@@ -3,17 +3,15 @@
 // found in the LICENSE file.
 
 /**
- * @param {!MetadataProviderCache} cache
  * @param {!MessagePort=} opt_messagePort Message port overriding the default
  *     worker port.
  * @extends {NewMetadataProvider}
  * @constructor
  * @struct
  */
-function ContentMetadataProvider(cache, opt_messagePort) {
+function ContentMetadataProvider(opt_messagePort) {
   NewMetadataProvider.call(
       this,
-      cache,
       ContentMetadataProvider.PROPERTY_NAMES);
 
   /**
@@ -96,11 +94,14 @@
 /**
  * @override
  */
-ContentMetadataProvider.prototype.getImpl = function(requests) {
+ContentMetadataProvider.prototype.get = function(requests) {
+  if (!requests.length)
+    return Promise.resolve([]);
+
   var promises = [];
   for (var i = 0; i < requests.length; i++) {
     promises.push(new Promise(function(request, fulfill) {
-      this.fetch(request.entry, request.names, fulfill);
+      this.getImpl_(request.entry, request.names, fulfill);
     }.bind(this, requests[i])));
   }
   return Promise.all(promises);
@@ -112,8 +113,9 @@
  * @param {!Array<string>} names Requested metadata type.
  * @param {function(Object)} callback Callback expects a map from metadata type
  *     to metadata value. This callback is called asynchronously.
+ * @private
  */
-ContentMetadataProvider.prototype.fetch = function(entry, names, callback) {
+ContentMetadataProvider.prototype.getImpl_ = function(entry, names, callback) {
   if (entry.isDirectory) {
     setTimeout(callback.bind(null, {}), 0);
     return;
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
index e60977b..d77ec3c 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/content_metadata_provider_unittest.js
@@ -31,20 +31,21 @@
     },
     start: function() {}
   };
-  var cache = new MetadataProviderCache();
-  var provider = new ContentMetadataProvider(cache, port);
-  reportPromise(provider.get(
-      [entryA, entryB],
-      ['contentThumbnailUrl', 'contentThumbnailTransform']).then(
-          function(results) {
-            assertEquals(2, results.length);
-            assertEquals('filesystem://A,url', results[0].contentThumbnailUrl);
-            assertEquals(
-                'filesystem://A,transform',
-                results[0].contentThumbnailTransform);
-            assertEquals('filesystem://B,url', results[1].contentThumbnailUrl);
-            assertEquals(
-                'filesystem://B,transform',
-                results[1].contentThumbnailTransform);
-          }), callback);
+  var provider = new ContentMetadataProvider(port);
+  reportPromise(provider.get([
+    new MetadataRequest(
+        entryA, ['contentThumbnailUrl', 'contentThumbnailTransform']),
+    new MetadataRequest(
+        entryB, ['contentThumbnailUrl', 'contentThumbnailTransform'])
+  ]).then(function(results) {
+    assertEquals(2, results.length);
+    assertEquals('filesystem://A,url', results[0].contentThumbnailUrl);
+    assertEquals(
+        'filesystem://A,transform',
+        results[0].contentThumbnailTransform);
+    assertEquals('filesystem://B,url', results[1].contentThumbnailUrl);
+    assertEquals(
+        'filesystem://B,transform',
+        results[1].contentThumbnailTransform);
+  }), callback);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
index f6cc007..261072053 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider.js
@@ -6,14 +6,12 @@
  * Metadata provider for FileEntry#getMetadata.
  * TODO(hirono): Rename thumbnailUrl with externalThumbnailUrl.
  *
- * @param {!MetadataProviderCache} cache
  * @constructor
  * @extends {NewMetadataProvider}
  * @struct
  */
-function ExternalMetadataProvider(cache) {
-  NewMetadataProvider.call(
-      this, cache, ExternalMetadataProvider.PROPERTY_NAMES);
+function ExternalMetadataProvider() {
+  NewMetadataProvider.call(this, ExternalMetadataProvider.PROPERTY_NAMES);
 }
 
 /**
@@ -44,7 +42,9 @@
 /**
  * @override
  */
-ExternalMetadataProvider.prototype.getImpl = function(requests) {
+ExternalMetadataProvider.prototype.get = function(requests) {
+  if (!requests.length)
+    return Promise.resolve([]);
   return new Promise(function(fulfill) {
     var urls = [];
     for (var i = 0; i < requests.length; i++) {
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
index b5a0509..198ef3e 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/external_metadata_provider_unittest.js
@@ -34,20 +34,19 @@
     },
     runtime: {lastError: null}
   };
-  var cache = new MetadataProviderCache();
-  var provider = new ExternalMetadataProvider(cache);
-  reportPromise(provider.get(
-      [entryA, entryB],
-      ['modificationTime', 'size']).then(
-          function(results) {
-            assertEquals(2, results.length);
-            assertEquals(
-                new Date(2015, 0, 1).toString(),
-                results[0].modificationTime.toString());
-            assertEquals(1024, results[0].size);
-            assertEquals(
-                new Date(2015, 1, 2).toString(),
-                results[1].modificationTime.toString());
-            assertEquals(2048, results[1].size);
-          }), callback);
+  var provider = new ExternalMetadataProvider();
+  reportPromise(provider.get([
+    new MetadataRequest(entryA, ['modificationTime', 'size']),
+    new MetadataRequest(entryB, ['modificationTime', 'size']),
+  ]).then(function(results) {
+    assertEquals(2, results.length);
+    assertEquals(
+        new Date(2015, 0, 1).toString(),
+        results[0].modificationTime.toString());
+    assertEquals(1024, results[0].size);
+    assertEquals(
+        new Date(2015, 1, 2).toString(),
+        results[1].modificationTime.toString());
+    assertEquals(2048, results[1].size);
+  }), callback);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js
deleted file mode 100644
index 8841cf1..0000000
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata.js
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * @param {!MetadataProviderCache} cache
- * @param {!FileSystemMetadataProvider} fileSystemMetadataProvider
- * @param {!ExternalMetadataProvider} externalMetadataProvider
- * @param {!ContentMetadataProvider} contentMetadataProvider
- * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager
- * @constructor
- * @struct
- */
-function FileSystemMetadata(
-    cache,
-    fileSystemMetadataProvider,
-    externalMetadataProvider,
-    contentMetadataProvider,
-    volumeManager) {
-  /**
-   * @private {!MetadataProviderCache}
-   * @const
-   */
-  this.cache_ = cache;
-
-  /**
-   * @private {!FileSystemMetadataProvider}
-   * @const
-   */
-  this.fileSystemMetadataProvider_ = fileSystemMetadataProvider;
-
-  /**
-   * @private {!ExternalMetadataProvider}
-   * @const
-   */
-  this.externalMetadataProvider_ = externalMetadataProvider;
-
-  /**
-   * @private {!ContentMetadataProvider}
-   * @const
-   */
-  this.contentMetadataProvider_ = contentMetadataProvider;
-
-  /**
-   * @private {!VolumeManagerCommon.VolumeInfoProvider}
-   * @const
-   */
-  this.volumeManager_ = volumeManager;
-}
-
-/**
- * @param {!MetadataProviderCache} cache
- * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager
- * @return {!FileSystemMetadata}
- */
-FileSystemMetadata.create = function(cache, volumeManager) {
-  return new FileSystemMetadata(
-      cache,
-      new FileSystemMetadataProvider(cache),
-      new ExternalMetadataProvider(cache),
-      new ContentMetadataProvider(cache),
-      volumeManager);
-};
-
-/**
- * Obtains metadata for entries.
- * @param {!Array<!Entry>} entries Entries.
- * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Promise<!Array<!MetadataItem>>}
- */
-FileSystemMetadata.prototype.get = function(entries, names) {
-  var localEntries = [];
-  var externalEntries = [];
-  for (var i = 0; i < entries.length; i++) {
-    var volumeInfo = this.volumeManager_.getVolumeInfo(entries[i]);
-    if (volumeInfo &&
-        (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE ||
-         volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED)) {
-      externalEntries.push(entries[i]);
-    } else {
-      localEntries.push(entries[i]);
-    }
-  }
-
-  // Group property names.
-  var fileSystemPropertyNames = [];
-  var externalPropertyNames = [];
-  var contentPropertyNames = [];
-  var fallbackContentPropertyNames = [];
-  for (var i = 0; i < names.length; i++) {
-    var name = names[i];
-    var isFileSystemProperty =
-        FileSystemMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
-    var isExternalProperty =
-        ExternalMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
-    var isContentProperty =
-        ContentMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
-    assert(isFileSystemProperty || isExternalProperty || isContentProperty);
-    assert(!(isFileSystemProperty && isContentProperty));
-    // If the property can be obtained both from ExternalProvider and from
-    // ContentProvider, we can obtain the property from ExternalProvider without
-    // fetching file content. On the other hand, the values from
-    // ExternalProvider may be out of sync if the file is 'dirty'. Thus we
-    // fallback to ContentProvider if the file is dirty. See below.
-    if (isExternalProperty && isContentProperty) {
-      externalPropertyNames.push(name);
-      fallbackContentPropertyNames.push(name);
-      continue;
-    }
-    if (isFileSystemProperty)
-      fileSystemPropertyNames.push(name);
-    if (isExternalProperty)
-      externalPropertyNames.push(name);
-    if (isContentProperty)
-      contentPropertyNames.push(name);
-  }
-
-  // Obtain each group of property names.
-  var resultPromises = [];
-  var get = function(provider, entries, names) {
-    return provider.get(entries, names).then(function(results) {
-      return {entries: entries, results: results};
-    });
-  };
-  resultPromises.push(get(
-      this.fileSystemMetadataProvider_, localEntries, fileSystemPropertyNames));
-  resultPromises.push(get(
-      this.externalMetadataProvider_, externalEntries, externalPropertyNames));
-  resultPromises.push(get(
-      this.contentMetadataProvider_, entries, contentPropertyNames));
-  if (fallbackContentPropertyNames.length) {
-    var dirtyEntriesPromise = this.externalMetadataProvider_.get(
-        externalEntries, ['dirty']).then(function(results) {
-          return externalEntries.filter(function(entry, index) {
-            return results[index].dirty;
-          });
-        });
-    resultPromises.push(dirtyEntriesPromise.then(function(dirtyEntries) {
-      return get(
-          this.contentMetadataProvider_,
-          localEntries.concat(dirtyEntries),
-          fallbackContentPropertyNames);
-    }.bind(this)));
-  }
-
-  // Merge results.
-  return Promise.all(resultPromises).then(function(resultsList) {
-    var integratedResults = {};
-    for (var i = 0; i < resultsList.length; i++) {
-      var inEntries = resultsList[i].entries;
-      var results = resultsList[i].results;
-      for (var j = 0; j < inEntries.length; j++) {
-        var url = inEntries[j].toURL();
-        integratedResults[url] = integratedResults[url] || new MetadataItem();
-        for (var name in results[j]) {
-          integratedResults[url][name] = results[j][name];
-        }
-      }
-    }
-    return entries.map(function(entry) {
-      return integratedResults[entry.toURL()];
-    });
-  });
-};
-
-/**
- * Obtains metadata cache for entries.
- * @param {!Array<!Entry>} entries Entries.
- * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Array<!MetadataItem>}
- */
-FileSystemMetadata.prototype.getCache = function(entries, names) {
-  return this.cache_.get(entries, names);
-};
-
-/**
- * Clears old metadata for newly created entries.
- * @param {!Array<!Entry>} entries
- */
-FileSystemMetadata.prototype.notifyEntriesCreated = function(entries) {
-  this.cache_.clear(util.entriesToURLs(entries));
-};
-
-/**
- * Clears metadata for deleted entries.
- * @param {!Array<string>} urls Note it is not an entry list because we cannot
- *     obtain entries after removing them from the file system.
- */
-FileSystemMetadata.prototype.notifyEntriesRemoved = function(urls) {
-  this.cache_.clear(urls);
-};
-
-/**
- * Invalidates metadata for updated entries.
- * @param {!Array<!Entry>} entries
- */
-FileSystemMetadata.prototype.notifyEntriesChanged = function(entries) {
-  this.cache_.invalidate(this.cache_.generateRequestId(), entries);
-};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
index 01c8519..41b40f6f 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
@@ -5,14 +5,12 @@
 /**
  * Metadata provider for FileEntry#getMetadata.
  *
- * @param {!MetadataProviderCache} cache
  * @constructor
  * @extends {NewMetadataProvider}
  * @struct
  */
-function FileSystemMetadataProvider(cache) {
-  NewMetadataProvider.call(
-      this, cache, FileSystemMetadataProvider.PROPERTY_NAMES);
+function FileSystemMetadataProvider() {
+  NewMetadataProvider.call(this, FileSystemMetadataProvider.PROPERTY_NAMES);
 }
 
 /**
@@ -27,7 +25,9 @@
 /**
  * @override
  */
-FileSystemMetadataProvider.prototype.getImpl = function(requests) {
+FileSystemMetadataProvider.prototype.get = function(requests) {
+  if (!requests.length)
+    return Promise.resolve([]);
   return Promise.all(requests.map(function(request) {
     return Promise.all([
         new Promise(function(fulfill, reject) {
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
index 3f81abd..bd90df8 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider_unittest.js
@@ -40,45 +40,44 @@
 }
 
 function testFileSystemMetadataProviderBasic(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new FileSystemMetadataProvider(cache);
-  reportPromise(provider.get(
-      [entryA, entryB],
-      ['modificationTime', 'size', 'contentMimeType',
-       'present', 'availableOffline']).then(
-          function(results) {
-            assertEquals(2, results.length);
-            assertEquals(
-                new Date(2015, 1, 1).toString(),
-                results[0].modificationTime.toString());
-            assertEquals(1024, results[0].size);
-            assertEquals('application/A', results[0].contentMimeType);
-            assertTrue(results[0].present);
-            assertTrue(results[0].availableOffline);
-            assertEquals(
-                new Date(2015, 2, 2).toString(),
-                results[1].modificationTime.toString());
-            assertEquals(2048, results[1].size);
-            assertEquals('application/B', results[1].contentMimeType);
-            assertTrue(results[1].present);
-            assertTrue(results[1].availableOffline);
-          }), callback);
+  var provider = new FileSystemMetadataProvider();
+  var names = [
+    'modificationTime', 'size', 'contentMimeType', 'present',
+    'availableOffline'];
+  reportPromise(provider.get([
+    new MetadataRequest(entryA, names),
+    new MetadataRequest(entryB, names)
+  ]).then(function(results) {
+    assertEquals(2, results.length);
+    assertEquals(
+        new Date(2015, 1, 1).toString(),
+        results[0].modificationTime.toString());
+    assertEquals(1024, results[0].size);
+    assertEquals('application/A', results[0].contentMimeType);
+    assertTrue(results[0].present);
+    assertTrue(results[0].availableOffline);
+    assertEquals(
+        new Date(2015, 2, 2).toString(),
+        results[1].modificationTime.toString());
+    assertEquals(2048, results[1].size);
+    assertEquals('application/B', results[1].contentMimeType);
+    assertTrue(results[1].present);
+    assertTrue(results[1].availableOffline);
+  }), callback);
 }
 
 function testFileSystemMetadataProviderPartialRequest(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new FileSystemMetadataProvider(cache);
+  var provider = new FileSystemMetadataProvider();
   reportPromise(provider.get(
-      [entryA],
-      ['modificationTime', 'size']).then(
-          function(results) {
-            assertEquals(1, results.length);
-            assertEquals(
-                new Date(2015, 1, 1).toString(),
-                results[0].modificationTime.toString());
-            assertEquals(1024, results[0].size);
-            // When contentMimeType is not requested, this shouldn't try to get
-            // MIME type.
-            assertFalse(chrome.fileManagerPrivate.isGetMimeTypeCalled_);
-          }), callback);
+      [new MetadataRequest(entryA, ['modificationTime', 'size'])]).then(
+      function(results) {
+        assertEquals(1, results.length);
+        assertEquals(
+            new Date(2015, 1, 1).toString(),
+            results[0].modificationTime.toString());
+        assertEquals(1024, results[0].size);
+        // When contentMimeType is not requested, this shouldn't try to get
+        // MIME type.
+        assertFalse(chrome.fileManagerPrivate.isGetMimeTypeCalled_);
+      }), callback);
 }
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js
deleted file mode 100644
index 1650b7c..0000000
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.js
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-var entryA = {
-  toURL: function() { return 'filesystem://A'; }
-};
-
-var entryB = {
-  toURL: function() { return 'filesystem://B'; }
-};
-
-var entryC = {
-  toURL: function() { return 'filesystem://C'; }
-};
-
-var volumeManager = {
-  getVolumeInfo: function(entry) {
-    if (entry.toURL() === 'filesystem://A') {
-      return {
-        volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS
-      };
-    } else if (entry.toURL() === 'filesystem://B') {
-      return {
-        volumeType: VolumeManagerCommon.VolumeType.DRIVE
-      };
-    } else if (entry.toURL() === 'filesystem://C') {
-      return {
-        volumeType: VolumeManagerCommon.VolumeType.DRIVE
-      };
-    }
-    assertNotReached();
-  }
-};
-
-function testFileSystemMetadataBasic(callback) {
-  var cache = new MetadataProviderCache();
-  var model = new FileSystemMetadata(
-      cache,
-      // Mocking FileSystemMetadataProvider.
-      {
-        get: function(entries, names) {
-          assertEquals(1, entries.length);
-          assertEquals('filesystem://A', entries[0].toURL());
-          assertArrayEquals(['size', 'modificationTime'], names);
-          return Promise.resolve(
-              [{modificationTime: new Date(2015, 0, 1), size: 1024}]);
-        }
-      },
-      // Mocking ExternalMetadataProvider.
-      {
-        get: function(entries, names) {
-          assertEquals(1, entries.length);
-          assertEquals('filesystem://B', entries[0].toURL());
-          assertArrayEquals(['size', 'modificationTime'], names);
-          return Promise.resolve(
-              [{modificationTime: new Date(2015, 1, 2), size: 2048}]);
-        }
-      },
-      // Mocking ContentMetadataProvider.
-      {
-        get: function(entries, names) {
-          assertEquals(2, entries.length);
-          assertEquals('filesystem://A', entries[0].toURL());
-          assertEquals('filesystem://B', entries[1].toURL());
-          assertArrayEquals(['contentThumbnailUrl'], names);
-          return Promise.resolve([
-            {contentThumbnailUrl: 'THUMBNAIL_URL_A'},
-            {contentThumbnailUrl: 'THUMBNAIL_URL_B'}
-          ]);
-        }
-      },
-      // Mocking VolumeManagerWrapper.
-      volumeManager);
-  reportPromise(
-      model.get(
-          [entryA, entryB],
-          ['size', 'modificationTime', 'contentThumbnailUrl']).then(
-          function(results) {
-            assertEquals(2, results.length);
-            assertEquals(
-                new Date(2015, 0, 1).toString(),
-                results[0].modificationTime.toString());
-            assertEquals(1024, results[0].size);
-            assertEquals('THUMBNAIL_URL_A', results[0].contentThumbnailUrl);
-            assertEquals(
-                new Date(2015, 1, 2).toString(),
-                results[1].modificationTime.toString());
-            assertEquals(2048, results[1].size);
-            assertEquals('THUMBNAIL_URL_B', results[1].contentThumbnailUrl);
-          }), callback);
-}
-
-function testFileSystemMetadataExternalAndContentProperty(callback) {
-  var cache = new MetadataProviderCache();
-  var model = new FileSystemMetadata(
-      cache,
-      // Mocking FileSystemMetadataProvider.
-      {
-        get: function(entries, names) {
-          assertEquals(0, names.length);
-          return Promise.resolve([{}]);
-        }
-      },
-      // Mocking ExternalMetadataProvider.
-      {
-        get: function(entries, names) {
-          assertEquals(2, entries.length);
-          assertEquals('filesystem://B', entries[0].toURL());
-          assertEquals('filesystem://C', entries[1].toURL());
-          return Promise.resolve([
-            {dirty: false, imageWidth: 200},
-            {dirty: true, imageWidth: 400}
-          ]);
-        }
-      },
-      // Mocking ContentMetadataProvider.
-      {
-        get: function(entries, names) {
-          if (names.length == 0)
-            return Promise.resolve(entries.map(function() { return {}; }));
-          assertEquals(2, entries.length);
-          assertEquals('filesystem://A', entries[0].toURL());
-          assertEquals('filesystem://C', entries[1].toURL());
-          assertArrayEquals(['imageWidth'], names);
-          return Promise.resolve([
-            {imageWidth: 100},
-            {imageWidth: 300}
-          ]);
-        }
-      },
-      // Mocking VolumeManagerWrapper.
-      volumeManager);
-  reportPromise(model.get([entryA, entryB, entryC], ['imageWidth']).then(
-      function(results) {
-        assertEquals(3, results.length);
-        assertEquals(100, results[0].imageWidth);
-        assertEquals(200, results[1].imageWidth);
-        assertEquals(300, results[2].imageWidth);
-      }), callback);
-}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js
new file mode 100644
index 0000000..bd46fa8
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model.js
@@ -0,0 +1,240 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @param {!NewMetadataProvider} rawProvider
+ * @constructor
+ * @struct
+ */
+function MetadataModel(rawProvider) {
+  /**
+   * @private {!NewMetadataProvider}
+   * @const
+   */
+  this.rawProvider_ = rawProvider;
+
+  /**
+   * @private {!MetadataProviderCache}
+   * @const
+   */
+  this.cache_ = new MetadataProviderCache();
+
+  /**
+   * @private {!Array<!MetadataProviderCallbackRequest<T>>}
+   * @const
+   */
+  this.callbackRequests_ = [];
+}
+
+/**
+ * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager
+ * @return {!MetadataModel}
+ */
+MetadataModel.create = function(volumeManager) {
+  return new MetadataModel(
+      new MultiMetadataProvider(
+          new FileSystemMetadataProvider(),
+          new ExternalMetadataProvider(),
+          new ContentMetadataProvider(),
+          volumeManager));
+};
+
+/**
+ * @return {!NewMetadataProvider}
+ */
+MetadataModel.prototype.getProvider = function() {
+  return this.rawProvider_;
+};
+
+/**
+ * Obtains metadata for entries.
+ * @param {!Array<!Entry>} entries Entries.
+ * @param {!Array<string>} names Metadata property names to be obtained.
+ * @return {!Promise<!Array<!MetadataItem>>}
+ */
+MetadataModel.prototype.get = function(entries, names) {
+  this.rawProvider_.checkPropertyNames(names);
+
+  // Check if the results are cached or not.
+  if (this.cache_.hasFreshCache(entries, names))
+    return Promise.resolve(this.getCache(entries, names));
+
+  // The LRU cache may be cached out when the callback is completed.
+  // To hold cached values, create snapshot of the cache for entries.
+  var requestId = this.cache_.generateRequestId();
+  var snapshot = this.cache_.createSnapshot(entries);
+  var requests = snapshot.createRequests(entries, names);
+  snapshot.startRequests(requestId, requests);
+  this.cache_.startRequests(requestId, requests);
+
+  // Register callback.
+  var promise = new Promise(function(fulfill) {
+    this.callbackRequests_.push(new MetadataProviderCallbackRequest(
+        entries, names, snapshot, fulfill));
+  }.bind(this));
+
+  // If the requests are not empty, call the requests.
+  if (requests.length) {
+    this.rawProvider_.get(requests).then(function(list) {
+      // Obtain requested entries and ensure all the requested properties are
+      // contained in the result.
+      var requestedEntries = [];
+      for (var i = 0; i < requests.length; i++) {
+        requestedEntries.push(requests[i].entry);
+        for (var j = 0; j < requests[i].names.length; j++) {
+          var name = requests[i].names[j];
+          if (!(name in list[i]))
+            list[i][name] = undefined;
+        }
+      }
+
+      // Store cache.
+      this.cache_.storeProperties(requestId, requestedEntries, list);
+
+      // Invoke callbacks.
+      var i = 0;
+      while (i < this.callbackRequests_.length) {
+        if (this.callbackRequests_[i].storeProperties(
+            requestId, requestedEntries, list)) {
+          // Callback was called.
+          this.callbackRequests_.splice(i, 1);
+        } else {
+          i++;
+        }
+      }
+    }.bind(this));
+  }
+
+  return promise;
+};
+
+/**
+ * Obtains metadata cache for entries.
+ * @param {!Array<!Entry>} entries Entries.
+ * @param {!Array<string>} names Metadata property names to be obtained.
+ * @return {!Array<!MetadataItem>}
+ */
+MetadataModel.prototype.getCache = function(entries, names) {
+  // Check if the property name is correct or not.
+  this.rawProvider_.checkPropertyNames(names);
+  return this.cache_.get(entries, names);
+};
+
+/**
+ * Clears old metadata for newly created entries.
+ * @param {!Array<!Entry>} entries
+ */
+MetadataModel.prototype.notifyEntriesCreated = function(entries) {
+  this.cache_.clear(util.entriesToURLs(entries));
+};
+
+/**
+ * Clears metadata for deleted entries.
+ * @param {!Array<string>} urls Note it is not an entry list because we cannot
+ *     obtain entries after removing them from the file system.
+ */
+MetadataModel.prototype.notifyEntriesRemoved = function(urls) {
+  this.cache_.clear(urls);
+};
+
+/**
+ * Invalidates metadata for updated entries.
+ * @param {!Array<!Entry>} entries
+ */
+MetadataModel.prototype.notifyEntriesChanged = function(entries) {
+  this.cache_.invalidate(this.cache_.generateRequestId(), entries);
+};
+
+/**
+ * Clears all cache.
+ */
+MetadataModel.prototype.clearAllCache = function() {
+  this.cache_.clearAll();
+};
+
+/**
+ * Adds event listener to internal cache object.
+ * @param {string} type
+ * @param {function(Event):undefined} callback
+ */
+MetadataModel.prototype.addEventListener = function(type, callback) {
+  this.cache_.addEventListener(type, callback);
+};
+
+/**
+ * @param {!Array<!Entry>} entries
+ * @param {!Array<string>} names
+ * @param {!MetadataCacheSet} cache
+ * @param {function(!MetadataItem):undefined} fulfill
+ * @constructor
+ * @struct
+ */
+function MetadataProviderCallbackRequest(entries, names, cache, fulfill) {
+  /**
+   * @private {!Array<!Entry>}
+   * @const
+   */
+  this.entries_ = entries;
+
+  /**
+   * @private {!Array<string>}
+   * @const
+   */
+  this.names_ = names;
+
+  /**
+   * @private {!MetadataCacheSet}
+   * @const
+   */
+  this.cache_ = cache;
+
+  /**
+   * @private {function(!MetadataItem):undefined}
+   * @const
+   */
+  this.fulfill_ = fulfill;
+}
+
+/**
+ * Stores properties to snapshot cache of the callback request.
+ * If all the requested property are served, it invokes the callback.
+ * @param {number} requestId
+ * @param {!Array<!Entry>} entries
+ * @param {!Array<!MetadataItem>} objects
+ * @return {boolean} Whether the callback is invoked or not.
+ */
+MetadataProviderCallbackRequest.prototype.storeProperties = function(
+    requestId, entries, objects) {
+  this.cache_.storeProperties(requestId, entries, objects);
+  if (this.cache_.hasFreshCache(this.entries_, this.names_)) {
+    this.fulfill_(this.cache_.get(this.entries_, this.names_));
+    return true;
+  }
+  return false;
+};
+
+/**
+ * Helper wrapper for LRUCache.
+ * @constructor
+ * @extends {MetadataCacheSet}
+ * @struct
+ */
+function MetadataProviderCache() {
+  MetadataCacheSet.call(this, new MetadataCacheSetStorageForObject({}));
+
+  /**
+   * @private {number}
+   */
+  this.requestIdCounter_ = 0;
+}
+
+MetadataProviderCache.prototype.__proto__ = MetadataCacheSet.prototype;
+
+/**
+ * Generates a unique request ID every time when it is called.
+ * @return {number}
+ */
+MetadataProviderCache.prototype.generateRequestId = function() {
+  return this.requestIdCounter_++;
+};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html
similarity index 88%
rename from ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html
rename to ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html
index 476242cd..974816d 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.html
@@ -14,6 +14,7 @@
 <script src="../../../common/js/unittest_util.js"></script>
 <script src="metadata_cache_item.js"></script>
 <script src="metadata_item.js"></script>
+<script src="metadata_model.js"></script>
 <script src="new_metadata_provider.js"></script>
 
-<script src="new_metadata_provider_unittest.js"></script>
+<script src="metadata_model_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js
new file mode 100644
index 0000000..64dd6c9e
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/metadata_model_unittest.js
@@ -0,0 +1,172 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+function TestMetadataProvider() {
+  NewMetadataProvider.call(this, ['property', 'propertyA', 'propertyB']);
+  this.requestCount = 0;
+}
+
+TestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+TestMetadataProvider.prototype.get = function(requests) {
+  this.requestCount++;
+  return Promise.resolve(requests.map(function(request) {
+    var entry = request.entry;
+    var names = request.names;
+    var result = {};
+    for (var i = 0; i < names.length; i++) {
+      result[names[i]] = entry.toURL() + ':' + names[i];
+    }
+    return result;
+  }));
+};
+
+function TestEmptyMetadataProvider() {
+  NewMetadataProvider.call(this, ['property']);
+}
+
+TestEmptyMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+TestEmptyMetadataProvider.prototype.get = function(requests) {
+  return Promise.resolve(requests.map(function() {
+    return {};
+  }));
+};
+
+function ManualTestMetadataProvider() {
+  NewMetadataProvider.call(
+      this, ['propertyA', 'propertyB', 'propertyC']);
+  this.callback = [];
+}
+
+ManualTestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+ManualTestMetadataProvider.prototype.get = function(requests) {
+  return new Promise(function(fulfill) {
+    this.callback.push(fulfill);
+  }.bind(this));
+};
+
+var entryA = {
+  toURL: function() { return "filesystem://A"; }
+};
+
+var entryB = {
+  toURL: function() { return "filesystem://B"; }
+};
+
+function testMetadataModelBasic(callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  reportPromise(model.get([entryA, entryB], ['property']).then(
+      function(results) {
+        assertEquals(1, model.getProvider().requestCount);
+        assertEquals('filesystem://A:property', results[0].property);
+        assertEquals('filesystem://B:property', results[1].property);
+      }), callback);
+}
+
+function testMetadataModelRequestForCachedProperty(callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  reportPromise(model.get([entryA, entryB], ['property']).then(
+      function() {
+        // All the result should be cached here.
+        return model.get([entryA, entryB], ['property']);
+      }).then(function(results) {
+        assertEquals(1, model.getProvider().requestCount);
+        assertEquals('filesystem://A:property', results[0].property);
+        assertEquals('filesystem://B:property', results[1].property);
+      }), callback);
+}
+
+function testMetadataModelRequestForCachedAndNonCachedProperty(callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  reportPromise(model.get([entryA, entryB], ['propertyA']).then(
+      function() {
+        assertEquals(1, model.getProvider().requestCount);
+        // propertyB has not been cached here.
+        return model.get([entryA, entryB], ['propertyA', 'propertyB']);
+      }).then(function(results) {
+        assertEquals(2, model.getProvider().requestCount);
+        assertEquals('filesystem://A:propertyA', results[0].propertyA);
+        assertEquals('filesystem://A:propertyB', results[0].propertyB);
+        assertEquals('filesystem://B:propertyA', results[1].propertyA);
+        assertEquals('filesystem://B:propertyB', results[1].propertyB);
+      }), callback);
+}
+
+function testMetadataModelRequestForCachedAndNonCachedEntry(callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  reportPromise(model.get([entryA], ['property']).then(
+      function() {
+        assertEquals(1, model.getProvider().requestCount);
+        // entryB has not been cached here.
+        return model.get([entryA, entryB], ['property']);
+      }).then(function(results) {
+        assertEquals(2, model.getProvider().requestCount);
+        assertEquals('filesystem://A:property', results[0].property);
+        assertEquals('filesystem://B:property', results[1].property);
+      }), callback);
+}
+
+function testMetadataModelRequestBeforeCompletingPreviousRequest(
+    callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  model.get([entryA], ['property']);
+  assertEquals(1, model.getProvider().requestCount);
+  // The result of first call has not been fetched yet.
+  reportPromise(model.get([entryA], ['property']).then(
+      function(results) {
+        assertEquals(1, model.getProvider().requestCount);
+        assertEquals('filesystem://A:property', results[0].property);
+      }), callback);
+}
+
+function testMetadataModelNotUpdateCachedResultAfterRequest(
+    callback) {
+  var model = new MetadataModel(new ManualTestMetadataProvider());
+  var promise = model.get([entryA], ['propertyA']);
+  model.getProvider().callback[0]([{propertyA: 'valueA1'}]);
+  reportPromise(promise.then(function() {
+    // 'propertyA' is cached here.
+    var promise1 = model.get([entryA], ['propertyA', 'propertyB']);
+    var promise2 = model.get([entryA], ['propertyC']);
+    // Returns propertyC.
+    model.getProvider().callback[2](
+        [{propertyA: 'valueA2', propertyC: 'valueC'}]);
+    model.getProvider().callback[1]([{propertyB: 'valueB'}]);
+    return Promise.all([promise1, promise2]);
+  }).then(function(results) {
+    // The result should be cached value at the time when get was called.
+    assertEquals('valueA1', results[0][0].propertyA);
+    assertEquals('valueB', results[0][0].propertyB);
+    assertEquals('valueC', results[1][0].propertyC);
+  }), callback);
+}
+
+function testMetadataModelGetCache(callback) {
+  var model = new MetadataModel(new TestMetadataProvider());
+  var promise = model.get([entryA], ['property']);
+  var cache = model.getCache([entryA], ['property']);
+  assertEquals(null, cache[0].property);
+  reportPromise(promise.then(function() {
+    var cache = model.getCache([entryA], ['property']);
+    assertEquals(1, model.getProvider().requestCount);
+    assertEquals('filesystem://A:property', cache[0].property);
+  }), callback);
+}
+
+function testMetadataModelUnknownProperty() {
+  var model = new MetadataModel(new TestMetadataProvider());
+  assertThrows(function() {
+    model.get([entryA], ['unknown']);
+  });
+}
+
+function testMetadataModelEmptyResult(callback) {
+  var model = new MetadataModel(new TestEmptyMetadataProvider());
+  // getImpl returns empty result.
+  reportPromise(model.get([entryA], ['property']).then(function(results) {
+    assertEquals(undefined, results[0].property);
+  }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
new file mode 100644
index 0000000..ae1a123
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider.js
@@ -0,0 +1,170 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @param {!FileSystemMetadataProvider} fileSystemMetadataProvider
+ * @param {!ExternalMetadataProvider} externalMetadataProvider
+ * @param {!ContentMetadataProvider} contentMetadataProvider
+ * @param {!VolumeManagerCommon.VolumeInfoProvider} volumeManager
+ * @constructor
+ * @extends {NewMetadataProvider}
+ * @struct
+ */
+function MultiMetadataProvider(
+    fileSystemMetadataProvider,
+    externalMetadataProvider,
+    contentMetadataProvider,
+    volumeManager) {
+  NewMetadataProvider.call(
+      this,
+      FileSystemMetadataProvider.PROPERTY_NAMES.concat(
+          ExternalMetadataProvider.PROPERTY_NAMES).concat(
+              ContentMetadataProvider.PROPERTY_NAMES));
+
+  /**
+   * @private {!FileSystemMetadataProvider}
+   * @const
+   */
+  this.fileSystemMetadataProvider_ = fileSystemMetadataProvider;
+
+  /**
+   * @private {!ExternalMetadataProvider}
+   * @const
+   */
+  this.externalMetadataProvider_ = externalMetadataProvider;
+
+  /**
+   * @private {!ContentMetadataProvider}
+   * @const
+   */
+  this.contentMetadataProvider_ = contentMetadataProvider;
+
+  /**
+   * @private {!VolumeManagerCommon.VolumeInfoProvider}
+   * @const
+   */
+  this.volumeManager_ = volumeManager;
+}
+
+MultiMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
+
+/**
+ * Obtains metadata for entries.
+ * @param {!Array<!MetadataRequest>} requests
+ * @return {!Promise<!Array<!MetadataItem>>}
+ */
+MultiMetadataProvider.prototype.get = function(requests) {
+  var fileSystemRequests = [];
+  var externalRequests = [];
+  var contentRequests = [];
+  var fallbackContentRequests = [];
+  requests.forEach(function(request) {
+    // Group property names.
+    var fileSystemPropertyNames = [];
+    var externalPropertyNames = [];
+    var contentPropertyNames = [];
+    var fallbackContentPropertyNames = [];
+    for (var i = 0; i < request.names.length; i++) {
+      var name = request.names[i];
+      var isFileSystemProperty =
+          FileSystemMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
+      var isExternalProperty =
+          ExternalMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
+      var isContentProperty =
+          ContentMetadataProvider.PROPERTY_NAMES.indexOf(name) !== -1;
+      assert(isFileSystemProperty || isExternalProperty || isContentProperty);
+      assert(!(isFileSystemProperty && isContentProperty));
+      // If the property can be obtained both from ExternalProvider and from
+      // ContentProvider, we can obtain the property from ExternalProvider
+      // without fetching file content. On the other hand, the values from
+      // ExternalProvider may be out of sync if the file is 'dirty'. Thus we
+      // fallback to ContentProvider if the file is dirty. See below.
+      if (isExternalProperty && isContentProperty) {
+        externalPropertyNames.push(name);
+        fallbackContentPropertyNames.push(name);
+        continue;
+      }
+      if (isFileSystemProperty)
+        fileSystemPropertyNames.push(name);
+      if (isExternalProperty)
+        externalPropertyNames.push(name);
+      if (isContentProperty)
+        contentPropertyNames.push(name);
+    }
+    var volumeInfo = this.volumeManager_.getVolumeInfo(request.entry);
+    var addRequests = function(list, names) {
+      if (names.length)
+        list.push(new MetadataRequest(request.entry, names));
+    };
+    if (volumeInfo &&
+        (volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE ||
+         volumeInfo.volumeType === VolumeManagerCommon.VolumeType.PROVIDED)) {
+      if (fallbackContentPropertyNames.length &&
+          externalPropertyNames.indexOf('dirty') === -1) {
+        externalPropertyNames.push('dirty');
+      }
+      addRequests(externalRequests, externalPropertyNames);
+      addRequests(contentRequests, contentPropertyNames);
+      addRequests(fallbackContentRequests, fallbackContentPropertyNames);
+    } else {
+      addRequests(fileSystemRequests, fileSystemPropertyNames);
+      addRequests(
+          contentRequests,
+          contentPropertyNames.concat(fallbackContentPropertyNames));
+    }
+  }.bind(this));
+
+  var get = function(provider, inRequests) {
+    return provider.get(inRequests).then(function(results) {
+      return {
+        requests: inRequests,
+        results: results
+      };
+    });
+  };
+  var fileSystemPromise = get(
+      this.fileSystemMetadataProvider_, fileSystemRequests);
+  var externalPromise = get(this.externalMetadataProvider_, externalRequests);
+  var contentPromise = get(this.contentMetadataProvider_, contentRequests);
+  var fallbackContentPromise = externalPromise.then(
+      function(requestsAndResults) {
+        var requests = requestsAndResults.requests;
+        var results = requestsAndResults.results;
+        var dirtyMap = [];
+        for (var i = 0; i < results.length; i++) {
+          dirtyMap[requests[i].entry.toURL()] = results[i].dirty;
+        }
+        return get(
+            this.contentMetadataProvider_,
+            fallbackContentRequests.filter(
+                function(request) {
+                  return dirtyMap[request.entry.toURL()];
+                }));
+      }.bind(this));
+
+  // Merge results.
+  return Promise.all([
+    fileSystemPromise,
+    externalPromise,
+    contentPromise,
+    fallbackContentPromise
+  ]).then(function(resultsList) {
+    var integratedResults = {};
+    for (var i = 0; i < resultsList.length; i++) {
+      var inRequests = resultsList[i].requests;
+      var results = resultsList[i].results;
+      assert(inRequests.length === results.length);
+      for (var j = 0; j < results.length; j++) {
+        var url = inRequests[j].entry.toURL();
+        integratedResults[url] = integratedResults[url] || new MetadataItem();
+        for (var name in results[j]) {
+          integratedResults[url][name] = results[j][name];
+        }
+      }
+    }
+    return requests.map(function(request) {
+      return integratedResults[request.entry.toURL()] || new MetadataItem();
+    });
+  });
+};
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html
similarity index 89%
rename from ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html
rename to ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html
index 7c23ebc7..2d2bc622 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.html
@@ -16,9 +16,9 @@
 <script src="../../../common/js/volume_manager_common.js"></script>
 <script src="content_metadata_provider.js"></script>
 <script src="external_metadata_provider.js"></script>
-<script src="file_system_metadata.js"></script>
 <script src="file_system_metadata_provider.js"></script>
 <script src="metadata_cache_item.js"></script>
 <script src="metadata_item.js"></script>
+<script src="multi_metadata_provider.js"></script>
 
-<script src="file_system_metadata_unittest.js"></script>
+<script src="multi_metadata_provider_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js
new file mode 100644
index 0000000..41fcfdea
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/js/metadata/multi_metadata_provider_unittest.js
@@ -0,0 +1,145 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var entryA = {
+  toURL: function() { return 'filesystem://A'; }
+};
+
+var entryB = {
+  toURL: function() { return 'filesystem://B'; }
+};
+
+var entryC = {
+  toURL: function() { return 'filesystem://C'; }
+};
+
+var volumeManager = {
+  getVolumeInfo: function(entry) {
+    if (entry.toURL() === 'filesystem://A') {
+      return {
+        volumeType: VolumeManagerCommon.VolumeType.DOWNLOADS
+      };
+    } else if (entry.toURL() === 'filesystem://B') {
+      return {
+        volumeType: VolumeManagerCommon.VolumeType.DRIVE
+      };
+    } else if (entry.toURL() === 'filesystem://C') {
+      return {
+        volumeType: VolumeManagerCommon.VolumeType.DRIVE
+      };
+    }
+    assertNotReached();
+  }
+};
+
+function testMultiMetadataProviderBasic(callback) {
+  var model = new MultiMetadataProvider(
+      // Mocking FileSystemMetadataProvider.
+      {
+        get: function(requests) {
+          assertEquals(1, requests.length);
+          assertEquals('filesystem://A', requests[0].entry.toURL());
+          assertArrayEquals(['size', 'modificationTime'], requests[0].names);
+          return Promise.resolve(
+              [{modificationTime: new Date(2015, 0, 1), size: 1024}]);
+        }
+      },
+      // Mocking ExternalMetadataProvider.
+      {
+        get: function(requests) {
+          assertEquals(1, requests.length);
+          assertEquals('filesystem://B', requests[0].entry.toURL());
+          assertArrayEquals(['size', 'modificationTime'], requests[0].names);
+          return Promise.resolve(
+              [{modificationTime: new Date(2015, 1, 2), size: 2048}]);
+        }
+      },
+      // Mocking ContentMetadataProvider.
+      {
+        get: function(requests) {
+          if (requests.length === 0)
+            return Promise.resolve([]);
+          assertEquals(2, requests.length);
+          assertEquals('filesystem://A', requests[0].entry.toURL());
+          assertEquals('filesystem://B', requests[1].entry.toURL());
+          assertArrayEquals(['contentThumbnailUrl'], requests[0].names);
+          assertArrayEquals(['contentThumbnailUrl'], requests[1].names);
+          return Promise.resolve([
+            {contentThumbnailUrl: 'THUMBNAIL_URL_A'},
+            {contentThumbnailUrl: 'THUMBNAIL_URL_B'}
+          ]);
+        }
+      },
+      // Mocking VolumeManagerWrapper.
+      volumeManager);
+  reportPromise(model.get([
+    new MetadataRequest(
+        entryA, ['size', 'modificationTime', 'contentThumbnailUrl']),
+    new MetadataRequest(
+        entryB, ['size', 'modificationTime', 'contentThumbnailUrl'])
+  ]).then(function(results) {
+    assertEquals(2, results.length);
+    assertEquals(
+        new Date(2015, 0, 1).toString(),
+        results[0].modificationTime.toString());
+    assertEquals(1024, results[0].size);
+    assertEquals('THUMBNAIL_URL_A', results[0].contentThumbnailUrl);
+    assertEquals(
+        new Date(2015, 1, 2).toString(),
+        results[1].modificationTime.toString());
+    assertEquals(2048, results[1].size);
+    assertEquals('THUMBNAIL_URL_B', results[1].contentThumbnailUrl);
+  }), callback);
+}
+
+function testMultiMetadataProviderExternalAndContentProperty(callback) {
+  var model = new MultiMetadataProvider(
+      // Mocking FileSystemMetadataProvider.
+      {
+        get: function(requests) {
+          assertEquals(0, requests.length);
+          return Promise.resolve([]);
+        }
+      },
+      // Mocking ExternalMetadataProvider.
+      {
+        get: function(requests) {
+          assertEquals(2, requests.length);
+          assertEquals('filesystem://B', requests[0].entry.toURL());
+          assertEquals('filesystem://C', requests[1].entry.toURL());
+          assertArrayEquals(['imageWidth', 'dirty'], requests[0].names);
+          assertArrayEquals(['imageWidth', 'dirty'], requests[1].names);
+          return Promise.resolve([
+            {dirty: false, imageWidth: 200},
+            {dirty: true, imageWidth: 400}
+          ]);
+        }
+      },
+      // Mocking ContentMetadataProvider.
+      {
+        get: function(requests) {
+          assertEquals(1, requests.length);
+          assertTrue(requests[0].entry.toURL() in this.results_);
+          return Promise.resolve([
+            this.results_[requests[0].entry.toURL()]
+          ]);
+        },
+        results_: {
+          'filesystem://A': {imageWidth: 100},
+          'filesystem://C': {imageWidth: 300}
+        }
+      },
+      // Mocking VolumeManagerWrapper.
+      volumeManager);
+  reportPromise(model.get([
+    new MetadataRequest(entryA, ['imageWidth']),
+    new MetadataRequest(entryB, ['imageWidth']),
+    new MetadataRequest(entryC, ['imageWidth'])
+  ]).then(function(results) {
+    assertEquals(3, results.length);
+    assertEquals(100, results[0].imageWidth);
+    assertEquals(200, results[1].imageWidth);
+    assertEquals(300, results[2].imageWidth);
+  }), callback);
+}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
index fc088271..282bbbf 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider.js
@@ -4,18 +4,11 @@
 
 /**
  * TODO(hirono): Remove 'New' from the name after removing old MetadataProvider.
- * @param {!MetadataProviderCache} cache
  * @param {!Array<string>} validPropertyNames
  * @constructor
  * @struct
  */
-function NewMetadataProvider(cache, validPropertyNames) {
-  /**
-   * @private {!MetadataProviderCache}
-   * @const
-   */
-  this.cache_ = cache;
-
+function NewMetadataProvider(validPropertyNames) {
   /**
    * Set of valid property names. Key is the name of property and value is
    * always true.
@@ -26,14 +19,15 @@
   for (var i = 0; i < validPropertyNames.length; i++) {
     this.validPropertyNames_[validPropertyNames[i]] = true;
   }
-
-  /**
-   * @private {!Array<!MetadataProviderCallbackRequest<T>>}
-   * @const
-   */
-  this.callbackRequests_ = [];
 }
 
+NewMetadataProvider.prototype.checkPropertyNames = function(names) {
+  // Check if the property name is correct or not.
+  for (var i = 0; i < names.length; i++) {
+    assert(this.validPropertyNames_[names[i]]);
+  }
+};
+
 /**
  * Obtains the metadata for the request.
  * @param {!Array<!MetadataRequest>} requests
@@ -41,162 +35,5 @@
  *     should not return rejected promise. Instead it should return undefined
  *     property for property error, and should return empty MetadataItem for
  *     entry error.
- * @protected
  */
-NewMetadataProvider.prototype.getImpl;
-
-/**
- * Obtains metadata for entries.
- * @param {!Array<!Entry>} entries Entries.
- * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Promise<!Array<!MetadataItem>>}
- */
-NewMetadataProvider.prototype.get = function(entries, names) {
-  // Check if the property name is correct or not.
-  for (var i = 0; i < names.length; i++) {
-    assert(this.validPropertyNames_[names[i]]);
-  }
-
-  // Check if the results are cached or not.
-  if (this.cache_.hasFreshCache(entries, names))
-    return Promise.resolve(this.getCache(entries, names));
-
-  // The LRU cache may be cached out when the callback is completed.
-  // To hold cached values, create snapshot of the cache for entries.
-  var requestId = this.cache_.generateRequestId();
-  var snapshot = this.cache_.createSnapshot(entries);
-  var requests = snapshot.createRequests(entries, names);
-  snapshot.startRequests(requestId, requests);
-  this.cache_.startRequests(requestId, requests);
-
-  // Register callback.
-  var promise = new Promise(function(fulfill) {
-    this.callbackRequests_.push(new MetadataProviderCallbackRequest(
-        entries, names, snapshot, fulfill));
-  }.bind(this));
-
-  // If the requests are not empty, call the requests.
-  if (requests.length) {
-    this.getImpl(requests).then(function(list) {
-      // Obtain requested entries and ensure all the requested properties are
-      // contained in the result.
-      var requestedEntries = [];
-      for (var i = 0; i < requests.length; i++) {
-        requestedEntries.push(requests[i].entry);
-        for (var j = 0; j < requests[i].names.length; j++) {
-          var name = requests[i].names[j];
-          if (!(name in list[i]))
-            list[i][name] = undefined;
-        }
-      }
-
-      // Store cache.
-      this.cache_.storeProperties(requestId, requestedEntries, list);
-
-      // Invoke callbacks.
-      var i = 0;
-      while (i < this.callbackRequests_.length) {
-        if (this.callbackRequests_[i].storeProperties(
-            requestId, requestedEntries, list)) {
-          // Callback was called.
-          this.callbackRequests_.splice(i, 1);
-        } else {
-          i++;
-        }
-      }
-    }.bind(this));
-  }
-
-  return promise;
-};
-
-/**
- * Obtains metadata cache for entries.
- * @param {!Array<!Entry>} entries Entries.
- * @param {!Array<string>} names Metadata property names to be obtained.
- * @return {!Array<!MetadataItem>}
- */
-NewMetadataProvider.prototype.getCache = function(entries, names) {
-  // Check if the property name is correct or not.
-  for (var i = 0; i < names.length; i++) {
-    assert(this.validPropertyNames_[names[i]]);
-  }
-  return this.cache_.get(entries, names);
-};
-
-/**
- * @param {!Array<!Entry>} entries
- * @param {!Array<string>} names
- * @param {!MetadataCacheSet} cache
- * @param {function(!MetadataItem):undefined} fulfill
- * @constructor
- * @struct
- */
-function MetadataProviderCallbackRequest(entries, names, cache, fulfill) {
-  /**
-   * @private {!Array<!Entry>}
-   * @const
-   */
-  this.entries_ = entries;
-
-  /**
-   * @private {!Array<string>}
-   * @const
-   */
-  this.names_ = names;
-
-  /**
-   * @private {!MetadataCacheSet}
-   * @const
-   */
-  this.cache_ = cache;
-
-  /**
-   * @private {function(!MetadataItem):undefined}
-   * @const
-   */
-  this.fulfill_ = fulfill;
-}
-
-/**
- * Stores properties to snapshot cache of the callback request.
- * If all the requested property are served, it invokes the callback.
- * @param {number} requestId
- * @param {!Array<!Entry>} entries
- * @param {!Array<!MetadataItem>} objects
- * @return {boolean} Whether the callback is invoked or not.
- */
-MetadataProviderCallbackRequest.prototype.storeProperties = function(
-    requestId, entries, objects) {
-  this.cache_.storeProperties(requestId, entries, objects);
-  if (this.cache_.hasFreshCache(this.entries_, this.names_)) {
-    this.fulfill_(this.cache_.get(this.entries_, this.names_));
-    return true;
-  }
-  return false;
-};
-
-/**
- * Helper wrapper for LRUCache.
- * @constructor
- * @extends {MetadataCacheSet}
- * @struct
- */
-function MetadataProviderCache() {
-  MetadataCacheSet.call(this, new MetadataCacheSetStorageForObject({}));
-
-  /**
-   * @private {number}
-   */
-  this.requestIdCounter_ = 0;
-}
-
-MetadataProviderCache.prototype.__proto__ = MetadataCacheSet.prototype;
-
-/**
- * Generates a unique request ID every time when it is called.
- * @return {number}
- */
-MetadataProviderCache.prototype.generateRequestId = function() {
-  return this.requestIdCounter_++;
-};
+NewMetadataProvider.prototype.get;
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js b/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js
deleted file mode 100644
index 54cda9f8..0000000
--- a/ui/file_manager/file_manager/foreground/js/metadata/new_metadata_provider_unittest.js
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-function TestMetadataProvider(cache) {
-  NewMetadataProvider.call(this, cache, ['property', 'propertyA', 'propertyB']);
-  this.requestCount = 0;
-}
-
-TestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
-
-TestMetadataProvider.prototype.getImpl = function(requests) {
-  this.requestCount++;
-  return Promise.resolve(requests.map(function(request) {
-    var entry = request.entry;
-    var names = request.names;
-    var result = {};
-    for (var i = 0; i < names.length; i++) {
-      result[names[i]] = entry.toURL() + ':' + names[i];
-    }
-    return result;
-  }));
-};
-
-function TestEmptyMetadataProvider(cache) {
-  NewMetadataProvider.call(this, cache, ['property']);
-}
-
-TestEmptyMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
-
-TestEmptyMetadataProvider.prototype.getImpl = function(requests) {
-  return Promise.resolve(requests.map(function() {
-    return {};
-  }));
-};
-
-function ManualTestMetadataProvider(cache) {
-  NewMetadataProvider.call(
-      this, cache, ['propertyA', 'propertyB', 'propertyC']);
-  this.callback = [];
-}
-
-ManualTestMetadataProvider.prototype.__proto__ = NewMetadataProvider.prototype;
-
-ManualTestMetadataProvider.prototype.getImpl = function(requests) {
-  return new Promise(function(fulfill) {
-    this.callback.push(fulfill);
-  }.bind(this));
-};
-
-var entryA = {
-  toURL: function() { return "filesystem://A"; }
-};
-
-var entryB = {
-  toURL: function() { return "filesystem://B"; }
-};
-
-function testNewMetadataProviderBasic(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  reportPromise(provider.get([entryA, entryB], ['property']).then(
-      function(results) {
-        assertEquals(1, provider.requestCount);
-        assertEquals('filesystem://A:property', results[0].property);
-        assertEquals('filesystem://B:property', results[1].property);
-      }), callback);
-}
-
-function testNewMetadataProviderRequestForCachedProperty(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  reportPromise(provider.get([entryA, entryB], ['property']).then(
-      function() {
-        // All the result should be cached here.
-        return provider.get([entryA, entryB], ['property']);
-      }).then(function(results) {
-        assertEquals(1, provider.requestCount);
-        assertEquals('filesystem://A:property', results[0].property);
-        assertEquals('filesystem://B:property', results[1].property);
-      }), callback);
-}
-
-function testNewMetadataProviderRequestForCachedAndNonCachedProperty(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  reportPromise(provider.get([entryA, entryB], ['propertyA']).then(
-      function() {
-        assertEquals(1, provider.requestCount);
-        // propertyB has not been cached here.
-        return provider.get([entryA, entryB], ['propertyA', 'propertyB']);
-      }).then(function(results) {
-        assertEquals(2, provider.requestCount);
-        assertEquals('filesystem://A:propertyA', results[0].propertyA);
-        assertEquals('filesystem://A:propertyB', results[0].propertyB);
-        assertEquals('filesystem://B:propertyA', results[1].propertyA);
-        assertEquals('filesystem://B:propertyB', results[1].propertyB);
-      }), callback);
-}
-
-function testNewMetadataProviderRequestForCachedAndNonCachedEntry(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  reportPromise(provider.get([entryA], ['property']).then(
-      function() {
-        assertEquals(1, provider.requestCount);
-        // entryB has not been cached here.
-        return provider.get([entryA, entryB], ['property']);
-      }).then(function(results) {
-        assertEquals(2, provider.requestCount);
-        assertEquals('filesystem://A:property', results[0].property);
-        assertEquals('filesystem://B:property', results[1].property);
-      }), callback);
-}
-
-function testNewMetadataProviderRequestBeforeCompletingPreviousRequest(
-    callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  provider.get([entryA], ['property']);
-  assertEquals(1, provider.requestCount);
-  // The result of first call has not been fetched yet.
-  reportPromise(provider.get([entryA], ['property']).then(
-      function(results) {
-        assertEquals(1, provider.requestCount);
-        assertEquals('filesystem://A:property', results[0].property);
-      }), callback);
-}
-
-function testNewMetadataProviderNotUpdateCachedResultAfterRequest(
-    callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new ManualTestMetadataProvider(cache);
-  var promise = provider.get([entryA], ['propertyA']);
-  provider.callback[0]([{propertyA: 'valueA1'}]);
-  reportPromise(promise.then(function() {
-    // 'propertyA' is cached here.
-    var promise1 = provider.get([entryA], ['propertyA', 'propertyB']);
-    var promise2 = provider.get([entryA], ['propertyC']);
-    // Returns propertyC.
-    provider.callback[2]([{propertyA: 'valueA2', propertyC: 'valueC'}]);
-    provider.callback[1]([{propertyB: 'valueB'}]);
-    return Promise.all([promise1, promise2]);
-  }).then(function(results) {
-    // The result should be cached value at the time when get was called.
-    assertEquals('valueA1', results[0][0].propertyA);
-    assertEquals('valueB', results[0][0].propertyB);
-    assertEquals('valueC', results[1][0].propertyC);
-  }), callback);
-}
-
-function testNewMetadataProviderGetCache(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  var promise = provider.get([entryA], ['property']);
-  var cache = provider.getCache([entryA], ['property']);
-  assertEquals(null, cache[0].property);
-  reportPromise(promise.then(function() {
-    var cache = provider.getCache([entryA], ['property']);
-    assertEquals(1, provider.requestCount);
-    assertEquals('filesystem://A:property', cache[0].property);
-  }), callback);
-}
-
-function testNewMetadataProviderUnknownProperty() {
-  var cache = new MetadataProviderCache();
-  var provider = new TestMetadataProvider(cache);
-  assertThrows(function() {
-    provider.get([entryA], ['unknown']);
-  });
-}
-
-function testNewMetadataProviderEmptyResult(callback) {
-  var cache = new MetadataProviderCache();
-  var provider = new TestEmptyMetadataProvider(cache);
-  // getImpl returns empty result.
-  reportPromise(provider.get([entryA], ['property']).then(function(results) {
-    assertEquals(undefined, results[0].property);
-  }), callback);
-}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
index 16f4a5f..e5b690e 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/thumbnail_model.js
@@ -3,16 +3,16 @@
 // found in the LICENSE file.
 
 /**
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @struct
  * @constructor
  */
-function ThumbnailModel(fileSystemMetadata) {
+function ThumbnailModel(metadataModel) {
   /**
-   * @private {!FileSystemMetadata}
+   * @private {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 }
 
 /**
@@ -21,7 +21,7 @@
  */
 ThumbnailModel.prototype.get = function(entries) {
   var results = {};
-  return this.fileSystemMetadata_.get(
+  return this.metadataModel_.get(
       entries,
       [
         'modificationTime',
@@ -53,7 +53,7 @@
             contentRequestEntries.push(entries[i]);
         }
         if (contentRequestEntries.length) {
-          return this.fileSystemMetadata_.get(
+          return this.metadataModel_.get(
               contentRequestEntries,
               [
                 'contentThumbnailUrl',
diff --git a/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js b/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js
index 67a32e2f..08b3465 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata_update_controller.js
@@ -6,15 +6,13 @@
  * Controller for list contents update.
  * @param {!ListContainer} listContainer
  * @param {!DirectoryModel} directoryModel
- * @param {!MetadataProviderCache} metadataProviderCache
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @constructor
  * @struct
  */
 function MetadataUpdateController(listContainer,
                                   directoryModel,
-                                  metadataProviderCache,
-                                  fileSystemMetadata) {
+                                  metadataModel) {
   /**
    * @private {!DirectoryModel}
    * @const
@@ -22,10 +20,10 @@
   this.directoryModel_ = directoryModel;
 
   /**
-   * @private {!FileSystemMetadata}
+   * @private {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   /**
    * @private {!ListContainer}
@@ -36,7 +34,7 @@
   chrome.fileManagerPrivate.onPreferencesChanged.addListener(
       this.onPreferencesChanged_.bind(this));
   this.onPreferencesChanged_();
-  metadataProviderCache.addEventListener(
+  metadataModel.addEventListener(
       'update', this.onCachedMetadataUpdate_.bind(this));
 
   // Update metadata to change 'Today' and 'Yesterday' dates.
@@ -70,11 +68,11 @@
   // changed.
   var isFakeEntry = util.isFakeEntry(directoryEntry);
   var changedEntries = (isFakeEntry ? [] : [directoryEntry]).concat(entries);
-  this.fileSystemMetadata_.notifyEntriesChanged(changedEntries);
+  this.metadataModel_.notifyEntriesChanged(changedEntries);
 
   // We don't pass callback here. When new metadata arrives, we have an
   // observer registered to update the UI.
-  this.fileSystemMetadata_.get(
+  this.metadataModel_.get(
       changedEntries, this.directoryModel_.getPrefetchPropertyNames());
 };
 
@@ -97,7 +95,7 @@
 MetadataUpdateController.prototype.dailyUpdateModificationTime_ = function() {
   var entries = /** @type {!Array<!Entry>} */(
       this.directoryModel_.getFileList().slice());
-  this.fileSystemMetadata_.get(entries, ['modificationTime']).then(function() {
+  this.metadataModel_.get(entries, ['modificationTime']).then(function() {
     this.listContainer_.currentView.updateListItemsMetadata(
         'filesystem', entries);
   }.bind(this));
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller.js b/ui/file_manager/file_manager/foreground/js/task_controller.js
index 90da38012..4cb37d1 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller.js
@@ -5,7 +5,7 @@
 /**
  * @param {DialogType} dialogType
  * @param {!FileManagerUI} ui
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @param {!FileSelectionHandler} selectionHandler
  * @param {!MetadataUpdateController} metadataUpdateController
  * @param {function():!FileTasks} createTask
@@ -13,7 +13,7 @@
  * @struct
  */
 function TaskController(
-    dialogType, ui, fileSystemMetadata, selectionHandler,
+    dialogType, ui, metadataModel, selectionHandler,
     metadataUpdateController, createTask) {
   /**
    * @type {DialogType}
@@ -30,11 +30,11 @@
   this.ui_ = ui;
 
   /**
-   * @type {!FileSystemMetadata}
+   * @type {!MetadataModel}
    * @const
    * @private
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   /**
    * @type {!FileSelectionHandler}
@@ -263,7 +263,7 @@
  * @private
  */
 TaskController.prototype.getMimeType_ = function(entry) {
-  return this.fileSystemMetadata_.get([entry], ['contentMimeType']).then(
+  return this.metadataModel_.get([entry], ['contentMimeType']).then(
       function(properties) {
         if (properties[0].contentMimeType)
           return properties[0].contentMimeType;
@@ -367,7 +367,7 @@
  */
 TaskController.prototype.doEntryAction = function(entry) {
   if (this.dialogType_ == DialogType.FULL_PAGE) {
-    this.fileSystemMetadata_.get([entry], ['contentMimeType']).then(
+    this.metadataModel_.get([entry], ['contentMimeType']).then(
         function(props) {
           var tasks = this.createTask_();
           tasks.init([entry], [props[0].contentMimeType || '']);
diff --git a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
index 15f3325..62e66f7 100644
--- a/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/task_controller_unittest.js
@@ -6,11 +6,11 @@
   recordEnum: function() {}
 };
 
-function MockFileSystemMetadata(properties) {
+function MockMetadataModel(properties) {
   this.properties_ = properties;
 }
 
-MockFileSystemMetadata.prototype.get = function() {
+MockMetadataModel.prototype.get = function() {
   return Promise.resolve([this.properties_]);
 };
 
@@ -48,7 +48,7 @@
           defaultActionMenuItem: document.createElement('div')
         }
       },
-      new MockFileSystemMetadata({}),
+      new MockMetadataModel({}),
       new cr.EventTarget(),
       null,
       function() {
@@ -61,7 +61,7 @@
           isOnDrive: function() {
             return true;
           },
-          getFileSystemMetadata: function() {}
+          getMetadataModel: function() {}
         });
       });
 
@@ -98,7 +98,7 @@
             }
           }
         },
-        new MockFileSystemMetadata({contentMimeType: 'application/rtf'}),
+        new MockMetadataModel({contentMimeType: 'application/rtf'}),
         new cr.EventTarget(),
         null,
         null);
@@ -141,7 +141,7 @@
             }
           }
         },
-        new MockFileSystemMetadata({}),
+        new MockMetadataModel({}),
         new cr.EventTarget(),
         null,
         null);
@@ -171,7 +171,7 @@
             defaultActionMenuItem: document.createElement('div')
           }
         },
-        new MockFileSystemMetadata({contentMimeType: 'image/png'}),
+        new MockMetadataModel({contentMimeType: 'image/png'}),
         new cr.EventTarget(),
         null,
         null);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index d254c49..8e6e1dea 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -396,8 +396,8 @@
  */
 SubDirectoryItem.prototype.updateSharedStatusIcon = function() {
   var icon = this.querySelector('.icon');
-  this.parentTree_.fileSystemMetadata.notifyEntriesChanged([this.dirEntry_]);
-  this.parentTree_.fileSystemMetadata.get([this.dirEntry_], ['shared']).then(
+  this.parentTree_.metadataModel.notifyEntriesChanged([this.dirEntry_]);
+  this.parentTree_.metadataModel.get([this.dirEntry_], ['shared']).then(
       function(metadata) {
         icon.classList.toggle('shared', metadata[0] && metadata[0].shared);
       });
@@ -792,15 +792,14 @@
  * @param {HTMLElement} el Element to be DirectoryTree.
  * @param {!DirectoryModel} directoryModel Current DirectoryModel.
  * @param {!VolumeManagerWrapper} volumeManager VolumeManager of the system.
- * @param {!FileSystemMetadata} fileSystemMetadata Shared MetadataCache
- *     instance.
+ * @param {!MetadataModel} metadataModel Shared MetadataModel instance.
  * @param {boolean} fakeEntriesVisible True if it should show the fakeEntries.
  */
 DirectoryTree.decorate = function(
-    el, directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible) {
+    el, directoryModel, volumeManager, metadataModel, fakeEntriesVisible) {
   el.__proto__ = DirectoryTree.prototype;
   /** @type {DirectoryTree} */ (el).decorateDirectoryTree(
-      directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible);
+      directoryModel, volumeManager, metadataModel, fakeEntriesVisible);
 };
 
 DirectoryTree.prototype = {
@@ -839,11 +838,11 @@
   },
 
   /**
-   * The reference to shared FileSystemMetadata instance.
-   * @type {!FileSystemMetadata}
+   * The reference to shared MetadataModel instance.
+   * @type {!MetadataModel}
    */
-  get fileSystemMetadata() {
-    return this.fileSystemMetadata_;
+  get metadataModel() {
+    return this.metadataModel_;
   },
 
   set dataModel(dataModel) {
@@ -959,18 +958,17 @@
  * Decorates an element.
  * @param {!DirectoryModel} directoryModel Current DirectoryModel.
  * @param {!VolumeManagerWrapper} volumeManager VolumeManager of the system.
- * @param {!FileSystemMetadata} fileSystemMetadata Shared MetadataCache
- *     instance.
+ * @param {!MetadataModel} metadataModel Shared MetadataModel instance.
  * @param {boolean} fakeEntriesVisible True if it should show the fakeEntries.
  */
 DirectoryTree.prototype.decorateDirectoryTree = function(
-    directoryModel, volumeManager, fileSystemMetadata, fakeEntriesVisible) {
+    directoryModel, volumeManager, metadataModel, fakeEntriesVisible) {
   cr.ui.Tree.prototype.decorate.call(this);
 
   this.sequence_ = 0;
   this.directoryModel_ = directoryModel;
   this.volumeManager_ = volumeManager;
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
   this.models_ = [];
 
   this.fileFilter_ = this.directoryModel_.getFileFilter();
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
index db001f07..728dc30 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_grid.js
@@ -22,15 +22,15 @@
 /**
  * Decorates an HTML element to be a FileGrid.
  * @param {!Element} self The grid to decorate.
- * @param {!FileSystemMetadata} fileSystemMetadata File system metadata.
+ * @param {!MetadataModel} metadataModel File system metadata.
  * @param {VolumeManagerWrapper} volumeManager Volume manager instance.
  * @param {!importer.HistoryLoader} historyLoader
  */
 FileGrid.decorate = function(
-    self, fileSystemMetadata, volumeManager, historyLoader) {
+    self, metadataModel, volumeManager, historyLoader) {
   cr.ui.Grid.decorate(self);
   self.__proto__ = FileGrid.prototype;
-  self.fileSystemMetadata_ = fileSystemMetadata;
+  self.metadataModel_ = metadataModel;
   self.volumeManager_ = volumeManager;
   self.historyLoader_ = historyLoader;
 
@@ -138,7 +138,7 @@
 
     FileGrid.decorateThumbnailBox_(assertInstanceof(box, HTMLDivElement),
                                    entry,
-                                   this.fileSystemMetadata_,
+                                   this.metadataModel_,
                                    this.volumeManager_,
                                    this.historyLoader_,
                                    this.listThumbnailLoader_);
@@ -168,7 +168,7 @@
  * Decorates thumbnail.
  * @param {cr.ui.ListItem} li List item.
  * @param {!Entry} entry Entry to render a thumbnail for.
- * @param {!FileSystemMetadata} fileSystemMetadata To retrieve metadata.
+ * @param {!MetadataModel} metadataModel To retrieve metadata.
  * @param {VolumeManagerWrapper} volumeManager Volume manager instance.
  * @param {!importer.HistoryLoader} historyLoader
  * @private
@@ -176,13 +176,13 @@
 FileGrid.decorateThumbnail_ = function(
     li,
     entry,
-    fileSystemMetadata,
+    metadataModel,
     volumeManager,
     historyLoader,
     listThumbnailLoader) {
   li.className = 'thumbnail-item';
   if (entry)
-    filelist.decorateListItem(li, entry, fileSystemMetadata);
+    filelist.decorateListItem(li, entry, metadataModel);
 
   var frame = li.ownerDocument.createElement('div');
   frame.className = 'thumbnail-frame';
@@ -193,7 +193,7 @@
     FileGrid.decorateThumbnailBox_(
         assertInstanceof(box, HTMLDivElement),
         entry,
-        fileSystemMetadata,
+        metadataModel,
         volumeManager,
         historyLoader,
         listThumbnailLoader);
@@ -219,7 +219,7 @@
  *
  * @param {!HTMLDivElement} box Box to decorate.
  * @param {Entry} entry Entry which thumbnail is generating for.
- * @param {!FileSystemMetadata} fileSystemMetadata To retrieve metadata.
+ * @param {!MetadataModel} metadataModel To retrieve metadata.
  * @param {VolumeManagerWrapper} volumeManager Volume manager instance.
  * @param {!importer.HistoryLoader} historyLoader
  * @param {function(HTMLImageElement)=} opt_imageLoadCallback Callback called
@@ -227,7 +227,7 @@
  * @private
  */
 FileGrid.decorateThumbnailBox_ = function(
-    box, entry, fileSystemMetadata, volumeManager, historyLoader,
+    box, entry, metadataModel, volumeManager, historyLoader,
     listThumbnailLoader, opt_imageLoadCallback) {
   box.className = 'img-container';
 
@@ -242,7 +242,7 @@
   if (entry.isDirectory) {
     box.setAttribute('generic-thumbnail', 'folder');
 
-    var shared = !!fileSystemMetadata.getCache([entry], ['shared'])[0].shared;
+    var shared = !!metadataModel.getCache([entry], ['shared'])[0].shared;
     box.classList.toggle('shared', shared);
 
     if (opt_imageLoadCallback)
@@ -279,7 +279,7 @@
   thumbnail.style.backgroundImage = 'url(' + dataUrl + ')';
   thumbnail.addEventListener('webkitAnimationEnd', function() {
     // Remove animation css once animation is completed in order not to animate
-    // agein when an item is attached to the dom again.
+    // again when an item is attached to the dom again.
     thumbnail.classList.remove('animate');
 
     for (var i = 0; i < oldThumbnails.length; i++) {
@@ -366,7 +366,7 @@
   FileGrid.decorateThumbnail_(
       li,
       entry,
-      grid.fileSystemMetadata_,
+      grid.metadataModel_,
       grid.volumeManager_,
       grid.historyLoader_,
       grid.listThumbnailLoader_);
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_table.js b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
index 7d62b53..860da24e 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_table.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_table.js
@@ -224,7 +224,7 @@
 /**
  * Decorates the element.
  * @param {!Element} self Table to decorate.
- * @param {!FileSystemMetadata} fileSystemMetadata To retrieve
+ * @param {!MetadataModel} metadataModel To retrieve
  *     metadata.
  * @param {VolumeManagerWrapper} volumeManager To retrieve volume info.
  * @param {!importer.HistoryLoader} historyLoader
@@ -232,11 +232,11 @@
  *                           False if a file open/save dialog.
  */
 FileTable.decorate = function(
-    self, fileSystemMetadata, volumeManager, historyLoader, fullPage) {
+    self, metadataModel, volumeManager, historyLoader, fullPage) {
   cr.ui.Table.decorate(self);
   FileTableList.decorate(self.list);
   self.__proto__ = FileTable.prototype;
-  self.fileSystemMetadata_ = fileSystemMetadata;
+  self.metadataModel_ = metadataModel;
   self.volumeManager_ = volumeManager;
   self.historyLoader_ = historyLoader;
 
@@ -394,7 +394,8 @@
     var box = listItem.querySelector('.detail-thumbnail');
     if (box) {
       this.setThumbnailImage_(
-          assertInstanceof(box, HTMLDivElement), event.dataUrl);
+          assertInstanceof(box, HTMLDivElement), event.dataUrl,
+          true /* with animation */);
     }
   }
 };
@@ -494,9 +495,12 @@
     return true;
 
   // Check if the point is on the column contents or not.
-  var item = this.list.getListItemByIndex(itemIndex);
   switch (this.columnModel.columns_[hitColumn.index].id) {
     case 'name':
+      var item = this.list.getListItemByIndex(itemIndex);
+      if (!item)
+        return false;
+
       var spanElement = item.querySelector('.filename-label span');
       var spanRect = spanElement.getBoundingClientRect();
       // The this.list.cachedBounds_ object is set by
@@ -564,7 +568,7 @@
  * @private
  */
 FileTable.prototype.updateSize_ = function(div, entry) {
-  var metadata = this.fileSystemMetadata_.getCache(
+  var metadata = this.metadataModel_.getCache(
       [entry], ['size', 'hosted'])[0];
   var size = metadata.size;
   if (size === null || size === undefined) {
@@ -694,7 +698,7 @@
  * @private
  */
 FileTable.prototype.updateDate_ = function(div, entry) {
-  var modTime = this.fileSystemMetadata_.getCache(
+  var modTime = this.metadataModel_.getCache(
       [entry], ['modificationTime'])[0].modificationTime;
 
   if (!modTime) {
@@ -776,7 +780,7 @@
     forEachCell('.table-row-cell > .date', function(item, entry, listItem) {
       filelist.updateListItemExternalProps(
           listItem,
-          this.fileSystemMetadata_.getCache(
+          this.metadataModel_.getCache(
               [entry], ['availableOffline', 'customIconUrl', 'shared'])[0]);
     });
   } else if (type === 'import-history') {
@@ -795,7 +799,7 @@
  */
 FileTable.prototype.renderTableRow_ = function(baseRenderFunction, entry) {
   var item = baseRenderFunction(entry, this);
-  filelist.decorateListItem(item, entry, this.fileSystemMetadata_);
+  filelist.decorateListItem(item, entry, this.metadataModel_);
   return item;
 };
 
@@ -814,7 +818,8 @@
   if (this.listThumbnailLoader_ &&
       this.listThumbnailLoader_.getThumbnailFromCache(entry)) {
     this.setThumbnailImage_(
-        box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl);
+        box, this.listThumbnailLoader_.getThumbnailFromCache(entry).dataUrl,
+        false /* without animation */);
   }
 
   return box;
@@ -824,12 +829,31 @@
  * Sets thumbnail image to the box.
  * @param {!HTMLDivElement} box Detail thumbnail div element.
  * @param {string} dataUrl Data url of thumbnail.
+ * @param {boolean} shouldAnimate Whether the thumbnail is shown with animation
+ *     or not.
  * @private
  */
-FileTable.prototype.setThumbnailImage_ = function(box, dataUrl) {
-  // TODO(yawano): Add transition animation for thumbnail update.
-  box.style.backgroundImage = 'url(' + dataUrl + ')';
-  box.classList.add('loaded');
+FileTable.prototype.setThumbnailImage_ = function(box, dataUrl, shouldAnimate) {
+  var oldThumbnails = box.querySelectorAll('.thumbnail');
+
+  var thumbnail = box.ownerDocument.createElement('div');
+  thumbnail.classList.add('thumbnail');
+  thumbnail.style.backgroundImage = 'url(' + dataUrl + ')';
+  thumbnail.addEventListener('webkitAnimationEnd', function() {
+    // Remove animation css once animation is completed in order not to animate
+    // again when an item is attached to the dom again.
+    thumbnail.classList.remove('animate');
+
+    for (var i = 0; i < oldThumbnails.length; i++) {
+      if (box.contains(oldThumbnails[i]))
+        box.removeChild(oldThumbnails[i]);
+    }
+  });
+
+  if (shouldAnimate)
+    thumbnail.classList.add('animate');
+
+  box.appendChild(thumbnail);
 };
 
 /**
@@ -866,15 +890,15 @@
  * Common item decoration for table's and grid's items.
  * @param {cr.ui.ListItem} li List item.
  * @param {Entry} entry The entry.
- * @param {!FileSystemMetadata} fileSystemMetadata Cache to
+ * @param {!MetadataModel} metadataModel Cache to
  *     retrieve metadada.
  */
-filelist.decorateListItem = function(li, entry, fileSystemMetadata) {
+filelist.decorateListItem = function(li, entry, metadataModel) {
   li.classList.add(entry.isDirectory ? 'directory' : 'file');
   // The metadata may not yet be ready. In that case, the list item will be
   // updated when the metadata is ready via updateListItemsMetadata. For files
   // not on an external backend, externalProps is not available.
-  var externalProps = fileSystemMetadata.getCache(
+  var externalProps = metadataModel.getCache(
       [entry], ['hosted', 'availableOffline', 'customIconUrl', 'shared'])[0];
   filelist.updateListItemExternalProps(li, externalProps);
 
diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html
index 5600fccc92..f3572ef 100644
--- a/ui/file_manager/file_manager/main.html
+++ b/ui/file_manager/file_manager/main.html
@@ -131,11 +131,12 @@
       <script src="foreground/js/launch_param.js"></script>
       <script src="foreground/js/metadata/content_metadata_provider.js"></script>
       <script src="foreground/js/metadata/external_metadata_provider.js"></script>
-      <script src="foreground/js/metadata/file_system_metadata.js"></script>
       <script src="foreground/js/metadata/file_system_metadata_provider.js"></script>
       <script src="foreground/js/metadata/metadata_cache.js"></script>
       <script src="foreground/js/metadata/metadata_cache_item.js"></script>
       <script src="foreground/js/metadata/metadata_item.js"></script>
+      <script src="foreground/js/metadata/metadata_model.js"></script>
+      <script src="foreground/js/metadata/multi_metadata_provider.js"></script>
       <script src="foreground/js/metadata_update_controller.js"></script>
       <script src="foreground/js/naming_controller.js"></script>
       <script src="foreground/js/navigation_list_model.js"></script>
diff --git a/ui/file_manager/gallery/gallery.html b/ui/file_manager/gallery/gallery.html
index 00f049b..b012927 100644
--- a/ui/file_manager/gallery/gallery.html
+++ b/ui/file_manager/gallery/gallery.html
@@ -54,14 +54,15 @@
     <script src="../file_manager/common/js/volume_manager_common.js"></script>
 
     <script src="../file_manager/foreground/js/metadata/content_metadata_provider.js"></script>
+    <script src="../file_manager/foreground/js/metadata/exif_constants.js"></script>
     <script src="../file_manager/foreground/js/metadata/external_metadata_provider.js"></script>
-    <script src="../file_manager/foreground/js/metadata/file_system_metadata.js"></script>
     <script src="../file_manager/foreground/js/metadata/file_system_metadata_provider.js"></script>
     <script src="../file_manager/foreground/js/metadata/metadata_cache.js"></script>
     <script src="../file_manager/foreground/js/metadata/metadata_cache_item.js"></script>
     <script src="../file_manager/foreground/js/metadata/metadata_item.js"></script>
+    <script src="../file_manager/foreground/js/metadata/metadata_model.js"></script>
+    <script src="../file_manager/foreground/js/metadata/multi_metadata_provider.js"></script>
     <script src="../file_manager/foreground/js/metadata/thumbnail_model.js"></script>
-    <script src="../file_manager/foreground/js/metadata/exif_constants.js"></script>
     <script src="../file_manager/foreground/js/mouse_inactivity_watcher.js"></script>
     <script src="../file_manager/foreground/js/share_client.js"></script>
     <script src="../file_manager/foreground/js/thumbnail_loader.js"></script>
diff --git a/ui/file_manager/gallery/js/compiled_resources.gyp b/ui/file_manager/gallery/js/compiled_resources.gyp
index ad5166f4..f4a7be9 100644
--- a/ui/file_manager/gallery/js/compiled_resources.gyp
+++ b/ui/file_manager/gallery/js/compiled_resources.gyp
@@ -69,12 +69,13 @@
           '../../file_manager/foreground/js/metadata/content_metadata_provider.js',
           '../../file_manager/foreground/js/metadata/exif_constants.js',
           '../../file_manager/foreground/js/metadata/external_metadata_provider.js',
-          '../../file_manager/foreground/js/metadata/file_system_metadata.js',
           '../../file_manager/foreground/js/metadata/file_system_metadata_provider.js',
           '../../file_manager/foreground/js/metadata/metadata_cache.js',
           '../../file_manager/foreground/js/metadata/metadata_cache_item.js',
           '../../file_manager/foreground/js/metadata/metadata_cache_set.js',
           '../../file_manager/foreground/js/metadata/metadata_item.js',
+          '../../file_manager/foreground/js/metadata/metadata_model.js',
+          '../../file_manager/foreground/js/metadata/multi_metadata_provider.js',
           '../../file_manager/foreground/js/metadata/new_metadata_provider.js',
           '../../file_manager/foreground/js/mouse_inactivity_watcher.js',
           '../../file_manager/foreground/js/share_client.js',
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js
index a835bfa3..3ed7817 100644
--- a/ui/file_manager/gallery/js/gallery.js
+++ b/ui/file_manager/gallery/js/gallery.js
@@ -53,11 +53,10 @@
   this.metadataCache_ = this.context_.metadataCache;
   this.volumeManager_ = volumeManager;
   /**
-   * @private {!FileSystemMetadata}
+   * @private {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata_ = FileSystemMetadata.create(
-      new MetadataProviderCache(), volumeManager);
+  this.metadataModel_ = MetadataModel.create(volumeManager);
   this.selectedEntry_ = null;
   this.metadataCacheObserverId_ = null;
   this.onExternallyUnmountedBound_ = this.onExternallyUnmounted_.bind(this);
@@ -65,7 +64,7 @@
 
   this.dataModel_ = new GalleryDataModel(
       this.context_.metadataCache,
-      this.fileSystemMetadata_);
+      this.metadataModel_);
   var downloadVolumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo(
       VolumeManagerCommon.VolumeType.DOWNLOADS);
   downloadVolumeInfo.resolveDisplayRoot().then(function(entry) {
@@ -393,7 +392,7 @@
             locationInfo,
             clonedMetadata,
             self.metadataCache_,
-            self.fileSystemMetadata_,
+            self.metadataModel_,
             /* original */ true));
       });
       self.dataModel_.push.apply(self.dataModel_, items);
diff --git a/ui/file_manager/gallery/js/gallery_data_model.js b/ui/file_manager/gallery/js/gallery_data_model.js
index 5b80f77..f9f3287c 100644
--- a/ui/file_manager/gallery/js/gallery_data_model.js
+++ b/ui/file_manager/gallery/js/gallery_data_model.js
@@ -6,12 +6,12 @@
  * Data model for gallery.
  *
  * @param {!MetadataCache} metadataCache Metadata cache.
- * @param {!FileSystemMetadata} fileSystemMetadata
+ * @param {!MetadataModel} metadataModel
  * @param {!EntryListWatcher=} opt_watcher Entry list watcher.
  * @constructor
  * @extends {cr.ui.ArrayDataModel}
  */
-function GalleryDataModel(metadataCache, fileSystemMetadata, opt_watcher) {
+function GalleryDataModel(metadataCache, metadataModel, opt_watcher) {
   cr.ui.ArrayDataModel.call(this, []);
 
   /**
@@ -23,10 +23,10 @@
 
   /**
    * File system metadata.
-   * @private {!FileSystemMetadata}
+   * @private {!MetadataModel}
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   /**
    * Directory where the image is saved if the image is located in a read-only
@@ -102,7 +102,7 @@
                 oldLocationInfo,
                 oldMetadata,
                 this.metadataCache_,
-                this.fileSystemMetadata_,
+                this.metadataModel_,
                 item.isOriginal());
             // The item must be added behind the existing item so that it does
             // not change the index of the existing item.
diff --git a/ui/file_manager/gallery/js/gallery_data_model_unittest.js b/ui/file_manager/gallery/js/gallery_data_model_unittest.js
index bad20791..f2b7a3ab 100644
--- a/ui/file_manager/gallery/js/gallery_data_model_unittest.js
+++ b/ui/file_manager/gallery/js/gallery_data_model_unittest.js
@@ -11,7 +11,7 @@
   var metadataCache = new MockMetadataCache();
   model = new GalleryDataModel(
       metadataCache,
-      /* Mock FileSystemMetadata */{},
+      /* Mock MetadataModel */{},
       /* Mock EntryListWatcher */{});
   fileSystem = new MockFileSystem('volumeId');
   item = new Gallery.Item(
diff --git a/ui/file_manager/gallery/js/gallery_item.js b/ui/file_manager/gallery/js/gallery_item.js
index 2db056dc..6d87f3e 100644
--- a/ui/file_manager/gallery/js/gallery_item.js
+++ b/ui/file_manager/gallery/js/gallery_item.js
@@ -9,13 +9,13 @@
  * @param {!EntryLocation} locationInfo Entry location information.
  * @param {!Object} metadata Metadata for the entry.
  * @param {!MetadataCache} metadataCache Metadata cache instance.
- * @param {!FileSystemMetadata} fileSystemMetadata File system metadata.
+ * @param {!MetadataModel} metadataModel File system metadata.
  * @param {boolean} original Whether the entry is original or edited.
  * @constructor
  * @struct
  */
 Gallery.Item = function(
-    entry, locationInfo, metadata, metadataCache, fileSystemMetadata,
+    entry, locationInfo, metadata, metadataCache, metadataModel,
     original) {
   /**
    * @type {!FileEntry}
@@ -43,11 +43,11 @@
   this.metadataCache_ = metadataCache;
 
   /**
-   * @type {!FileSystemMetadata}
+   * @type {!MetadataModel}
    * @private
    * @const
    */
-  this.fileSystemMetadata_ = fileSystemMetadata;
+  this.metadataModel_ = metadataModel;
 
   // TODO(yawano): Change this.contentImage and this.screenImage to private
   // fields and provide utility methods for them (e.g. revokeFullImageCache).
@@ -271,7 +271,7 @@
               opt_callback(false);
           }
         }.bind(this));
-    this.fileSystemMetadata_.notifyEntriesChanged([this.entry_]);
+    this.metadataModel_.notifyEntriesChanged([this.entry_]);
   }.bind(this);
 
   var onError = function(error) {
@@ -282,7 +282,7 @@
   };
 
   var doSave = function(newFile, fileEntry) {
-    var metadataPromise = this.fileSystemMetadata_.get(
+    var metadataPromise = this.metadataModel_.get(
         [fileEntry],
         ['mediaMimeType', 'contentMimeType', 'ifd', 'exifLittleEndian']);
     metadataPromise.then(function(metadataItems) {
diff --git a/ui/file_manager/gallery/js/gallery_item_unittest.js b/ui/file_manager/gallery/js/gallery_item_unittest.js
index 8a7b25df..ce10ef12 100644
--- a/ui/file_manager/gallery/js/gallery_item_unittest.js
+++ b/ui/file_manager/gallery/js/gallery_item_unittest.js
@@ -63,7 +63,7 @@
       {isReadOnly: false},
       {name: 'oldMetadata'},
       metadataCache,
-      // Mock of FileSystemMetadata.
+      // Mock of MetadataModel.
       {
         get: function() {
           return Promise.resolve([{}]);
diff --git a/ui/file_manager/gallery/js/gallery_scripts.js b/ui/file_manager/gallery/js/gallery_scripts.js
index df653f5..c288391 100644
--- a/ui/file_manager/gallery/js/gallery_scripts.js
+++ b/ui/file_manager/gallery/js/gallery_scripts.js
@@ -46,14 +46,15 @@
 //<include src="../../file_manager/common/js/util.js">
 //<include src="../../file_manager/common/js/volume_manager_common.js">
 //<include src="../../file_manager/foreground/js/metadata/content_metadata_provider.js">
+//<include src="../../file_manager/foreground/js/metadata/exif_constants.js">
 //<include src="../../file_manager/foreground/js/metadata/external_metadata_provider.js">
-//<include src="../../file_manager/foreground/js/metadata/file_system_metadata.js">
 //<include src="../../file_manager/foreground/js/metadata/file_system_metadata_provider.js">
 //<include src="../../file_manager/foreground/js/metadata/metadata_cache.js">
 //<include src="../../file_manager/foreground/js/metadata/metadata_cache_item.js">
 //<include src="../../file_manager/foreground/js/metadata/metadata_item.js">
+//<include src="../../file_manager/foreground/js/metadata/metadata_model.js">
+//<include src="../../file_manager/foreground/js/metadata/multi_metadata_provider.js">
 //<include src="../../file_manager/foreground/js/metadata/thumbnail_model.js">
-//<include src="../../file_manager/foreground/js/metadata/exif_constants.js">
 //<include src="../../file_manager/foreground/js/mouse_inactivity_watcher.js">
 //<include src="../../file_manager/foreground/js/share_client.js">
 //<include src="../../file_manager/foreground/js/thumbnail_loader.js">
diff --git a/ui/gfx/x/x11_error_tracker.cc b/ui/gfx/x/x11_error_tracker.cc
index 110f79c..859e718 100644
--- a/ui/gfx/x/x11_error_tracker.cc
+++ b/ui/gfx/x/x11_error_tracker.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/logging.h"
 #include "ui/gfx/x/x11_error_tracker.h"
 
+#include "base/logging.h"
 #include "ui/gfx/x/x11_types.h"
 
 namespace {
@@ -16,7 +16,8 @@
   g_x11_error_code = error->error_code;
   return 0;
 }
-}
+
+}  // namespace
 
 namespace gfx {
 
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index a6e6ff1d..b67ca69 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -156,6 +156,15 @@
   static scoped_refptr<GLSurface> CreateViewGLSurface(
       gfx::AcceleratedWidget window);
 
+#if defined(USE_OZONE)
+  // Create a GL surface that renders directly into a window with surfaceless
+  // semantics - there is no default framebuffer and the primary surface must
+  // be presented as an overlay. If surfaceless mode is not supported or
+  // enabled it will return a null pointer.
+  static scoped_refptr<GLSurface> CreateSurfacelessViewGLSurface(
+      gfx::AcceleratedWidget window);
+#endif  // defined(USE_OZONE)
+
   // Create a GL surface used for offscreen rendering.
   static scoped_refptr<GLSurface> CreateOffscreenGLSurface(
       const gfx::Size& size);
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index f79b6d0..47ea8d6 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -4,16 +4,20 @@
 
 #include "ui/gl/gl_surface.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_image.h"
+#include "ui/gl/gl_image_linux_dma_buffer.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/gl/gl_surface_osmesa.h"
 #include "ui/gl/gl_surface_stub.h"
+#include "ui/gl/scoped_binders.h"
 #include "ui/gl/scoped_make_current.h"
+#include "ui/ozone/public/native_pixmap.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 #include "ui/ozone/public/surface_ozone_egl.h"
 
@@ -157,7 +161,7 @@
     return SwapBuffersAsync(callback);
   }
 
- private:
+ protected:
   ~GLSurfaceOzoneSurfaceless() override {
     Destroy();  // EGL surface must be destroyed before SurfaceOzone
   }
@@ -196,6 +200,157 @@
   DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfaceless);
 };
 
+// This provides surface-like semantics implemented through surfaceless.
+// A framebuffer is bound automatically.
+class GL_EXPORT GLSurfaceOzoneSurfacelessSurfaceImpl
+    : public GLSurfaceOzoneSurfaceless {
+ public:
+  GLSurfaceOzoneSurfacelessSurfaceImpl(
+      scoped_ptr<ui::SurfaceOzoneEGL> ozone_surface,
+      AcceleratedWidget widget)
+      : GLSurfaceOzoneSurfaceless(ozone_surface.Pass(), widget),
+        fbo_(0),
+        current_surface_(0) {
+    for (auto& texture : textures_)
+      texture = 0;
+  }
+
+  unsigned int GetBackingFrameBufferObject() override { return fbo_; }
+
+  bool OnMakeCurrent(GLContext* context) override {
+    if (!fbo_) {
+      glGenFramebuffersEXT(1, &fbo_);
+      if (!fbo_)
+        return false;
+      glGenTextures(arraysize(textures_), textures_);
+      if (!CreatePixmaps())
+        return false;
+    }
+    BindFramebuffer();
+    glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_);
+    return SurfacelessEGL::OnMakeCurrent(context);
+  }
+
+  bool Resize(const gfx::Size& size) override {
+    if (size == GetSize())
+      return true;
+    return GLSurfaceOzoneSurfaceless::Resize(size) && CreatePixmaps();
+  }
+
+  bool SupportsPostSubBuffer() override { return false; }
+
+  bool SwapBuffers() override {
+    if (!images_[current_surface_]->ScheduleOverlayPlane(
+            widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
+            gfx::Rect(GetSize()), gfx::RectF(1, 1)))
+      return false;
+    if (!GLSurfaceOzoneSurfaceless::SwapBuffers())
+      return false;
+    current_surface_ ^= 1;
+    BindFramebuffer();
+    return true;
+  }
+
+  bool SwapBuffersAsync(const SwapCompletionCallback& callback) override {
+    if (!images_[current_surface_]->ScheduleOverlayPlane(
+            widget_, 0, OverlayTransform::OVERLAY_TRANSFORM_NONE,
+            gfx::Rect(GetSize()), gfx::RectF(1, 1)))
+      return false;
+    if (!GLSurfaceOzoneSurfaceless::SwapBuffersAsync(callback))
+      return false;
+    current_surface_ ^= 1;
+    BindFramebuffer();
+    return true;
+  }
+
+  void Destroy() override {
+    GLContext* current_context = GLContext::GetCurrent();
+    DCHECK(current_context && current_context->IsCurrent(this));
+    glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+    if (fbo_) {
+      glDeleteTextures(arraysize(textures_), textures_);
+      for (auto& texture : textures_)
+        texture = 0;
+      glDeleteFramebuffersEXT(1, &fbo_);
+      fbo_ = 0;
+    }
+    for (auto image : images_) {
+      if (image)
+        image->Destroy(true);
+    }
+  }
+
+ private:
+  class SurfaceImage : public GLImageLinuxDMABuffer {
+   public:
+    SurfaceImage(const gfx::Size& size, unsigned internalformat)
+        : GLImageLinuxDMABuffer(size, internalformat) {}
+
+    bool Initialize(scoped_refptr<ui::NativePixmap> pixmap,
+                    gfx::GpuMemoryBuffer::Format format) {
+      base::FileDescriptor handle(pixmap->GetDmaBufFd(), false);
+      if (!GLImageLinuxDMABuffer::Initialize(handle, format,
+                                             pixmap->GetDmaBufPitch()))
+        return false;
+      pixmap_ = pixmap;
+      return true;
+    }
+    bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
+                              int z_order,
+                              gfx::OverlayTransform transform,
+                              const gfx::Rect& bounds_rect,
+                              const gfx::RectF& crop_rect) override {
+      return ui::SurfaceFactoryOzone::GetInstance()->ScheduleOverlayPlane(
+          widget, z_order, transform, pixmap_, bounds_rect, crop_rect);
+    }
+
+   private:
+    ~SurfaceImage() override {}
+
+    scoped_refptr<ui::NativePixmap> pixmap_;
+  };
+
+  ~GLSurfaceOzoneSurfacelessSurfaceImpl() override {
+    DCHECK(!fbo_);
+    for (size_t i = 0; i < arraysize(textures_); i++)
+      DCHECK(!textures_[i]) << "texture " << i << " not released";
+  }
+
+  void BindFramebuffer() {
+    ScopedFrameBufferBinder fb(fbo_);
+    glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                              GL_TEXTURE_2D, textures_[current_surface_], 0);
+  }
+
+  bool CreatePixmaps() {
+    if (!fbo_)
+      return true;
+    for (size_t i = 0; i < arraysize(textures_); i++) {
+      scoped_refptr<ui::NativePixmap> pixmap =
+          ui::SurfaceFactoryOzone::GetInstance()->CreateNativePixmap(
+              widget_, GetSize(), ui::SurfaceFactoryOzone::RGBA_8888,
+              ui::SurfaceFactoryOzone::SCANOUT);
+      if (!pixmap)
+        return false;
+      scoped_refptr<SurfaceImage> image = new SurfaceImage(GetSize(), GL_RGBA);
+      if (!image->Initialize(pixmap, gfx::GpuMemoryBuffer::Format::BGRA_8888))
+        return false;
+      images_[i] = image;
+      // Bind image to texture.
+      ScopedTextureBinder binder(GL_TEXTURE_2D, textures_[i]);
+      if (!images_[i]->BindTexImage(GL_TEXTURE_2D))
+        return false;
+    }
+    return true;
+  }
+
+  GLuint fbo_;
+  GLuint textures_[2];
+  scoped_refptr<GLImage> images_[2];
+  int current_surface_;
+  DISALLOW_COPY_AND_ASSIGN(GLSurfaceOzoneSurfacelessSurfaceImpl);
+};
+
 }  // namespace
 
 // static
@@ -217,6 +372,27 @@
 }
 
 // static
+scoped_refptr<GLSurface> GLSurface::CreateSurfacelessViewGLSurface(
+    gfx::AcceleratedWidget window) {
+  if (GetGLImplementation() == kGLImplementationEGLGLES2 &&
+      window != kNullAcceleratedWidget &&
+      GLSurfaceEGL::IsEGLSurfacelessContextSupported() &&
+      ui::SurfaceFactoryOzone::GetInstance()->CanShowPrimaryPlaneAsOverlay()) {
+    scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
+        ui::SurfaceFactoryOzone::GetInstance()
+            ->CreateSurfacelessEGLSurfaceForWidget(window);
+    if (!surface_ozone)
+      return nullptr;
+    scoped_refptr<GLSurface> surface;
+    surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
+    if (surface->Initialize())
+      return surface;
+  }
+
+  return nullptr;
+}
+
+// static
 scoped_refptr<GLSurface> GLSurface::CreateViewGLSurface(
     gfx::AcceleratedWidget window) {
   if (GetGLImplementation() == kGLImplementationOSMesaGL) {
@@ -236,7 +412,8 @@
               ->CreateSurfacelessEGLSurfaceForWidget(window);
       if (!surface_ozone)
         return NULL;
-      surface = new GLSurfaceOzoneSurfaceless(surface_ozone.Pass(), window);
+      surface = new GLSurfaceOzoneSurfacelessSurfaceImpl(surface_ozone.Pass(),
+                                                         window);
     } else {
       scoped_ptr<ui::SurfaceOzoneEGL> surface_ozone =
           ui::SurfaceFactoryOzone::GetInstance()->CreateEGLSurfaceForWidget(
diff --git a/ui/keyboard/BUILD.gn b/ui/keyboard/BUILD.gn
index b504ba2..66a98a4 100644
--- a/ui/keyboard/BUILD.gn
+++ b/ui/keyboard/BUILD.gn
@@ -93,33 +93,31 @@
   path = rebase_path("//third_party/google_input_tools")
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("keyboard_unittests") {
-    sources = [
-      "keyboard_controller_unittest.cc",
-      "test/run_all_unittests.cc",
-    ]
+test("keyboard_unittests") {
+  sources = [
+    "keyboard_controller_unittest.cc",
+    "test/run_all_unittests.cc",
+  ]
 
-    deps = [
-      ":keyboard",
-      "//base",
-      "//base/allocator",
-      "//base/test:test_support",
-      "//content",
-      "//skia",
-      "//testing/gtest",
-      "//ui/aura:test_support",
-      "//ui/base",
-      "//ui/base/ime",
-      "//ui/base:test_support",
-      "//ui/compositor:test_support",
-      "//ui/events:test_support",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-      "//ui/resources:ui_test_pak",
-      "//ui/wm",
-      "//url",
-    ]
-  }
+  deps = [
+    ":keyboard",
+    "//base",
+    "//base/allocator",
+    "//base/test:test_support",
+    "//content",
+    "//skia",
+    "//testing/gtest",
+    "//ui/aura:test_support",
+    "//ui/base",
+    "//ui/base/ime",
+    "//ui/base:test_support",
+    "//ui/compositor:test_support",
+    "//ui/events:test_support",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//ui/resources:ui_test_pak",
+    "//ui/wm",
+    "//url",
+  ]
 }
diff --git a/ui/message_center/BUILD.gn b/ui/message_center/BUILD.gn
index b295019..cedc5b9 100644
--- a/ui/message_center/BUILD.gn
+++ b/ui/message_center/BUILD.gn
@@ -176,65 +176,63 @@
   ]
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("message_center_unittests") {
-    sources = [
-      "test/run_all_unittests.cc",
+test("message_center_unittests") {
+  sources = [
+    "test/run_all_unittests.cc",
+  ]
+
+  deps = [
+    ":message_center",
+    ":test_support",
+    "//base",
+    "//base/allocator",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/base",
+    "//ui/events",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//ui/resources",
+    "//ui/resources:ui_test_pak",
+    "//url",
+  ]
+
+  if (enable_notifications && !is_android) {
+    sources += [
+      "cocoa/notification_controller_unittest.mm",
+      "cocoa/popup_collection_unittest.mm",
+      "cocoa/popup_controller_unittest.mm",
+      "cocoa/settings_controller_unittest.mm",
+      "cocoa/status_item_view_unittest.mm",
+      "cocoa/tray_controller_unittest.mm",
+      "cocoa/tray_view_controller_unittest.mm",
+      "message_center_impl_unittest.cc",
+      "message_center_tray_unittest.cc",
+      "notification_delegate_unittest.cc",
+      "notification_list_unittest.cc",
     ]
 
-    deps = [
-      ":message_center",
-      ":test_support",
-      "//base",
-      "//base/allocator",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/base",
-      "//ui/events",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-      "//ui/resources",
-      "//ui/resources:ui_test_pak",
-      "//url",
-    ]
+    if (is_mac) {
+      deps += [ "//ui/gfx:test_support" ]
+    }
 
-    if (enable_notifications && !is_android) {
+    if (toolkit_views && !is_mac) {
       sources += [
-        "cocoa/notification_controller_unittest.mm",
-        "cocoa/popup_collection_unittest.mm",
-        "cocoa/popup_controller_unittest.mm",
-        "cocoa/settings_controller_unittest.mm",
-        "cocoa/status_item_view_unittest.mm",
-        "cocoa/tray_controller_unittest.mm",
-        "cocoa/tray_view_controller_unittest.mm",
-        "message_center_impl_unittest.cc",
-        "message_center_tray_unittest.cc",
-        "notification_delegate_unittest.cc",
-        "notification_list_unittest.cc",
+        "views/bounded_label_unittest.cc",
+        "views/message_center_view_unittest.cc",
+        "views/message_popup_collection_unittest.cc",
+        "views/notification_view_unittest.cc",
+        "views/notifier_settings_view_unittest.cc",
       ]
-
-      if (is_mac) {
-        deps += [ "//ui/gfx:test_support" ]
-      }
-
-      if (toolkit_views && !is_mac) {
-        sources += [
-          "views/bounded_label_unittest.cc",
-          "views/message_center_view_unittest.cc",
-          "views/message_popup_collection_unittest.cc",
-          "views/notification_view_unittest.cc",
-          "views/notifier_settings_view_unittest.cc",
-        ]
-        deps += [
-          # Compositor is needed by message_center_view_unittest.cc and for the
-          # fonts used by bounded_label_unittest.cc.
-          "//ui/compositor",
-          "//ui/views",
-          "//ui/views:test_support",
-        ]
-      }
-    }  # enable_notifications && !is_android
-  }
+      deps += [
+        # Compositor is needed by message_center_view_unittest.cc and for the
+        # fonts used by bounded_label_unittest.cc.
+        "//ui/compositor",
+        "//ui/views",
+        "//ui/views:test_support",
+      ]
+    }
+  }  # enable_notifications && !is_android
 }
diff --git a/ui/ozone/platform/dri/BUILD.gn b/ui/ozone/platform/dri/BUILD.gn
index d796a60..f7c55c5 100644
--- a/ui/ozone/platform/dri/BUILD.gn
+++ b/ui/ozone/platform/dri/BUILD.gn
@@ -52,8 +52,8 @@
     "dri_window_delegate_manager.h",
     "dri_window_manager.cc",
     "dri_window_manager.h",
-    "dri_wrapper.cc",
-    "dri_wrapper.h",
+    "drm_device.cc",
+    "drm_device.h",
     "drm_device_generator.cc",
     "drm_device_generator.h",
     "drm_device_manager.cc",
@@ -149,14 +149,14 @@
       "gbm_buffer.h",
       "gbm_buffer_base.cc",
       "gbm_buffer_base.h",
+      "gbm_device.cc",
+      "gbm_device.h",
       "gbm_surface.cc",
       "gbm_surface.h",
       "gbm_surface_factory.cc",
       "gbm_surface_factory.h",
       "gbm_surfaceless.cc",
       "gbm_surfaceless.h",
-      "gbm_wrapper.cc",
-      "gbm_wrapper.h",
       "ozone_platform_gbm.cc",
       "ozone_platform_gbm.h",
     ]
diff --git a/ui/ozone/platform/dri/crtc_controller.cc b/ui/ozone/platform/dri/crtc_controller.cc
index b5dcb14..d9e86f23 100644
--- a/ui/ozone/platform/dri/crtc_controller.cc
+++ b/ui/ozone/platform/dri/crtc_controller.cc
@@ -6,13 +6,13 @@
 
 #include "base/logging.h"
 #include "base/time/time.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/page_flip_observer.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 
 namespace ui {
 
-CrtcController::CrtcController(const scoped_refptr<DriWrapper>& drm,
+CrtcController::CrtcController(const scoped_refptr<DrmDevice>& drm,
                                uint32_t crtc,
                                uint32_t connector)
     : drm_(drm),
diff --git a/ui/ozone/platform/dri/crtc_controller.h b/ui/ozone/platform/dri/crtc_controller.h
index 01dc9a6..827515ce 100644
--- a/ui/ozone/platform/dri/crtc_controller.h
+++ b/ui/ozone/platform/dri/crtc_controller.h
@@ -18,7 +18,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 class PageFlipObserver;
 
 // Wrapper around a CRTC.
@@ -29,14 +29,14 @@
 class OZONE_EXPORT CrtcController
     : public base::SupportsWeakPtr<CrtcController> {
  public:
-  CrtcController(const scoped_refptr<DriWrapper>& drm,
+  CrtcController(const scoped_refptr<DrmDevice>& drm,
                  uint32_t crtc,
                  uint32_t connector);
   ~CrtcController();
 
   uint32_t crtc() const { return crtc_; }
   uint32_t connector() const { return connector_; }
-  const scoped_refptr<DriWrapper>& drm() const { return drm_; }
+  const scoped_refptr<DrmDevice>& drm() const { return drm_; }
   bool is_disabled() const { return is_disabled_; }
   bool page_flip_pending() const { return page_flip_pending_; }
   uint64_t time_of_last_flip() const { return time_of_last_flip_; }
@@ -75,7 +75,7 @@
   void RemoveObserver(PageFlipObserver* observer);
 
  private:
-  scoped_refptr<DriWrapper> drm_;
+  scoped_refptr<DrmDevice> drm_;
 
   HardwareDisplayPlaneManager* overlay_plane_manager_;  // Not owned.
 
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.cc b/ui/ozone/platform/dri/display_snapshot_dri.cc
index 1ad9fb2c..164d5ee 100644
--- a/ui/ozone/platform/dri/display_snapshot_dri.cc
+++ b/ui/ozone/platform/dri/display_snapshot_dri.cc
@@ -14,7 +14,7 @@
 #include "ui/display/util/edid_parser.h"
 #include "ui/ozone/platform/dri/display_mode_dri.h"
 #include "ui/ozone/platform/dri/dri_util.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 #if !defined(DRM_MODE_CONNECTOR_DSI)
 #define DRM_MODE_CONNECTOR_DSI 16
@@ -46,7 +46,7 @@
   }
 }
 
-bool IsAspectPreserving(DriWrapper* drm, drmModeConnector* connector) {
+bool IsAspectPreserving(DrmDevice* drm, drmModeConnector* connector) {
   ScopedDrmPropertyPtr property(drm->GetProperty(connector, "scaling mode"));
   if (!property)
     return false;
@@ -67,7 +67,7 @@
 
 }  // namespace
 
-DisplaySnapshotDri::DisplaySnapshotDri(const scoped_refptr<DriWrapper>& drm,
+DisplaySnapshotDri::DisplaySnapshotDri(const scoped_refptr<DrmDevice>& drm,
                                        drmModeConnector* connector,
                                        drmModeCrtc* crtc,
                                        uint32_t index)
diff --git a/ui/ozone/platform/dri/display_snapshot_dri.h b/ui/ozone/platform/dri/display_snapshot_dri.h
index 0a7052b..2ba799034 100644
--- a/ui/ozone/platform/dri/display_snapshot_dri.h
+++ b/ui/ozone/platform/dri/display_snapshot_dri.h
@@ -11,17 +11,17 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 class DisplaySnapshotDri : public DisplaySnapshot {
  public:
-  DisplaySnapshotDri(const scoped_refptr<DriWrapper>& drm,
+  DisplaySnapshotDri(const scoped_refptr<DrmDevice>& drm,
                      drmModeConnector* connector,
                      drmModeCrtc* crtc,
                      uint32_t index);
   ~DisplaySnapshotDri() override;
 
-  scoped_refptr<DriWrapper> drm() const { return drm_; }
+  scoped_refptr<DrmDevice> drm() const { return drm_; }
   // Native properties of a display used by the DRI implementation in
   // configuring this display.
   uint32_t connector() const { return connector_; }
@@ -32,7 +32,7 @@
   std::string ToString() const override;
 
  private:
-  scoped_refptr<DriWrapper> drm_;
+  scoped_refptr<DrmDevice> drm_;
   uint32_t connector_;
   uint32_t crtc_;
   ScopedDrmPropertyPtr dpms_property_;
diff --git a/ui/ozone/platform/dri/dri.gypi b/ui/ozone/platform/dri/dri.gypi
index 77795af..e44b3b1 100644
--- a/ui/ozone/platform/dri/dri.gypi
+++ b/ui/ozone/platform/dri/dri.gypi
@@ -74,8 +74,8 @@
         'dri_window_delegate_manager.h',
         'dri_window_manager.cc',
         'dri_window_manager.h',
-        'dri_wrapper.cc',
-        'dri_wrapper.h',
+        'drm_device.cc',
+        'drm_device.h',
         'drm_device_generator.cc',
         'drm_device_generator.h',
         'drm_device_manager.cc',
@@ -124,8 +124,8 @@
           'hardware_display_controller_unittest.cc',
           'hardware_display_plane_manager_unittest.cc',
           'screen_manager_unittest.cc',
-          'test/mock_dri_wrapper.cc',
-          'test/mock_dri_wrapper.h',
+          'test/mock_drm_device.cc',
+          'test/mock_drm_device.h',
         ],
       },
     },
diff --git a/ui/ozone/platform/dri/dri_buffer.cc b/ui/ozone/platform/dri/dri_buffer.cc
index 9fa284f..bd2c2c2 100644
--- a/ui/ozone/platform/dri/dri_buffer.cc
+++ b/ui/ozone/platform/dri/dri_buffer.cc
@@ -5,7 +5,7 @@
 #include "ui/ozone/platform/dri/dri_buffer.h"
 
 #include "base/logging.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
@@ -34,8 +34,8 @@
 
 }  // namespace
 
-DriBuffer::DriBuffer(const scoped_refptr<DriWrapper>& dri)
-    : dri_(dri), handle_(0), framebuffer_(0) {
+DriBuffer::DriBuffer(const scoped_refptr<DrmDevice>& drm)
+    : drm_(drm), handle_(0), framebuffer_(0) {
 }
 
 DriBuffer::~DriBuffer() {
@@ -43,26 +43,26 @@
     return;
 
   if (framebuffer_)
-    dri_->RemoveFramebuffer(framebuffer_);
+    drm_->RemoveFramebuffer(framebuffer_);
 
   SkImageInfo info;
   void* pixels = const_cast<void*>(surface_->peekPixels(&info, NULL));
   if (!pixels)
     return;
 
-  dri_->DestroyDumbBuffer(info, handle_, stride_, pixels);
+  drm_->DestroyDumbBuffer(info, handle_, stride_, pixels);
 }
 
 bool DriBuffer::Initialize(const SkImageInfo& info,
                            bool should_register_framebuffer) {
   void* pixels = NULL;
-  if (!dri_->CreateDumbBuffer(info, &handle_, &stride_, &pixels)) {
+  if (!drm_->CreateDumbBuffer(info, &handle_, &stride_, &pixels)) {
     VLOG(2) << "Cannot create drm dumb buffer";
     return false;
   }
 
   if (should_register_framebuffer &&
-      !dri_->AddFramebuffer(
+      !drm_->AddFramebuffer(
           info.width(), info.height(), GetColorDepth(info.colorType()),
           info.bytesPerPixel() << 3, stride_, handle_, &framebuffer_)) {
     VLOG(2) << "Failed to register framebuffer: " << strerror(errno);
@@ -100,7 +100,7 @@
 DriBufferGenerator::~DriBufferGenerator() {}
 
 scoped_refptr<ScanoutBuffer> DriBufferGenerator::Create(
-    const scoped_refptr<DriWrapper>& drm,
+    const scoped_refptr<DrmDevice>& drm,
     const gfx::Size& size) {
   scoped_refptr<DriBuffer> buffer(new DriBuffer(drm));
   SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
diff --git a/ui/ozone/platform/dri/dri_buffer.h b/ui/ozone/platform/dri/dri_buffer.h
index 7bcca1b..0b9f8e68 100644
--- a/ui/ozone/platform/dri/dri_buffer.h
+++ b/ui/ozone/platform/dri/dri_buffer.h
@@ -13,14 +13,14 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 // Wrapper for a DRM allocated buffer. Keeps track of the native properties of
 // the buffer and wraps the pixel memory into a SkSurface which can be used to
 // draw into using Skia.
 class OZONE_EXPORT DriBuffer : public ScanoutBuffer {
  public:
-  DriBuffer(const scoped_refptr<DriWrapper>& dri);
+  DriBuffer(const scoped_refptr<DrmDevice>& drm);
 
   // Allocates the backing pixels and wraps them in |surface_|. |info| is used
   // to describe the buffer characteristics (size, color format).
@@ -38,7 +38,7 @@
  protected:
   ~DriBuffer() override;
 
-  scoped_refptr<DriWrapper> dri_;
+  scoped_refptr<DrmDevice> drm_;
 
   // Wrapper around the native pixel memory.
   skia::RefPtr<SkSurface> surface_;
@@ -62,7 +62,7 @@
   ~DriBufferGenerator() override;
 
   // ScanoutBufferGenerator:
-  scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DriWrapper>& drm,
+  scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm,
                                       const gfx::Size& size) override;
 
  private:
diff --git a/ui/ozone/platform/dri/dri_console_buffer.cc b/ui/ozone/platform/dri/dri_console_buffer.cc
index 204590f..91aba48 100644
--- a/ui/ozone/platform/dri/dri_console_buffer.cc
+++ b/ui/ozone/platform/dri/dri_console_buffer.cc
@@ -9,14 +9,14 @@
 
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "ui/ozone/platform/dri/dri_util.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/scoped_drm_types.h"
 
 namespace ui {
 
-DriConsoleBuffer::DriConsoleBuffer(const scoped_refptr<DriWrapper>& dri,
+DriConsoleBuffer::DriConsoleBuffer(const scoped_refptr<DrmDevice>& drm,
                                    uint32_t framebuffer)
-    : dri_(dri),
+    : drm_(drm),
       handle_(0),
       framebuffer_(framebuffer),
       mmap_base_(NULL),
@@ -30,7 +30,7 @@
 }
 
 bool DriConsoleBuffer::Initialize() {
-  ScopedDrmFramebufferPtr fb(dri_->GetFramebuffer(framebuffer_));
+  ScopedDrmFramebufferPtr fb(drm_->GetFramebuffer(framebuffer_));
 
   if (!fb)
     return false;
@@ -41,7 +41,7 @@
 
   mmap_size_ = info.getSafeSize(stride_);
 
-  if (!MapDumbBuffer(dri_->get_fd(), fb->handle, mmap_size_, &mmap_base_)) {
+  if (!MapDumbBuffer(drm_->get_fd(), fb->handle, mmap_size_, &mmap_base_)) {
     mmap_base_ = NULL;
     return false;
   }
diff --git a/ui/ozone/platform/dri/dri_console_buffer.h b/ui/ozone/platform/dri/dri_console_buffer.h
index 6a9c3cca..e174955 100644
--- a/ui/ozone/platform/dri/dri_console_buffer.h
+++ b/ui/ozone/platform/dri/dri_console_buffer.h
@@ -14,7 +14,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 // Wrapper for the console buffer. This is the buffer that is allocated by
 // default by the system and is used when no application is controlling the
@@ -22,7 +22,7 @@
 // memory into a SkSurface which can be used to draw into using Skia.
 class DriConsoleBuffer {
  public:
-  DriConsoleBuffer(const scoped_refptr<DriWrapper>& dri, uint32_t framebuffer);
+  DriConsoleBuffer(const scoped_refptr<DrmDevice>& drm, uint32_t framebuffer);
   ~DriConsoleBuffer();
 
   SkCanvas* canvas() { return surface_->getCanvas(); }
@@ -34,7 +34,7 @@
   bool Initialize();
 
  protected:
-  scoped_refptr<DriWrapper> dri_;
+  scoped_refptr<DrmDevice> drm_;
 
   // Wrapper around the native pixel memory.
   skia::RefPtr<SkSurface> surface_;
diff --git a/ui/ozone/platform/dri/dri_gpu_platform_support.cc b/ui/ozone/platform/dri/dri_gpu_platform_support.cc
index d4116bf..c9736a2 100644
--- a/ui/ozone/platform/dri/dri_gpu_platform_support.cc
+++ b/ui/ozone/platform/dri/dri_gpu_platform_support.cc
@@ -11,7 +11,7 @@
 #include "ui/ozone/common/gpu/ozone_gpu_messages.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/native_display_delegate_dri.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/dri/dri_surface.cc b/ui/ozone/platform/dri/dri_surface.cc
index 89107f2b..5fb108c 100644
--- a/ui/ozone/platform/dri/dri_surface.cc
+++ b/ui/ozone/platform/dri/dri_surface.cc
@@ -14,16 +14,16 @@
 #include "ui/ozone/platform/dri/dri_buffer.h"
 #include "ui/ozone/platform/dri/dri_vsync_provider.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 
 namespace ui {
 
 namespace {
 
-scoped_refptr<DriBuffer> AllocateBuffer(const scoped_refptr<DriWrapper>& dri,
+scoped_refptr<DriBuffer> AllocateBuffer(const scoped_refptr<DrmDevice>& drm,
                                         const gfx::Size& size) {
-  scoped_refptr<DriBuffer> buffer(new DriBuffer(dri));
+  scoped_refptr<DriBuffer> buffer(new DriBuffer(drm));
   SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
 
   bool initialized =
@@ -58,7 +58,7 @@
   // For the display buffers use the mode size since a |viewport_size| smaller
   // than the display size will not scanout.
   for (size_t i = 0; i < arraysize(buffers_); ++i)
-    buffers_[i] = AllocateBuffer(controller->GetAllocationDriWrapper(),
+    buffers_[i] = AllocateBuffer(controller->GetAllocationDrmDevice(),
                                  controller->GetModeSize());
 }
 
diff --git a/ui/ozone/platform/dri/dri_surface_unittest.cc b/ui/ozone/platform/dri/dri_surface_unittest.cc
index 53d155a..949c8c5 100644
--- a/ui/ozone/platform/dri/dri_surface_unittest.cc
+++ b/ui/ozone/platform/dri/dri_surface_unittest.cc
@@ -12,7 +12,7 @@
 #include "ui/ozone/platform/dri/dri_surface.h"
 #include "ui/ozone/platform/dri/dri_window_delegate.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
 
 namespace {
 
@@ -26,7 +26,7 @@
 
 class MockDriWindowDelegate : public ui::DriWindowDelegate {
  public:
-  MockDriWindowDelegate(ui::DriWrapper* drm) {
+  MockDriWindowDelegate(ui::DrmDevice* drm) {
     controller_.reset(new ui::HardwareDisplayController(make_scoped_ptr(
         new ui::CrtcController(drm, kDefaultCrtc, kDefaultConnector))));
     scoped_refptr<ui::DriBuffer> buffer(new ui::DriBuffer(drm));
@@ -69,7 +69,7 @@
 
  protected:
   scoped_ptr<base::MessageLoop> message_loop_;
-  scoped_refptr<ui::MockDriWrapper> drm_;
+  scoped_refptr<ui::MockDrmDevice> drm_;
   scoped_ptr<MockDriWindowDelegate> window_delegate_;
   scoped_ptr<ui::DriSurface> surface_;
 
@@ -81,7 +81,7 @@
   message_loop_.reset(new base::MessageLoopForUI);
   std::vector<uint32_t> crtcs;
   crtcs.push_back(kDefaultCrtc);
-  drm_ = new ui::MockDriWrapper(true, crtcs, kPlanesPerCrtc);
+  drm_ = new ui::MockDrmDevice(true, crtcs, kPlanesPerCrtc);
   window_delegate_.reset(new MockDriWindowDelegate(drm_.get()));
   surface_.reset(new ui::DriSurface(window_delegate_.get()));
   surface_->ResizeCanvas(gfx::Size(kDefaultMode.hdisplay,
diff --git a/ui/ozone/platform/dri/dri_util.cc b/ui/ozone/platform/dri/dri_util.cc
index 7849efdc..338c411 100644
--- a/ui/ozone/platform/dri/dri_util.cc
+++ b/ui/ozone/platform/dri/dri_util.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/strings/stringprintf.h"
 #include "ui/ozone/platform/dri/dri_util.h"
 
 #include <errno.h>
@@ -13,7 +12,8 @@
 #include <xf86drm.h>
 #include <xf86drmMode.h>
 
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "base/strings/stringprintf.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/screen_manager.h"
 
 namespace ui {
@@ -142,7 +142,7 @@
   return true;
 }
 
-void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DriWrapper>& drm,
+void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DrmDevice>& drm,
                                          ScreenManager* screen_manager) {
   LOG(WARNING) << "Forcing initialization of primary display.";
   ScopedVector<HardwareDisplayControllerInfo> displays =
diff --git a/ui/ozone/platform/dri/dri_util.h b/ui/ozone/platform/dri/dri_util.h
index 742f512f..eb83939 100644
--- a/ui/ozone/platform/dri/dri_util.h
+++ b/ui/ozone/platform/dri/dri_util.h
@@ -15,7 +15,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 class ScreenManager;
 
 // Representation of the information required to initialize and configure a
@@ -49,7 +49,7 @@
                    uint32_t size,
                    void** pixels);
 
-void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DriWrapper>& drm,
+void ForceInitializationOfPrimaryDisplay(const scoped_refptr<DrmDevice>& drm,
                                          ScreenManager* screen_manager);
 
 base::FilePath GetPrimaryDisplayCardPath();
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl.cc b/ui/ozone/platform/dri/dri_window_delegate_impl.cc
index af81012d..9a9c8a33 100644
--- a/ui/ozone/platform/dri/dri_window_delegate_impl.cc
+++ b/ui/ozone/platform/dri/dri_window_delegate_impl.cc
@@ -9,7 +9,7 @@
 #include "third_party/skia/include/core/SkDevice.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "ui/ozone/platform/dri/dri_buffer.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/screen_manager.h"
 
@@ -181,9 +181,9 @@
 }
 
 void DriWindowDelegateImpl::UpdateWidgetToDrmDeviceMapping() {
-  scoped_refptr<DriWrapper> drm = nullptr;
+  scoped_refptr<DrmDevice> drm = nullptr;
   if (controller_)
-    drm = controller_->GetAllocationDriWrapper();
+    drm = controller_->GetAllocationDrmDevice();
 
   device_manager_->UpdateDrmDevice(widget_, drm);
 }
@@ -194,7 +194,7 @@
       cursor_buffers_[i] = nullptr;
     }
   } else {
-    scoped_refptr<DriWrapper> drm = controller_->GetAllocationDriWrapper();
+    scoped_refptr<DrmDevice> drm = controller_->GetAllocationDrmDevice();
 
     uint64_t cursor_width = 64;
     uint64_t cursor_height = 64;
diff --git a/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc b/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc
index 95068bd..b02ee8fa 100644
--- a/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc
+++ b/ui/ozone/platform/dri/dri_window_delegate_impl_unittest.cc
@@ -18,7 +18,7 @@
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/platform/dri/screen_manager.h"
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
 namespace {
@@ -33,7 +33,7 @@
 const int kDefaultCursorSize = 64;
 
 std::vector<skia::RefPtr<SkSurface>> GetCursorBuffers(
-    const scoped_refptr<ui::MockDriWrapper> drm) {
+    const scoped_refptr<ui::MockDrmDevice> drm) {
   std::vector<skia::RefPtr<SkSurface>> cursor_buffers;
   for (const skia::RefPtr<SkSurface>& cursor_buffer : drm->buffers()) {
     if (cursor_buffer->width() == kDefaultCursorSize &&
@@ -56,7 +56,7 @@
 
  protected:
   scoped_ptr<base::MessageLoop> message_loop_;
-  scoped_refptr<ui::MockDriWrapper> dri_;
+  scoped_refptr<ui::MockDrmDevice> drm_;
   scoped_ptr<ui::DriBufferGenerator> buffer_generator_;
   scoped_ptr<ui::ScreenManager> screen_manager_;
   scoped_ptr<ui::DrmDeviceManager> drm_device_manager_;
@@ -68,14 +68,14 @@
 
 void DriWindowDelegateImplTest::SetUp() {
   message_loop_.reset(new base::MessageLoopForUI);
-  dri_ = new ui::MockDriWrapper();
+  drm_ = new ui::MockDrmDevice();
   buffer_generator_.reset(new ui::DriBufferGenerator());
   screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
-  screen_manager_->AddDisplayController(dri_, kDefaultCrtc, kDefaultConnector);
+  screen_manager_->AddDisplayController(drm_, kDefaultCrtc, kDefaultConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
+      drm_, kDefaultCrtc, kDefaultConnector, gfx::Point(), kDefaultMode);
 
-  drm_device_manager_.reset(new ui::DrmDeviceManager(dri_));
+  drm_device_manager_.reset(new ui::DrmDeviceManager(drm_));
   window_delegate_manager_.reset(new ui::DriWindowDelegateManager());
 
   scoped_ptr<ui::DriWindowDelegate> window_delegate(
@@ -109,7 +109,7 @@
       ->SetCursor(cursor_bitmaps, gfx::Point(4, 2), 0);
 
   SkBitmap cursor;
-  std::vector<skia::RefPtr<SkSurface>> cursor_buffers = GetCursorBuffers(dri_);
+  std::vector<skia::RefPtr<SkSurface>> cursor_buffers = GetCursorBuffers(drm_);
   EXPECT_EQ(2u, cursor_buffers.size());
 
   // Buffers 1 is the cursor backbuffer we just drew in.
@@ -130,7 +130,7 @@
 
 TEST_F(DriWindowDelegateImplTest, CheckCursorSurfaceAfterChangingDevice) {
   // Add another device.
-  scoped_refptr<ui::MockDriWrapper> drm = new ui::MockDriWrapper();
+  scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice();
   screen_manager_->AddDisplayController(drm, kDefaultCrtc, kDefaultConnector);
   screen_manager_->ConfigureDisplayController(
       drm, kDefaultCrtc, kDefaultConnector,
diff --git a/ui/ozone/platform/dri/dri_wrapper.cc b/ui/ozone/platform/dri/drm_device.cc
similarity index 72%
rename from ui/ozone/platform/dri/dri_wrapper.cc
rename to ui/ozone/platform/dri/drm_device.cc
index 87b250ec..e51059d 100644
--- a/ui/ozone/platform/dri/dri_wrapper.cc
+++ b/ui/ozone/platform/dri/drm_device.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 #include <fcntl.h>
 #include <sys/mman.h>
@@ -27,13 +27,13 @@
 
 struct PageFlipPayload {
   PageFlipPayload(const scoped_refptr<base::TaskRunner>& task_runner,
-                  const DriWrapper::PageFlipCallback& callback)
+                  const DrmDevice::PageFlipCallback& callback)
       : task_runner(task_runner), callback(callback) {}
 
   // Task runner for the thread scheduling the page flip event. This is used to
   // run the callback on the same thread the callback was created on.
   scoped_refptr<base::TaskRunner> task_runner;
-  DriWrapper::PageFlipCallback callback;
+  DrmDevice::PageFlipCallback callback;
 };
 
 bool DrmCreateDumbBuffer(int fd,
@@ -99,8 +99,8 @@
 
 }  // namespace
 
-class DriWrapper::IOWatcher
-    : public base::RefCountedThreadSafe<DriWrapper::IOWatcher>,
+class DrmDevice::IOWatcher
+    : public base::RefCountedThreadSafe<DrmDevice::IOWatcher>,
       public base::MessagePumpLibevent::Watcher {
  public:
   IOWatcher(int fd,
@@ -173,7 +173,7 @@
   DISALLOW_COPY_AND_ASSIGN(IOWatcher);
 };
 
-DriWrapper::DriWrapper(const base::FilePath& device_path)
+DrmDevice::DrmDevice(const base::FilePath& device_path)
     : device_path_(device_path),
       file_(device_path,
             base::File::FLAG_OPEN | base::File::FLAG_READ |
@@ -183,16 +183,16 @@
       << "': " << base::File::ErrorToString(file_.error_details());
 }
 
-DriWrapper::DriWrapper(const base::FilePath& device_path, base::File file)
+DrmDevice::DrmDevice(const base::FilePath& device_path, base::File file)
     : device_path_(device_path), file_(file.Pass()) {
 }
 
-DriWrapper::~DriWrapper() {
+DrmDevice::~DrmDevice() {
   if (watcher_)
     watcher_->Shutdown();
 }
 
-bool DriWrapper::Initialize() {
+bool DrmDevice::Initialize() {
   // Ignore devices that cannot perform modesetting.
   if (!CanQueryForResources(file_.GetPlatformFile())) {
     VLOG(2) << "Cannot query for resources for '" << device_path_.value()
@@ -211,33 +211,33 @@
   return true;
 }
 
-void DriWrapper::InitializeTaskRunner(
+void DrmDevice::InitializeTaskRunner(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
   DCHECK(!task_runner_);
   task_runner_ = task_runner;
   watcher_ = new IOWatcher(file_.GetPlatformFile(), task_runner_);
 }
 
-ScopedDrmCrtcPtr DriWrapper::GetCrtc(uint32_t crtc_id) {
+ScopedDrmCrtcPtr DrmDevice::GetCrtc(uint32_t crtc_id) {
   DCHECK(file_.IsValid());
   return ScopedDrmCrtcPtr(drmModeGetCrtc(file_.GetPlatformFile(), crtc_id));
 }
 
-bool DriWrapper::SetCrtc(uint32_t crtc_id,
-                         uint32_t framebuffer,
-                         std::vector<uint32_t> connectors,
-                         drmModeModeInfo* mode) {
+bool DrmDevice::SetCrtc(uint32_t crtc_id,
+                        uint32_t framebuffer,
+                        std::vector<uint32_t> connectors,
+                        drmModeModeInfo* mode) {
   DCHECK(file_.IsValid());
   DCHECK(!connectors.empty());
   DCHECK(mode);
 
-  TRACE_EVENT2("dri", "DriWrapper::SetCrtc", "crtc", crtc_id, "size",
+  TRACE_EVENT2("dri", "DrmDevice::SetCrtc", "crtc", crtc_id, "size",
                gfx::Size(mode->hdisplay, mode->vdisplay).ToString());
   return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, framebuffer, 0, 0,
                          vector_as_array(&connectors), connectors.size(), mode);
 }
 
-bool DriWrapper::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
+bool DrmDevice::SetCrtc(drmModeCrtc* crtc, std::vector<uint32_t> connectors) {
   DCHECK(file_.IsValid());
   // If there's no buffer then the CRTC was disabled.
   if (!crtc->buffer_id)
@@ -245,58 +245,54 @@
 
   DCHECK(!connectors.empty());
 
-  TRACE_EVENT1("dri", "DriWrapper::RestoreCrtc",
-               "crtc", crtc->crtc_id);
+  TRACE_EVENT1("dri", "DrmDevice::RestoreCrtc", "crtc", crtc->crtc_id);
   return !drmModeSetCrtc(file_.GetPlatformFile(), crtc->crtc_id,
                          crtc->buffer_id, crtc->x, crtc->y,
                          vector_as_array(&connectors), connectors.size(),
                          &crtc->mode);
 }
 
-bool DriWrapper::DisableCrtc(uint32_t crtc_id) {
+bool DrmDevice::DisableCrtc(uint32_t crtc_id) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::DisableCrtc",
-               "crtc", crtc_id);
+  TRACE_EVENT1("dri", "DrmDevice::DisableCrtc", "crtc", crtc_id);
   return !drmModeSetCrtc(file_.GetPlatformFile(), crtc_id, 0, 0, 0, NULL, 0,
                          NULL);
 }
 
-ScopedDrmConnectorPtr DriWrapper::GetConnector(uint32_t connector_id) {
+ScopedDrmConnectorPtr DrmDevice::GetConnector(uint32_t connector_id) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::GetConnector", "connector", connector_id);
+  TRACE_EVENT1("dri", "DrmDevice::GetConnector", "connector", connector_id);
   return ScopedDrmConnectorPtr(
       drmModeGetConnector(file_.GetPlatformFile(), connector_id));
 }
 
-bool DriWrapper::AddFramebuffer(uint32_t width,
-                                uint32_t height,
-                                uint8_t depth,
-                                uint8_t bpp,
-                                uint32_t stride,
-                                uint32_t handle,
-                                uint32_t* framebuffer) {
+bool DrmDevice::AddFramebuffer(uint32_t width,
+                               uint32_t height,
+                               uint8_t depth,
+                               uint8_t bpp,
+                               uint32_t stride,
+                               uint32_t handle,
+                               uint32_t* framebuffer) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::AddFramebuffer",
-               "handle", handle);
+  TRACE_EVENT1("dri", "DrmDevice::AddFramebuffer", "handle", handle);
   return !drmModeAddFB(file_.GetPlatformFile(), width, height, depth, bpp,
                        stride, handle, framebuffer);
 }
 
-bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
+bool DrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::RemoveFramebuffer",
-               "framebuffer", framebuffer);
+  TRACE_EVENT1("dri", "DrmDevice::RemoveFramebuffer", "framebuffer",
+               framebuffer);
   return !drmModeRmFB(file_.GetPlatformFile(), framebuffer);
 }
 
-bool DriWrapper::PageFlip(uint32_t crtc_id,
-                          uint32_t framebuffer,
-                          bool is_sync,
-                          const PageFlipCallback& callback) {
+bool DrmDevice::PageFlip(uint32_t crtc_id,
+                         uint32_t framebuffer,
+                         bool is_sync,
+                         const PageFlipCallback& callback) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT2("dri", "DriWrapper::PageFlip",
-               "crtc", crtc_id,
-               "framebuffer", framebuffer);
+  TRACE_EVENT2("dri", "DrmDevice::PageFlip", "crtc", crtc_id, "framebuffer",
+               framebuffer);
 
   if (watcher_)
     watcher_->SetPaused(is_sync);
@@ -329,14 +325,13 @@
   return false;
 }
 
-bool DriWrapper::PageFlipOverlay(uint32_t crtc_id,
-                                 uint32_t framebuffer,
-                                 const gfx::Rect& location,
-                                 const gfx::Rect& source,
-                                 int overlay_plane) {
+bool DrmDevice::PageFlipOverlay(uint32_t crtc_id,
+                                uint32_t framebuffer,
+                                const gfx::Rect& location,
+                                const gfx::Rect& source,
+                                int overlay_plane) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT2("dri", "DriWrapper::PageFlipOverlay",
-               "crtc", crtc_id,
+  TRACE_EVENT2("dri", "DrmDevice::PageFlipOverlay", "crtc", crtc_id,
                "framebuffer", framebuffer);
   return !drmModeSetPlane(file_.GetPlatformFile(), overlay_plane, crtc_id,
                           framebuffer, 0, location.x(), location.y(),
@@ -344,19 +339,17 @@
                           source.y(), source.width(), source.height());
 }
 
-ScopedDrmFramebufferPtr DriWrapper::GetFramebuffer(uint32_t framebuffer) {
+ScopedDrmFramebufferPtr DrmDevice::GetFramebuffer(uint32_t framebuffer) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::GetFramebuffer",
-               "framebuffer", framebuffer);
+  TRACE_EVENT1("dri", "DrmDevice::GetFramebuffer", "framebuffer", framebuffer);
   return ScopedDrmFramebufferPtr(
       drmModeGetFB(file_.GetPlatformFile(), framebuffer));
 }
 
-ScopedDrmPropertyPtr DriWrapper::GetProperty(drmModeConnector* connector,
-                                             const char* name) {
-  TRACE_EVENT2("dri", "DriWrapper::GetProperty",
-               "connector", connector->connector_id,
-               "name", name);
+ScopedDrmPropertyPtr DrmDevice::GetProperty(drmModeConnector* connector,
+                                            const char* name) {
+  TRACE_EVENT2("dri", "DrmDevice::GetProperty", "connector",
+               connector->connector_id, "name", name);
   for (int i = 0; i < connector->count_props; ++i) {
     ScopedDrmPropertyPtr property(
         drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
@@ -370,25 +363,24 @@
   return ScopedDrmPropertyPtr();
 }
 
-bool DriWrapper::SetProperty(uint32_t connector_id,
-                             uint32_t property_id,
-                             uint64_t value) {
+bool DrmDevice::SetProperty(uint32_t connector_id,
+                            uint32_t property_id,
+                            uint64_t value) {
   DCHECK(file_.IsValid());
   return !drmModeConnectorSetProperty(file_.GetPlatformFile(), connector_id,
                                       property_id, value);
 }
 
-bool DriWrapper::GetCapability(uint64_t capability, uint64_t* value) {
+bool DrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
   DCHECK(file_.IsValid());
   return !drmGetCap(file_.GetPlatformFile(), capability, value);
 }
 
-ScopedDrmPropertyBlobPtr DriWrapper::GetPropertyBlob(
-    drmModeConnector* connector, const char* name) {
+ScopedDrmPropertyBlobPtr DrmDevice::GetPropertyBlob(drmModeConnector* connector,
+                                                    const char* name) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT2("dri", "DriWrapper::GetPropertyBlob",
-               "connector", connector->connector_id,
-               "name", name);
+  TRACE_EVENT2("dri", "DrmDevice::GetPropertyBlob", "connector",
+               connector->connector_id, "name", name);
   for (int i = 0; i < connector->count_props; ++i) {
     ScopedDrmPropertyPtr property(
         drmModeGetProperty(file_.GetPlatformFile(), connector->props[i]));
@@ -404,28 +396,28 @@
   return ScopedDrmPropertyBlobPtr();
 }
 
-bool DriWrapper::SetCursor(uint32_t crtc_id,
-                           uint32_t handle,
-                           const gfx::Size& size) {
+bool DrmDevice::SetCursor(uint32_t crtc_id,
+                          uint32_t handle,
+                          const gfx::Size& size) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::SetCursor", "handle", handle);
+  TRACE_EVENT1("dri", "DrmDevice::SetCursor", "handle", handle);
   return !drmModeSetCursor(file_.GetPlatformFile(), crtc_id, handle,
                            size.width(), size.height());
 }
 
-bool DriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+bool DrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
   DCHECK(file_.IsValid());
   return !drmModeMoveCursor(file_.GetPlatformFile(), crtc_id, point.x(),
                             point.y());
 }
 
-bool DriWrapper::CreateDumbBuffer(const SkImageInfo& info,
-                                  uint32_t* handle,
-                                  uint32_t* stride,
-                                  void** pixels) {
+bool DrmDevice::CreateDumbBuffer(const SkImageInfo& info,
+                                 uint32_t* handle,
+                                 uint32_t* stride,
+                                 void** pixels) {
   DCHECK(file_.IsValid());
 
-  TRACE_EVENT0("dri", "DriWrapper::CreateDumbBuffer");
+  TRACE_EVENT0("dri", "DrmDevice::CreateDumbBuffer");
   if (!DrmCreateDumbBuffer(file_.GetPlatformFile(), info, handle, stride))
     return false;
 
@@ -438,22 +430,22 @@
   return true;
 }
 
-void DriWrapper::DestroyDumbBuffer(const SkImageInfo& info,
-                                   uint32_t handle,
-                                   uint32_t stride,
-                                   void* pixels) {
+void DrmDevice::DestroyDumbBuffer(const SkImageInfo& info,
+                                  uint32_t handle,
+                                  uint32_t stride,
+                                  void* pixels) {
   DCHECK(file_.IsValid());
-  TRACE_EVENT1("dri", "DriWrapper::DestroyDumbBuffer", "handle", handle);
+  TRACE_EVENT1("dri", "DrmDevice::DestroyDumbBuffer", "handle", handle);
   munmap(pixels, info.getSafeSize(stride));
   DrmDestroyDumbBuffer(file_.GetPlatformFile(), handle);
 }
 
-bool DriWrapper::SetMaster() {
+bool DrmDevice::SetMaster() {
   DCHECK(file_.IsValid());
   return (drmSetMaster(file_.GetPlatformFile()) == 0);
 }
 
-bool DriWrapper::DropMaster() {
+bool DrmDevice::DropMaster() {
   DCHECK(file_.IsValid());
   return (drmDropMaster(file_.GetPlatformFile()) == 0);
 }
diff --git a/ui/ozone/platform/dri/dri_wrapper.h b/ui/ozone/platform/dri/drm_device.h
similarity index 93%
rename from ui/ozone/platform/dri/dri_wrapper.h
rename to ui/ozone/platform/dri/drm_device.h
index 27582dbb..73b42bc 100644
--- a/ui/ozone/platform/dri/dri_wrapper.h
+++ b/ui/ozone/platform/dri/drm_device.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
-#define UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
+#ifndef UI_OZONE_PLATFORM_DRI_DRM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRI_DRM_DEVICE_H_
 
 #include <stdint.h>
 
@@ -38,14 +38,14 @@
 // Wraps DRM calls into a nice interface. Used to provide different
 // implementations of the DRM calls. For the actual implementation the DRM API
 // would be called. In unit tests this interface would be stubbed.
-class OZONE_EXPORT DriWrapper : public base::RefCountedThreadSafe<DriWrapper> {
+class OZONE_EXPORT DrmDevice : public base::RefCountedThreadSafe<DrmDevice> {
  public:
   typedef base::Callback<void(unsigned int /* frame */,
                               unsigned int /* seconds */,
                               unsigned int /* useconds */)> PageFlipCallback;
 
-  DriWrapper(const base::FilePath& device_path);
-  DriWrapper(const base::FilePath& device_path, base::File file);
+  DrmDevice(const base::FilePath& device_path);
+  DrmDevice(const base::FilePath& device_path, base::File file);
 
   // Open device.
   virtual bool Initialize();
@@ -141,7 +141,6 @@
                          uint32_t handle,
                          const gfx::Size& size);
 
-
   // Move the cursor on CRTC |crtc_id| to (x, y);
   virtual bool MoveCursor(uint32_t crtc_id, const gfx::Point& point);
 
@@ -166,9 +165,9 @@
   HardwareDisplayPlaneManager* plane_manager() { return plane_manager_.get(); }
 
  protected:
-  friend class base::RefCountedThreadSafe<DriWrapper>;
+  friend class base::RefCountedThreadSafe<DrmDevice>;
 
-  virtual ~DriWrapper();
+  virtual ~DrmDevice();
 
   scoped_ptr<HardwareDisplayPlaneManager> plane_manager_;
 
@@ -187,9 +186,9 @@
   // Watcher for |fd_| listening for page flip events.
   scoped_refptr<IOWatcher> watcher_;
 
-  DISALLOW_COPY_AND_ASSIGN(DriWrapper);
+  DISALLOW_COPY_AND_ASSIGN(DrmDevice);
 };
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_DRI_DRI_WRAPPER_H_
+#endif  // UI_OZONE_PLATFORM_DRI_DRM_DEVICE_H_
diff --git a/ui/ozone/platform/dri/drm_device_generator.cc b/ui/ozone/platform/dri/drm_device_generator.cc
index 13985db..f6f6f33 100644
--- a/ui/ozone/platform/dri/drm_device_generator.cc
+++ b/ui/ozone/platform/dri/drm_device_generator.cc
@@ -4,7 +4,7 @@
 
 #include "ui/ozone/platform/dri/drm_device_generator.h"
 
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
@@ -14,10 +14,10 @@
 DrmDeviceGenerator::~DrmDeviceGenerator() {
 }
 
-scoped_refptr<DriWrapper> DrmDeviceGenerator::CreateDevice(
+scoped_refptr<DrmDevice> DrmDeviceGenerator::CreateDevice(
     const base::FilePath& device_path,
     base::File file) {
-  scoped_refptr<DriWrapper> drm = new DriWrapper(device_path, file.Pass());
+  scoped_refptr<DrmDevice> drm = new DrmDevice(device_path, file.Pass());
   if (drm->Initialize())
     return drm;
 
diff --git a/ui/ozone/platform/dri/drm_device_generator.h b/ui/ozone/platform/dri/drm_device_generator.h
index acd25c02..8d59f72 100644
--- a/ui/ozone/platform/dri/drm_device_generator.h
+++ b/ui/ozone/platform/dri/drm_device_generator.h
@@ -10,7 +10,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 class DrmDeviceGenerator {
  public:
@@ -19,7 +19,7 @@
 
   // Creates a DRM device for |file|. |device_path| describes the location of
   // the DRM device.
-  virtual scoped_refptr<DriWrapper> CreateDevice(
+  virtual scoped_refptr<DrmDevice> CreateDevice(
       const base::FilePath& device_path,
       base::File file);
 
diff --git a/ui/ozone/platform/dri/drm_device_manager.cc b/ui/ozone/platform/dri/drm_device_manager.cc
index 5bbfd94e..d04aee0 100644
--- a/ui/ozone/platform/dri/drm_device_manager.cc
+++ b/ui/ozone/platform/dri/drm_device_manager.cc
@@ -4,12 +4,12 @@
 
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
 DrmDeviceManager::DrmDeviceManager(
-    const scoped_refptr<DriWrapper>& primary_device)
+    const scoped_refptr<DrmDevice>& primary_device)
     : primary_device_(primary_device) {
 }
 
@@ -17,9 +17,8 @@
   DCHECK(drm_device_map_.empty());
 }
 
-void DrmDeviceManager::UpdateDrmDevice(
-    gfx::AcceleratedWidget widget,
-    const scoped_refptr<DriWrapper>& device) {
+void DrmDeviceManager::UpdateDrmDevice(gfx::AcceleratedWidget widget,
+                                       const scoped_refptr<DrmDevice>& device) {
   base::AutoLock lock(lock_);
   drm_device_map_[widget] = device;
 }
@@ -31,7 +30,7 @@
     drm_device_map_.erase(it);
 }
 
-scoped_refptr<DriWrapper> DrmDeviceManager::GetDrmDevice(
+scoped_refptr<DrmDevice> DrmDeviceManager::GetDrmDevice(
     gfx::AcceleratedWidget widget) {
   base::AutoLock lock(lock_);
   if (widget == gfx::kNullAcceleratedWidget)
diff --git a/ui/ozone/platform/dri/drm_device_manager.h b/ui/ozone/platform/dri/drm_device_manager.h
index 03133abb..5a7431e 100644
--- a/ui/ozone/platform/dri/drm_device_manager.h
+++ b/ui/ozone/platform/dri/drm_device_manager.h
@@ -14,28 +14,28 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 // Tracks the mapping between widgets and the DRM devices used to allocate
 // buffers for the window represented by the widget.
 class OZONE_EXPORT DrmDeviceManager {
  public:
-  DrmDeviceManager(const scoped_refptr<DriWrapper>& primary_device);
+  DrmDeviceManager(const scoped_refptr<DrmDevice>& primary_device);
   ~DrmDeviceManager();
 
   // Updates the device associated with |widget|.
   void UpdateDrmDevice(gfx::AcceleratedWidget widget,
-                       const scoped_refptr<DriWrapper>& device);
+                       const scoped_refptr<DrmDevice>& device);
 
   // Removes the device associated with |widget|.
   void RemoveDrmDevice(gfx::AcceleratedWidget widget);
 
   // Returns the device associated with |widget|. If there is no association
   // returns |primary_device_|.
-  scoped_refptr<DriWrapper> GetDrmDevice(gfx::AcceleratedWidget widget);
+  scoped_refptr<DrmDevice> GetDrmDevice(gfx::AcceleratedWidget widget);
 
  private:
-  std::map<gfx::AcceleratedWidget, scoped_refptr<DriWrapper>> drm_device_map_;
+  std::map<gfx::AcceleratedWidget, scoped_refptr<DrmDevice>> drm_device_map_;
 
   // This device represents the primary graphics device and is used when:
   // 1) 'widget == kNullAcceleratedWidget' when the API requesting a buffer has
@@ -43,7 +43,7 @@
   // for video buffers), or
   // 2) in order to allocate buffers for unmatched surfaces (surfaces without a
   // display; ie: when in headless mode).
-  scoped_refptr<DriWrapper> primary_device_;
+  scoped_refptr<DrmDevice> primary_device_;
 
   // This class is accessed from the main thread and the IO thread. This lock
   // protects access to the device map.
diff --git a/ui/ozone/platform/dri/gbm.gypi b/ui/ozone/platform/dri/gbm.gypi
index f59833b61..19d3a0d2 100644
--- a/ui/ozone/platform/dri/gbm.gypi
+++ b/ui/ozone/platform/dri/gbm.gypi
@@ -37,14 +37,14 @@
         'gbm_buffer.h',
         'gbm_buffer_base.cc',
         'gbm_buffer_base.h',
+        'gbm_device.cc',
+        'gbm_device.h',
         'gbm_surface.cc',
         'gbm_surface.h',
         'gbm_surface_factory.cc',
         'gbm_surface_factory.h',
         'gbm_surfaceless.cc',
         'gbm_surfaceless.h',
-        'gbm_wrapper.cc',
-        'gbm_wrapper.h',
         'ozone_platform_gbm.cc',
         'ozone_platform_gbm.h',
       ],
diff --git a/ui/ozone/platform/dri/gbm_buffer.cc b/ui/ozone/platform/dri/gbm_buffer.cc
index 371e9ab..30f0ad85 100644
--- a/ui/ozone/platform/dri/gbm_buffer.cc
+++ b/ui/ozone/platform/dri/gbm_buffer.cc
@@ -11,7 +11,7 @@
 
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
-#include "ui/ozone/platform/dri/gbm_wrapper.h"
+#include "ui/ozone/platform/dri/gbm_device.h"
 
 namespace ui {
 
@@ -31,7 +31,7 @@
 
 }  // namespace
 
-GbmBuffer::GbmBuffer(const scoped_refptr<GbmWrapper>& gbm,
+GbmBuffer::GbmBuffer(const scoped_refptr<GbmDevice>& gbm,
                      gbm_bo* bo,
                      bool scanout)
     : GbmBufferBase(gbm, bo, scanout) {
@@ -44,7 +44,7 @@
 
 // static
 scoped_refptr<GbmBuffer> GbmBuffer::CreateBuffer(
-    const scoped_refptr<GbmWrapper>& gbm,
+    const scoped_refptr<GbmDevice>& gbm,
     SurfaceFactoryOzone::BufferFormat format,
     const gfx::Size& size,
     bool scanout) {
diff --git a/ui/ozone/platform/dri/gbm_buffer.h b/ui/ozone/platform/dri/gbm_buffer.h
index 2af83de..7e34068d1 100644
--- a/ui/ozone/platform/dri/gbm_buffer.h
+++ b/ui/ozone/platform/dri/gbm_buffer.h
@@ -16,18 +16,18 @@
 
 namespace ui {
 
-class GbmWrapper;
+class GbmDevice;
 
 class GbmBuffer : public GbmBufferBase {
  public:
   static scoped_refptr<GbmBuffer> CreateBuffer(
-      const scoped_refptr<GbmWrapper>& gbm,
+      const scoped_refptr<GbmDevice>& gbm,
       SurfaceFactoryOzone::BufferFormat format,
       const gfx::Size& size,
       bool scanout);
 
  private:
-  GbmBuffer(const scoped_refptr<GbmWrapper>& gbm, gbm_bo* bo, bool scanout);
+  GbmBuffer(const scoped_refptr<GbmDevice>& gbm, gbm_bo* bo, bool scanout);
   ~GbmBuffer() override;
 
   DISALLOW_COPY_AND_ASSIGN(GbmBuffer);
diff --git a/ui/ozone/platform/dri/gbm_buffer_base.cc b/ui/ozone/platform/dri/gbm_buffer_base.cc
index c4b69ff..ca835e3 100644
--- a/ui/ozone/platform/dri/gbm_buffer_base.cc
+++ b/ui/ozone/platform/dri/gbm_buffer_base.cc
@@ -7,7 +7,7 @@
 #include <gbm.h>
 
 #include "base/logging.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
@@ -21,23 +21,20 @@
 
 }  // namespace
 
-GbmBufferBase::GbmBufferBase(const scoped_refptr<DriWrapper>& dri,
+GbmBufferBase::GbmBufferBase(const scoped_refptr<DrmDevice>& drm,
                              gbm_bo* bo,
                              bool scanout)
-    : dri_(dri), bo_(bo), framebuffer_(0) {
-  if (scanout && !dri_->AddFramebuffer(gbm_bo_get_width(bo),
-                                       gbm_bo_get_height(bo),
-                                       kColorDepth,
-                                       kPixelDepth,
-                                       gbm_bo_get_stride(bo),
-                                       gbm_bo_get_handle(bo).u32,
-                                       &framebuffer_))
+    : drm_(drm), bo_(bo), framebuffer_(0) {
+  if (scanout &&
+      !drm_->AddFramebuffer(gbm_bo_get_width(bo), gbm_bo_get_height(bo),
+                            kColorDepth, kPixelDepth, gbm_bo_get_stride(bo),
+                            gbm_bo_get_handle(bo).u32, &framebuffer_))
     LOG(ERROR) << "Failed to register buffer";
 }
 
 GbmBufferBase::~GbmBufferBase() {
   if (framebuffer_)
-    dri_->RemoveFramebuffer(framebuffer_);
+    drm_->RemoveFramebuffer(framebuffer_);
 }
 
 uint32_t GbmBufferBase::GetFramebufferId() const {
diff --git a/ui/ozone/platform/dri/gbm_buffer_base.h b/ui/ozone/platform/dri/gbm_buffer_base.h
index 7f79f86..9152483 100644
--- a/ui/ozone/platform/dri/gbm_buffer_base.h
+++ b/ui/ozone/platform/dri/gbm_buffer_base.h
@@ -11,7 +11,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 // Wrapper for a GBM buffer. The base class provides common functionality
 // required to prepare the buffer for scanout. It does not provide any ownership
@@ -27,11 +27,11 @@
   gfx::Size GetSize() const override;
 
  protected:
-  GbmBufferBase(const scoped_refptr<DriWrapper>& dri, gbm_bo* bo, bool scanout);
+  GbmBufferBase(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo, bool scanout);
   ~GbmBufferBase() override;
 
  private:
-  scoped_refptr<DriWrapper> dri_;
+  scoped_refptr<DrmDevice> drm_;
   gbm_bo* bo_;
   uint32_t framebuffer_;
 
diff --git a/ui/ozone/platform/dri/gbm_device.cc b/ui/ozone/platform/dri/gbm_device.cc
new file mode 100644
index 0000000..e726c2f
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_device.cc
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/dri/gbm_device.h"
+
+#include <gbm.h>
+
+namespace ui {
+
+GbmDevice::GbmDevice(const base::FilePath& device_path)
+    : DrmDevice(device_path), device_(nullptr) {
+}
+
+GbmDevice::GbmDevice(const base::FilePath& device_path, base::File file)
+    : DrmDevice(device_path, file.Pass()), device_(nullptr) {
+}
+
+GbmDevice::~GbmDevice() {
+  if (device_)
+    gbm_device_destroy(device_);
+}
+
+bool GbmDevice::Initialize() {
+  if (!DrmDevice::Initialize())
+    return false;
+
+  device_ = gbm_create_device(get_fd());
+  if (!device_) {
+    LOG(ERROR) << "Unable to initialize GBM";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_device.h b/ui/ozone/platform/dri/gbm_device.h
new file mode 100644
index 0000000..da884e5
--- /dev/null
+++ b/ui/ozone/platform/dri/gbm_device.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_
+
+#include "ui/ozone/platform/dri/drm_device.h"
+
+struct gbm_device;
+
+namespace ui {
+
+class GbmDevice : public DrmDevice {
+ public:
+  GbmDevice(const base::FilePath& device_path);
+  GbmDevice(const base::FilePath& device_path, base::File file);
+  ~GbmDevice() override;
+
+  gbm_device* device() const { return device_; }
+
+  // DrmDevice implementation:
+  bool Initialize() override;
+
+ private:
+  gbm_device* device_;
+
+  DISALLOW_COPY_AND_ASSIGN(GbmDevice);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_DRI_GBM_DEVICE_H_
diff --git a/ui/ozone/platform/dri/gbm_surface.cc b/ui/ozone/platform/dri/gbm_surface.cc
index e3b6252..ab8e5e3 100644
--- a/ui/ozone/platform/dri/gbm_surface.cc
+++ b/ui/ozone/platform/dri/gbm_surface.cc
@@ -11,7 +11,7 @@
 #include "ui/ozone/platform/dri/dri_buffer.h"
 #include "ui/ozone/platform/dri/dri_window_delegate.h"
 #include "ui/ozone/platform/dri/gbm_buffer_base.h"
-#include "ui/ozone/platform/dri/gbm_wrapper.h"
+#include "ui/ozone/platform/dri/gbm_device.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 
@@ -22,12 +22,12 @@
 class GbmSurfaceBuffer : public GbmBufferBase {
  public:
   static scoped_refptr<GbmSurfaceBuffer> CreateBuffer(
-      const scoped_refptr<DriWrapper>& dri,
+      const scoped_refptr<DrmDevice>& drm,
       gbm_bo* buffer);
   static scoped_refptr<GbmSurfaceBuffer> GetBuffer(gbm_bo* buffer);
 
  private:
-  GbmSurfaceBuffer(const scoped_refptr<DriWrapper>& dri, gbm_bo* bo);
+  GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm, gbm_bo* bo);
   ~GbmSurfaceBuffer() override;
 
   static void Destroy(gbm_bo* buffer, void* data);
@@ -42,9 +42,9 @@
   DISALLOW_COPY_AND_ASSIGN(GbmSurfaceBuffer);
 };
 
-GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DriWrapper>& dri,
+GbmSurfaceBuffer::GbmSurfaceBuffer(const scoped_refptr<DrmDevice>& drm,
                                    gbm_bo* bo)
-    : GbmBufferBase(dri, bo, true) {
+    : GbmBufferBase(drm, bo, true) {
   if (GetFramebufferId()) {
     self_ = this;
     gbm_bo_set_user_data(bo, this, GbmSurfaceBuffer::Destroy);
@@ -55,10 +55,10 @@
 
 // static
 scoped_refptr<GbmSurfaceBuffer> GbmSurfaceBuffer::CreateBuffer(
-    const scoped_refptr<DriWrapper>& dri,
+    const scoped_refptr<DrmDevice>& drm,
     gbm_bo* buffer) {
-  scoped_refptr<GbmSurfaceBuffer> scoped_buffer(new GbmSurfaceBuffer(dri,
-                                                                     buffer));
+  scoped_refptr<GbmSurfaceBuffer> scoped_buffer(
+      new GbmSurfaceBuffer(drm, buffer));
   if (!scoped_buffer->GetFramebufferId())
     return NULL;
 
@@ -80,7 +80,7 @@
 }  // namespace
 
 GbmSurface::GbmSurface(DriWindowDelegate* window_delegate,
-                       const scoped_refptr<GbmWrapper>& gbm)
+                       const scoped_refptr<GbmDevice>& gbm)
     : GbmSurfaceless(window_delegate, NULL),
       gbm_(gbm),
       native_surface_(NULL),
diff --git a/ui/ozone/platform/dri/gbm_surface.h b/ui/ozone/platform/dri/gbm_surface.h
index e0e3c47..c549d9a 100644
--- a/ui/ozone/platform/dri/gbm_surface.h
+++ b/ui/ozone/platform/dri/gbm_surface.h
@@ -18,7 +18,7 @@
 
 class DriBuffer;
 class DriWindowDelegate;
-class GbmWrapper;
+class GbmDevice;
 
 // Extends the GBM surfaceless functionality and adds an implicit surface for
 // the primary plane. Arbitrary buffers can still be allocated and displayed as
@@ -27,7 +27,7 @@
 class GbmSurface : public GbmSurfaceless {
  public:
   GbmSurface(DriWindowDelegate* window_delegate,
-             const scoped_refptr<GbmWrapper>& gbm);
+             const scoped_refptr<GbmDevice>& gbm);
   ~GbmSurface() override;
 
   bool Initialize();
@@ -42,7 +42,7 @@
   void OnSwapBuffersCallback(const SwapCompletionCallback& callback,
                              gbm_bo* pending_buffer);
 
-  scoped_refptr<GbmWrapper> gbm_;
+  scoped_refptr<GbmDevice> gbm_;
 
   // The native GBM surface. In EGL this represents the EGLNativeWindowType.
   gbm_surface* native_surface_;
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.cc b/ui/ozone/platform/dri/gbm_surface_factory.cc
index 2017535..b9c8f9f 100644
--- a/ui/ozone/platform/dri/gbm_surface_factory.cc
+++ b/ui/ozone/platform/dri/gbm_surface_factory.cc
@@ -14,13 +14,14 @@
 #include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/gbm_buffer.h"
+#include "ui/ozone/platform/dri/gbm_device.h"
 #include "ui/ozone/platform/dri/gbm_surface.h"
 #include "ui/ozone/platform/dri/gbm_surfaceless.h"
-#include "ui/ozone/platform/dri/gbm_wrapper.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/public/native_pixmap.h"
 #include "ui/ozone/public/overlay_candidates_ozone.h"
 #include "ui/ozone/public/ozone_switches.h"
+#include "ui/ozone/public/surface_ozone_canvas.h"
 #include "ui/ozone/public/surface_ozone_egl.h"
 
 namespace ui {
@@ -92,7 +93,7 @@
 }
 
 int GbmSurfaceFactory::GetDrmFd() {
-  scoped_refptr<GbmWrapper> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget);
+  scoped_refptr<GbmDevice> gbm = GetGbmDevice(gfx::kNullAcceleratedWidget);
   DCHECK(gbm);
   return gbm->get_fd();
 }
@@ -119,9 +120,15 @@
   return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address);
 }
 
+scoped_ptr<SurfaceOzoneCanvas> GbmSurfaceFactory::CreateCanvasForWidget(
+    gfx::AcceleratedWidget widget) {
+  LOG(FATAL) << "Software rendering mode is not supported with GBM platform";
+  return nullptr;
+}
+
 scoped_ptr<SurfaceOzoneEGL> GbmSurfaceFactory::CreateEGLSurfaceForWidget(
     gfx::AcceleratedWidget widget) {
-  scoped_refptr<GbmWrapper> gbm = GetGbmDevice(widget);
+  scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget);
   DCHECK(gbm);
 
   scoped_ptr<GbmSurface> surface(
@@ -150,7 +157,7 @@
   if (usage == MAP)
     return nullptr;
 
-  scoped_refptr<GbmWrapper> gbm = GetGbmDevice(widget);
+  scoped_refptr<GbmDevice> gbm = GetGbmDevice(widget);
   DCHECK(gbm);
 
   scoped_refptr<GbmBuffer> buffer =
@@ -213,9 +220,9 @@
   return false;
 }
 
-scoped_refptr<GbmWrapper> GbmSurfaceFactory::GetGbmDevice(
+scoped_refptr<GbmDevice> GbmSurfaceFactory::GetGbmDevice(
     gfx::AcceleratedWidget widget) {
-  return static_cast<GbmWrapper*>(
+  return static_cast<GbmDevice*>(
       drm_device_manager_->GetDrmDevice(widget).get());
 }
 
diff --git a/ui/ozone/platform/dri/gbm_surface_factory.h b/ui/ozone/platform/dri/gbm_surface_factory.h
index 1b913c0..7b10b08 100644
--- a/ui/ozone/platform/dri/gbm_surface_factory.h
+++ b/ui/ozone/platform/dri/gbm_surface_factory.h
@@ -12,7 +12,7 @@
 class DriWindowDelegate;
 class DriWindowDelegateManager;
 class DrmDeviceManager;
-class GbmWrapper;
+class GbmDevice;
 
 class GbmSurfaceFactory : public DriSurfaceFactory {
  public:
@@ -29,6 +29,8 @@
   bool LoadEGLGLES2Bindings(
       AddGLLibraryCallback add_gl_library,
       SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+  scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+      gfx::AcceleratedWidget widget) override;
   scoped_ptr<ui::SurfaceOzoneEGL> CreateEGLSurfaceForWidget(
       gfx::AcceleratedWidget w) override;
   scoped_ptr<SurfaceOzoneEGL> CreateSurfacelessEGLSurfaceForWidget(
@@ -50,7 +52,7 @@
   bool CanCreateNativePixmap(BufferUsage usage) override;
 
  private:
-  scoped_refptr<GbmWrapper> GetGbmDevice(gfx::AcceleratedWidget widget);
+  scoped_refptr<GbmDevice> GetGbmDevice(gfx::AcceleratedWidget widget);
 
   bool allow_surfaceless_;
 
diff --git a/ui/ozone/platform/dri/gbm_surfaceless.cc b/ui/ozone/platform/dri/gbm_surfaceless.cc
index 6745a20..30e18e7 100644
--- a/ui/ozone/platform/dri/gbm_surfaceless.cc
+++ b/ui/ozone/platform/dri/gbm_surfaceless.cc
@@ -8,7 +8,7 @@
 #include "base/bind_helpers.h"
 #include "ui/ozone/platform/dri/dri_vsync_provider.h"
 #include "ui/ozone/platform/dri/dri_window_delegate.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/gbm_buffer.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
@@ -59,14 +59,14 @@
 bool GbmSurfaceless::IsUniversalDisplayLinkDevice() {
   if (!drm_device_manager_)
     return false;
-  scoped_refptr<DriWrapper> drm_primary =
+  scoped_refptr<DrmDevice> drm_primary =
       drm_device_manager_->GetDrmDevice(gfx::kNullAcceleratedWidget);
   DCHECK(drm_primary);
 
   HardwareDisplayController* controller = window_delegate_->GetController();
   if (!controller)
     return false;
-  scoped_refptr<DriWrapper> drm = controller->GetAllocationDriWrapper();
+  scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
   DCHECK(drm);
 
   return drm_primary != drm;
diff --git a/ui/ozone/platform/dri/gbm_wrapper.cc b/ui/ozone/platform/dri/gbm_wrapper.cc
deleted file mode 100644
index e0d1f17..0000000
--- a/ui/ozone/platform/dri/gbm_wrapper.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/dri/gbm_wrapper.h"
-
-#include <gbm.h>
-
-namespace ui {
-
-GbmWrapper::GbmWrapper(const base::FilePath& device_path)
-    : DriWrapper(device_path), device_(nullptr) {
-}
-
-GbmWrapper::GbmWrapper(const base::FilePath& device_path, base::File file)
-    : DriWrapper(device_path, file.Pass()), device_(nullptr) {
-}
-
-GbmWrapper::~GbmWrapper() {
-  if (device_)
-    gbm_device_destroy(device_);
-}
-
-bool GbmWrapper::Initialize() {
-  if (!DriWrapper::Initialize())
-    return false;
-
-  device_ = gbm_create_device(get_fd());
-  if (!device_) {
-    LOG(ERROR) << "Unable to initialize GBM";
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/dri/gbm_wrapper.h b/ui/ozone/platform/dri/gbm_wrapper.h
deleted file mode 100644
index 3df2550..0000000
--- a/ui/ozone/platform/dri/gbm_wrapper.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_
-#define UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_
-
-#include "ui/ozone/platform/dri/dri_wrapper.h"
-
-struct gbm_device;
-
-namespace ui {
-
-class GbmWrapper : public DriWrapper {
- public:
-  GbmWrapper(const base::FilePath& device_path);
-  GbmWrapper(const base::FilePath& device_path, base::File file);
-
-  gbm_device* device() const { return device_; }
-
-  // DriWrapper implementation:
-  bool Initialize() override;
-
- private:
-  ~GbmWrapper() override;
-
-  gbm_device* device_;
-
-  DISALLOW_COPY_AND_ASSIGN(GbmWrapper);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_DRI_GBM_WRAPPER_H_
diff --git a/ui/ozone/platform/dri/hardware_display_controller.cc b/ui/ozone/platform/dri/hardware_display_controller.cc
index faee6e6..0615067 100644
--- a/ui/ozone/platform/dri/hardware_display_controller.cc
+++ b/ui/ozone/platform/dri/hardware_display_controller.cc
@@ -17,7 +17,7 @@
 #include "ui/gfx/geometry/size.h"
 #include "ui/ozone/platform/dri/crtc_controller.h"
 #include "ui/ozone/platform/dri/dri_buffer.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/public/native_pixmap.h"
 
 namespace ui {
@@ -157,7 +157,7 @@
 }
 
 scoped_ptr<CrtcController> HardwareDisplayController::RemoveCrtc(
-    const scoped_refptr<DriWrapper>& drm,
+    const scoped_refptr<DrmDevice>& drm,
     uint32_t crtc) {
   for (ScopedVector<CrtcController>::iterator it = crtc_controllers_.begin();
        it != crtc_controllers_.end(); ++it) {
@@ -191,7 +191,7 @@
   return nullptr;
 }
 
-bool HardwareDisplayController::HasCrtc(const scoped_refptr<DriWrapper>& drm,
+bool HardwareDisplayController::HasCrtc(const scoped_refptr<DrmDevice>& drm,
                                         uint32_t crtc) const {
   for (size_t i = 0; i < crtc_controllers_.size(); ++i)
     if (crtc_controllers_[i]->drm() == drm &&
@@ -260,7 +260,7 @@
   }
 }
 
-scoped_refptr<DriWrapper> HardwareDisplayController::GetAllocationDriWrapper()
+scoped_refptr<DrmDevice> HardwareDisplayController::GetAllocationDrmDevice()
     const {
   DCHECK(!crtc_controllers_.empty());
   // TODO(dnicoara) When we support mirroring across DRM devices, figure out
diff --git a/ui/ozone/platform/dri/hardware_display_controller.h b/ui/ozone/platform/dri/hardware_display_controller.h
index 7f015a5..e32ba63 100644
--- a/ui/ozone/platform/dri/hardware_display_controller.h
+++ b/ui/ozone/platform/dri/hardware_display_controller.h
@@ -31,7 +31,7 @@
 
 class CrtcController;
 class ScanoutBuffer;
-class DriWrapper;
+class DrmDevice;
 
 // The HDCOz will handle modesettings and scannout operations for hardware
 // devices.
@@ -134,9 +134,9 @@
   bool MoveCursor(const gfx::Point& location);
 
   void AddCrtc(scoped_ptr<CrtcController> controller);
-  scoped_ptr<CrtcController> RemoveCrtc(const scoped_refptr<DriWrapper>& drm,
+  scoped_ptr<CrtcController> RemoveCrtc(const scoped_refptr<DrmDevice>& drm,
                                         uint32_t crtc);
-  bool HasCrtc(const scoped_refptr<DriWrapper>& drm, uint32_t crtc) const;
+  bool HasCrtc(const scoped_refptr<DrmDevice>& drm, uint32_t crtc) const;
   bool IsMirrored() const;
   bool IsDisabled() const;
   gfx::Size GetModeSize() const;
@@ -152,7 +152,7 @@
     return crtc_controllers_.get();
   }
 
-  scoped_refptr<DriWrapper> GetAllocationDriWrapper() const;
+  scoped_refptr<DrmDevice> GetAllocationDrmDevice() const;
 
  private:
   // Returns true if any of the CRTCs is waiting for a page flip.
@@ -185,7 +185,7 @@
   std::deque<PageFlipRequest> requests_;
   scoped_refptr<ScanoutBuffer> cursor_buffer_;
 
-  base::ScopedPtrHashMap<DriWrapper*, HardwareDisplayPlaneList>
+  base::ScopedPtrHashMap<DrmDevice*, HardwareDisplayPlaneList>
       owned_hardware_planes_;
 
   // Stores the CRTC configuration. This is used to identify monitors and
diff --git a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
index 6a20ac121..f63c136 100644
--- a/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
+++ b/ui/ozone/platform/dri/hardware_display_controller_unittest.cc
@@ -7,9 +7,9 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "ui/ozone/platform/dri/crtc_controller.h"
 #include "ui/ozone/platform/dri/dri_buffer.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
 #include "ui/ozone/public/native_pixmap.h"
 
 namespace {
@@ -58,7 +58,7 @@
 
  protected:
   scoped_ptr<ui::HardwareDisplayController> controller_;
-  scoped_refptr<ui::MockDriWrapper> drm_;
+  scoped_refptr<ui::MockDrmDevice> drm_;
 
   int page_flips_;
 
@@ -70,7 +70,7 @@
   std::vector<uint32_t> crtcs;
   crtcs.push_back(kPrimaryCrtc);
   crtcs.push_back(kSecondaryCrtc);
-  drm_ = new ui::MockDriWrapper(false, crtcs, kPlanesPerCrtc);
+  drm_ = new ui::MockDrmDevice(false, crtcs, kPlanesPerCrtc);
   controller_.reset(new ui::HardwareDisplayController(
       scoped_ptr<ui::CrtcController>(new ui::CrtcController(
           drm_.get(), kPrimaryCrtc, kPrimaryConnector))));
diff --git a/ui/ozone/platform/dri/hardware_display_plane.cc b/ui/ozone/platform/dri/hardware_display_plane.cc
index 89bc882..cb50c6c 100644
--- a/ui/ozone/platform/dri/hardware_display_plane.cc
+++ b/ui/ozone/platform/dri/hardware_display_plane.cc
@@ -10,7 +10,7 @@
 
 #include "base/logging.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
@@ -33,7 +33,7 @@
   return possible_crtcs_ & (1 << crtc_index);
 }
 
-bool HardwareDisplayPlane::Initialize(DriWrapper* drm) {
+bool HardwareDisplayPlane::Initialize(DrmDevice* drm) {
   return true;
 }
 
diff --git a/ui/ozone/platform/dri/hardware_display_plane.h b/ui/ozone/platform/dri/hardware_display_plane.h
index e8589317..2fffae4 100644
--- a/ui/ozone/platform/dri/hardware_display_plane.h
+++ b/ui/ozone/platform/dri/hardware_display_plane.h
@@ -18,7 +18,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 class OZONE_EXPORT HardwareDisplayPlane {
  public:
@@ -27,7 +27,7 @@
 
   virtual ~HardwareDisplayPlane();
 
-  bool Initialize(DriWrapper* drm);
+  bool Initialize(DrmDevice* drm);
 
   bool CanUseForCrtc(uint32_t crtc_index);
 
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.cc b/ui/ozone/platform/dri/hardware_display_plane_manager.cc
index 2a8b7cc..0c0b321c 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager.cc
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager.cc
@@ -11,7 +11,7 @@
 #include "base/logging.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/ozone/platform/dri/crtc_controller.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 #include "ui/ozone/public/ozone_switches.h"
@@ -65,7 +65,7 @@
 HardwareDisplayPlaneManager::~HardwareDisplayPlaneManager() {
 }
 
-bool HardwareDisplayPlaneManager::Initialize(DriWrapper* drm) {
+bool HardwareDisplayPlaneManager::Initialize(DrmDevice* drm) {
   drm_ = drm;
   ScopedDrmResourcesPtr resources(drmModeGetResources(drm->get_fd()));
   if (!resources) {
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager.h b/ui/ozone/platform/dri/hardware_display_plane_manager.h
index d25b7d5f..49593e0 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager.h
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager.h
@@ -23,7 +23,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 class CrtcController;
 
 // This contains the list of planes controlled by one HDC on a given DRM fd.
@@ -77,7 +77,7 @@
 
   // This parses information from the drm driver, adding any new planes
   // or crtcs found.
-  bool Initialize(DriWrapper* drm);
+  bool Initialize(DrmDevice* drm);
 
   // Assign hardware planes from the |planes_| list to |overlay_list| entries,
   // recording the plane IDs in the |plane_list|. Only planes compatible with
@@ -112,7 +112,7 @@
 
   // Object containing the connection to the graphics device and wraps the API
   // calls to control it. Not owned.
-  DriWrapper* drm_;
+  DrmDevice* drm_;
 
   ScopedVector<HardwareDisplayPlane> planes_;
   std::vector<uint32_t> crtcs_;
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc
index 3853ff5..b41f456 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager_legacy.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "ui/ozone/platform/dri/crtc_controller.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 
 namespace ui {
diff --git a/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc b/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc
index 7e5dade..5ee02543 100644
--- a/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc
+++ b/ui/ozone/platform/dri/hardware_display_plane_manager_unittest.cc
@@ -13,7 +13,7 @@
 #include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h"
 #include "ui/ozone/platform/dri/overlay_plane.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
 
 namespace {
 
@@ -232,8 +232,7 @@
 TEST(HardwareDisplayPlaneManagerLegacyTest, UnusedPlanesAreReleased) {
   std::vector<uint32_t> crtcs;
   crtcs.push_back(100);
-  scoped_refptr<ui::MockDriWrapper> drm =
-      new ui::MockDriWrapper(false, crtcs, 2);
+  scoped_refptr<ui::MockDrmDevice> drm = new ui::MockDrmDevice(false, crtcs, 2);
   ui::OverlayPlaneList assigns;
   scoped_refptr<FakeScanoutBuffer> fake_buffer = new FakeScanoutBuffer();
   assigns.push_back(ui::OverlayPlane(fake_buffer));
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.cc b/ui/ozone/platform/dri/native_display_delegate_dri.cc
index af18bb59..b6dedffda 100644
--- a/ui/ozone/platform/dri/native_display_delegate_dri.cc
+++ b/ui/ozone/platform/dri/native_display_delegate_dri.cc
@@ -15,7 +15,7 @@
 #include "ui/ozone/platform/dri/display_mode_dri.h"
 #include "ui/ozone/platform/dri/display_snapshot_dri.h"
 #include "ui/ozone/platform/dri/dri_util.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/drm_device_generator.h"
 #include "ui/ozone/platform/dri/screen_manager.h"
 #include "ui/ozone/public/ozone_switches.h"
@@ -61,7 +61,7 @@
         crtc_(snapshot->crtc()),
         connector_(snapshot->connector()) {}
 
-  DisplaySnapshotComparator(const scoped_refptr<DriWrapper>& drm,
+  DisplaySnapshotComparator(const scoped_refptr<DrmDevice>& drm,
                             uint32_t crtc,
                             uint32_t connector)
       : drm_(drm), crtc_(crtc), connector_(connector) {}
@@ -72,7 +72,7 @@
   }
 
  private:
-  scoped_refptr<DriWrapper> drm_;
+  scoped_refptr<DrmDevice> drm_;
   uint32_t crtc_;
   uint32_t connector_;
 };
@@ -81,7 +81,7 @@
  public:
   explicit FindByDevicePath(const base::FilePath& path) : path_(path) {}
 
-  bool operator()(const scoped_refptr<DriWrapper>& device) {
+  bool operator()(const scoped_refptr<DrmDevice>& device) {
     return device->device_path() == path_;
   }
 
@@ -93,7 +93,7 @@
 
 NativeDisplayDelegateDri::NativeDisplayDelegateDri(
     ScreenManager* screen_manager,
-    const scoped_refptr<DriWrapper>& primary_device,
+    const scoped_refptr<DrmDevice>& primary_device,
     scoped_ptr<DrmDeviceGenerator> drm_device_generator)
     : screen_manager_(screen_manager),
       drm_device_generator_(drm_device_generator.Pass()) {
@@ -213,7 +213,7 @@
     return;
   }
 
-  scoped_refptr<DriWrapper> device =
+  scoped_refptr<DrmDevice> device =
       drm_device_generator_->CreateDevice(path, file.Pass());
   if (!device) {
     VLOG(2) << "Could not initialize DRM device for '" << path.value() << "'";
diff --git a/ui/ozone/platform/dri/native_display_delegate_dri.h b/ui/ozone/platform/dri/native_display_delegate_dri.h
index 88d1cb6..55c554c 100644
--- a/ui/ozone/platform/dri/native_display_delegate_dri.h
+++ b/ui/ozone/platform/dri/native_display_delegate_dri.h
@@ -22,14 +22,14 @@
 class DisplaySnapshotDri;
 class DisplayMode;
 class DisplayModeDri;
-class DriWrapper;
+class DrmDevice;
 class DrmDeviceGenerator;
 class ScreenManager;
 
 class NativeDisplayDelegateDri {
  public:
   NativeDisplayDelegateDri(ScreenManager* screen_manager,
-                           const scoped_refptr<DriWrapper>& primary_device,
+                           const scoped_refptr<DrmDevice>& primary_device,
                            scoped_ptr<DrmDeviceGenerator> device_generator);
   ~NativeDisplayDelegateDri();
 
@@ -77,7 +77,7 @@
   ScreenManager* screen_manager_;  // Not owned.
   scoped_ptr<DrmDeviceGenerator> drm_device_generator_;
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-  std::vector<scoped_refptr<DriWrapper>> devices_;
+  std::vector<scoped_refptr<DrmDevice>> devices_;
   // Modes can be shared between different displays, so we need to keep track
   // of them independently for cleanup.
   ScopedVector<const DisplayMode> cached_modes_;
diff --git a/ui/ozone/platform/dri/ozone_platform_dri.cc b/ui/ozone/platform/dri/ozone_platform_dri.cc
index 8dd7838..71552d4c 100644
--- a/ui/ozone/platform/dri/ozone_platform_dri.cc
+++ b/ui/ozone/platform/dri/ozone_platform_dri.cc
@@ -22,7 +22,7 @@
 #include "ui/ozone/platform/dri/dri_window_delegate_impl.h"
 #include "ui/ozone/platform/dri/dri_window_delegate_manager.h"
 #include "ui/ozone/platform/dri/dri_window_manager.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/drm_device_generator.h"
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/native_display_delegate_dri.h"
@@ -49,7 +49,7 @@
 class OzonePlatformDri : public OzonePlatform {
  public:
   OzonePlatformDri()
-      : dri_(new DriWrapper(GetPrimaryDisplayCardPath())),
+      : drm_(new DrmDevice(GetPrimaryDisplayCardPath())),
         buffer_generator_(new DriBufferGenerator()),
         screen_manager_(new ScreenManager(buffer_generator_.get())),
         device_manager_(CreateDeviceManager()),
@@ -88,21 +88,21 @@
   scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
     return make_scoped_ptr(new NativeDisplayDelegateProxy(
         gpu_platform_support_host_.get(), device_manager_.get(),
-        display_manager_.get(), dri_->device_path()));
+        display_manager_.get(), drm_->device_path()));
   }
   void InitializeUI() override {
-    if (!dri_->Initialize())
+    if (!drm_->Initialize())
       LOG(FATAL) << "Failed to initialize primary DRM device";
 
     // This makes sure that simple targets that do not handle display
     // configuration can still use the primary display.
-    ForceInitializationOfPrimaryDisplay(dri_, screen_manager_.get());
-    drm_device_manager_.reset(new DrmDeviceManager(dri_));
+    ForceInitializationOfPrimaryDisplay(drm_, screen_manager_.get());
+    drm_device_manager_.reset(new DrmDeviceManager(drm_));
     display_manager_.reset(new DisplayManager());
     surface_factory_ozone_.reset(
         new DriSurfaceFactory(&window_delegate_manager_));
     scoped_ptr<NativeDisplayDelegateDri> ndd(new NativeDisplayDelegateDri(
-        screen_manager_.get(), dri_,
+        screen_manager_.get(), drm_,
         scoped_ptr<DrmDeviceGenerator>(new DrmDeviceGenerator())));
     gpu_platform_support_.reset(new DriGpuPlatformSupport(
         drm_device_manager_.get(), &window_delegate_manager_,
@@ -132,7 +132,7 @@
   void InitializeGPU() override {}
 
  private:
-  scoped_refptr<DriWrapper> dri_;
+  scoped_refptr<DrmDevice> drm_;
   scoped_ptr<DrmDeviceManager> drm_device_manager_;
   scoped_ptr<DriBufferGenerator> buffer_generator_;
   scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/dri/ozone_platform_gbm.cc b/ui/ozone/platform/dri/ozone_platform_gbm.cc
index 7c237df..15d5466 100644
--- a/ui/ozone/platform/dri/ozone_platform_gbm.cc
+++ b/ui/ozone/platform/dri/ozone_platform_gbm.cc
@@ -26,9 +26,9 @@
 #include "ui/ozone/platform/dri/drm_device_generator.h"
 #include "ui/ozone/platform/dri/drm_device_manager.h"
 #include "ui/ozone/platform/dri/gbm_buffer.h"
+#include "ui/ozone/platform/dri/gbm_device.h"
 #include "ui/ozone/platform/dri/gbm_surface.h"
 #include "ui/ozone/platform/dri/gbm_surface_factory.h"
-#include "ui/ozone/platform/dri/gbm_wrapper.h"
 #include "ui/ozone/platform/dri/native_display_delegate_dri.h"
 #include "ui/ozone/platform/dri/native_display_delegate_proxy.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
@@ -76,9 +76,9 @@
   ~GbmBufferGenerator() override {}
 
   // ScanoutBufferGenerator:
-  scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DriWrapper>& drm,
+  scoped_refptr<ScanoutBuffer> Create(const scoped_refptr<DrmDevice>& drm,
                                       const gfx::Size& size) override {
-    scoped_refptr<GbmWrapper> gbm(static_cast<GbmWrapper*>(drm.get()));
+    scoped_refptr<GbmDevice> gbm(static_cast<GbmDevice*>(drm.get()));
     return GbmBuffer::CreateBuffer(gbm, SurfaceFactoryOzone::RGBA_8888, size,
                                    true);
   }
@@ -93,9 +93,9 @@
   ~GbmDeviceGenerator() override {}
 
   // DrmDeviceGenerator:
-  scoped_refptr<DriWrapper> CreateDevice(const base::FilePath& path,
-                                         base::File file) override {
-    scoped_refptr<DriWrapper> drm = new GbmWrapper(path, file.Pass());
+  scoped_refptr<DrmDevice> CreateDevice(const base::FilePath& path,
+                                        base::File file) override {
+    scoped_refptr<DrmDevice> drm = new GbmDevice(path, file.Pass());
     if (drm->Initialize())
       return drm;
 
@@ -175,7 +175,7 @@
   void InitializeGPU() override {
     gl_api_loader_.reset(new GlApiLoader());
     // Async page flips are supported only on surfaceless mode.
-    gbm_ = new GbmWrapper(GetPrimaryDisplayCardPath());
+    gbm_ = new GbmDevice(GetPrimaryDisplayCardPath());
     if (!gbm_->Initialize())
       LOG(FATAL) << "Failed to initialize primary DRM device";
 
@@ -204,7 +204,7 @@
   bool use_surfaceless_;
   base::FilePath primary_graphics_card_path_;
   scoped_ptr<GlApiLoader> gl_api_loader_;
-  scoped_refptr<GbmWrapper> gbm_;
+  scoped_refptr<GbmDevice> gbm_;
   scoped_ptr<DrmDeviceManager> drm_device_manager_;
   scoped_ptr<GbmBufferGenerator> buffer_generator_;
   scoped_ptr<ScreenManager> screen_manager_;
diff --git a/ui/ozone/platform/dri/scanout_buffer.h b/ui/ozone/platform/dri/scanout_buffer.h
index cf653322..bfe1990a 100644
--- a/ui/ozone/platform/dri/scanout_buffer.h
+++ b/ui/ozone/platform/dri/scanout_buffer.h
@@ -12,7 +12,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 
 // Abstraction for a DRM buffer that can be scanned-out of.
 class ScanoutBuffer : public base::RefCountedThreadSafe<ScanoutBuffer> {
@@ -37,7 +37,7 @@
   virtual ~ScanoutBufferGenerator() {}
 
   virtual scoped_refptr<ScanoutBuffer> Create(
-      const scoped_refptr<DriWrapper>& drm,
+      const scoped_refptr<DrmDevice>& drm,
       const gfx::Size& size) = 0;
 };
 
diff --git a/ui/ozone/platform/dri/screen_manager.cc b/ui/ozone/platform/dri/screen_manager.cc
index fbf2edef..a2b0ee8 100644
--- a/ui/ozone/platform/dri/screen_manager.cc
+++ b/ui/ozone/platform/dri/screen_manager.cc
@@ -13,7 +13,7 @@
 #include "ui/ozone/platform/dri/crtc_controller.h"
 #include "ui/ozone/platform/dri/dri_console_buffer.h"
 #include "ui/ozone/platform/dri/dri_util.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/platform/dri/scanout_buffer.h"
 
@@ -23,10 +23,10 @@
 
 // Copies the contents of the saved framebuffer from the CRTCs in |controller|
 // to the new modeset buffer |buffer|.
-void FillModesetBuffer(const scoped_refptr<DriWrapper>& dri,
+void FillModesetBuffer(const scoped_refptr<DrmDevice>& drm,
                        HardwareDisplayController* controller,
                        ScanoutBuffer* buffer) {
-  DriConsoleBuffer modeset_buffer(dri, buffer->GetFramebufferId());
+  DriConsoleBuffer modeset_buffer(drm, buffer->GetFramebufferId());
   if (!modeset_buffer.Initialize()) {
     LOG(ERROR) << "Failed to grab framebuffer " << buffer->GetFramebufferId();
     return;
@@ -40,7 +40,7 @@
 
   // If the display controller is in mirror mode, the CRTCs should be sharing
   // the same framebuffer.
-  DriConsoleBuffer saved_buffer(dri, crtcs[0]->saved_crtc()->buffer_id);
+  DriConsoleBuffer saved_buffer(drm, crtcs[0]->saved_crtc()->buffer_id);
   if (!saved_buffer.Initialize()) {
     LOG(ERROR) << "Failed to grab saved framebuffer "
                << crtcs[0]->saved_crtc()->buffer_id;
@@ -69,10 +69,10 @@
 ScreenManager::~ScreenManager() {
 }
 
-void ScreenManager::AddDisplayController(const scoped_refptr<DriWrapper>& dri,
+void ScreenManager::AddDisplayController(const scoped_refptr<DrmDevice>& drm,
                                          uint32_t crtc,
                                          uint32_t connector) {
-  HardwareDisplayControllers::iterator it = FindDisplayController(dri, crtc);
+  HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
   // TODO(dnicoara): Turn this into a DCHECK when async display configuration is
   // properly supported. (When there can't be a race between forcing initial
   // display configuration in ScreenManager and NativeDisplayDelegate creating
@@ -83,12 +83,11 @@
   }
 
   controllers_.push_back(new HardwareDisplayController(
-      scoped_ptr<CrtcController>(new CrtcController(dri, crtc, connector))));
+      scoped_ptr<CrtcController>(new CrtcController(drm, crtc, connector))));
 }
 
-void ScreenManager::RemoveDisplayController(
-    const scoped_refptr<DriWrapper>& drm,
-    uint32_t crtc) {
+void ScreenManager::RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
+                                            uint32_t crtc) {
   HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
   if (it != controllers_.end()) {
     bool is_mirrored = (*it)->IsMirrored();
@@ -102,7 +101,7 @@
 }
 
 bool ScreenManager::ConfigureDisplayController(
-    const scoped_refptr<DriWrapper>& drm,
+    const scoped_refptr<DrmDevice>& drm,
     uint32_t crtc,
     uint32_t connector,
     const gfx::Point& origin,
@@ -156,7 +155,7 @@
 }
 
 bool ScreenManager::DisableDisplayController(
-    const scoped_refptr<DriWrapper>& drm,
+    const scoped_refptr<DrmDevice>& drm,
     uint32_t crtc) {
   HardwareDisplayControllers::iterator it = FindDisplayController(drm, crtc);
   if (it != controllers_.end()) {
@@ -193,7 +192,7 @@
 }
 
 ScreenManager::HardwareDisplayControllers::iterator
-ScreenManager::FindDisplayController(const scoped_refptr<DriWrapper>& drm,
+ScreenManager::FindDisplayController(const scoped_refptr<DrmDevice>& drm,
                                      uint32_t crtc) {
   for (HardwareDisplayControllers::iterator it = controllers_.begin();
        it != controllers_.end();
@@ -223,7 +222,7 @@
     const gfx::Point& origin,
     const drmModeModeInfo& mode) {
   DCHECK(!controller->crtc_controllers().empty());
-  scoped_refptr<DriWrapper> drm = controller->GetAllocationDriWrapper();
+  scoped_refptr<DrmDevice> drm = controller->GetAllocationDrmDevice();
   controller->set_origin(origin);
 
   // Create a surface suitable for the current controller.
@@ -250,7 +249,7 @@
 bool ScreenManager::HandleMirrorMode(
     HardwareDisplayControllers::iterator original,
     HardwareDisplayControllers::iterator mirror,
-    const scoped_refptr<DriWrapper>& drm,
+    const scoped_refptr<DrmDevice>& drm,
     uint32_t crtc,
     uint32_t connector) {
   (*mirror)->AddCrtc((*original)->RemoveCrtc(drm, crtc));
diff --git a/ui/ozone/platform/dri/screen_manager.h b/ui/ozone/platform/dri/screen_manager.h
index 5eaaa46..bf8fed9 100644
--- a/ui/ozone/platform/dri/screen_manager.h
+++ b/ui/ozone/platform/dri/screen_manager.h
@@ -22,7 +22,7 @@
 
 namespace ui {
 
-class DriWrapper;
+class DrmDevice;
 class ScanoutBufferGenerator;
 
 // Responsible for keeping track of active displays and configuring them.
@@ -33,18 +33,18 @@
 
   // Register a display controller. This must be called before trying to
   // configure it.
-  void AddDisplayController(const scoped_refptr<DriWrapper>& dri,
+  void AddDisplayController(const scoped_refptr<DrmDevice>& drm,
                             uint32_t crtc,
                             uint32_t connector);
 
   // Remove a display controller from the list of active controllers. The
   // controller is removed since it was disconnected.
-  void RemoveDisplayController(const scoped_refptr<DriWrapper>& dri,
+  void RemoveDisplayController(const scoped_refptr<DrmDevice>& drm,
                                uint32_t crtc);
 
   // Configure a display controller. The display controller is identified by
   // (|crtc|, |connector|) and the controller is modeset using |mode|.
-  bool ConfigureDisplayController(const scoped_refptr<DriWrapper>& dri,
+  bool ConfigureDisplayController(const scoped_refptr<DrmDevice>& drm,
                                   uint32_t crtc,
                                   uint32_t connector,
                                   const gfx::Point& origin,
@@ -52,7 +52,7 @@
 
   // Disable the display controller identified by |crtc|. Note, the controller
   // may still be connected, so this does not remove the controller.
-  bool DisableDisplayController(const scoped_refptr<DriWrapper>& dri,
+  bool DisableDisplayController(const scoped_refptr<DrmDevice>& drm,
                                 uint32_t crtc);
 
   // Returns a reference to the display controller configured to display within
@@ -69,7 +69,7 @@
   // Returns an iterator into |controllers_| for the controller identified by
   // (|crtc|, |connector|).
   HardwareDisplayControllers::iterator FindDisplayController(
-      const scoped_refptr<DriWrapper>& drm,
+      const scoped_refptr<DrmDevice>& drm,
       uint32_t crtc);
 
   // Returns an iterator into |controllers_| for the controller located at
@@ -87,7 +87,7 @@
   // controller is currently present.
   bool HandleMirrorMode(HardwareDisplayControllers::iterator original,
                         HardwareDisplayControllers::iterator mirror,
-                        const scoped_refptr<DriWrapper>& drm,
+                        const scoped_refptr<DrmDevice>& drm,
                         uint32_t crtc,
                         uint32_t connector);
 
diff --git a/ui/ozone/platform/dri/screen_manager_unittest.cc b/ui/ozone/platform/dri/screen_manager_unittest.cc
index 1501b71..58e08d1 100644
--- a/ui/ozone/platform/dri/screen_manager_unittest.cc
+++ b/ui/ozone/platform/dri/screen_manager_unittest.cc
@@ -7,7 +7,7 @@
 #include "ui/ozone/platform/dri/dri_buffer.h"
 #include "ui/ozone/platform/dri/hardware_display_controller.h"
 #include "ui/ozone/platform/dri/screen_manager.h"
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
 
 namespace {
 
@@ -64,7 +64,7 @@
   }
 
   void SetUp() override {
-    dri_ = new ui::MockDriWrapper();
+    drm_ = new ui::MockDrmDevice();
     buffer_generator_.reset(new ui::DriBufferGenerator());
     screen_manager_.reset(new ui::ScreenManager(buffer_generator_.get()));
     screen_manager_->AddObserver(&observer_);
@@ -72,11 +72,11 @@
   void TearDown() override {
     screen_manager_->RemoveObserver(&observer_);
     screen_manager_.reset();
-    dri_ = nullptr;
+    drm_ = nullptr;
   }
 
  protected:
-  scoped_refptr<ui::MockDriWrapper> dri_;
+  scoped_refptr<ui::MockDrmDevice> drm_;
   scoped_ptr<ui::DriBufferGenerator> buffer_generator_;
   scoped_ptr<ui::ScreenManager> screen_manager_;
 
@@ -91,21 +91,21 @@
 }
 
 TEST_F(ScreenManagerTest, CheckWithValidController) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   ui::HardwareDisplayController* controller =
       screen_manager_->GetDisplayController(GetPrimaryBounds());
 
   EXPECT_TRUE(controller);
-  EXPECT_TRUE(controller->HasCrtc(dri_, kPrimaryCrtc));
+  EXPECT_TRUE(controller->HasCrtc(drm_, kPrimaryCrtc));
 }
 
 TEST_F(ScreenManagerTest, CheckWithInvalidBounds) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
@@ -113,14 +113,14 @@
 }
 
 TEST_F(ScreenManagerTest, CheckForSecondValidController) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
       kDefaultMode);
 
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
@@ -128,33 +128,33 @@
 }
 
 TEST_F(ScreenManagerTest, CheckControllerAfterItIsRemoved) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   EXPECT_EQ(1, observer_.num_displays_changed());
   EXPECT_EQ(0, observer_.num_displays_removed());
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
 
-  screen_manager_->RemoveDisplayController(dri_, kPrimaryCrtc);
+  screen_manager_->RemoveDisplayController(drm_, kPrimaryCrtc);
   EXPECT_EQ(1, observer_.num_displays_changed());
   EXPECT_EQ(1, observer_.num_displays_removed());
   EXPECT_FALSE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
 }
 
 TEST_F(ScreenManagerTest, CheckDuplicateConfiguration) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  uint32_t framebuffer = dri_->current_framebuffer();
+  uint32_t framebuffer = drm_->current_framebuffer();
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   // Should reuse existing framebuffer.
-  EXPECT_EQ(framebuffer, dri_->current_framebuffer());
+  EXPECT_EQ(framebuffer, drm_->current_framebuffer());
 
   EXPECT_EQ(2, observer_.num_displays_changed());
   EXPECT_EQ(0, observer_.num_displays_removed());
@@ -164,14 +164,14 @@
 }
 
 TEST_F(ScreenManagerTest, CheckChangingMode) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   drmModeModeInfo new_mode = kDefaultMode;
   new_mode.vdisplay = 10;
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       new_mode);
 
   EXPECT_EQ(2, observer_.num_displays_changed());
@@ -187,14 +187,14 @@
 }
 
 TEST_F(ScreenManagerTest, CheckForControllersInMirroredMode) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   EXPECT_EQ(2, observer_.num_displays_changed());
@@ -204,55 +204,55 @@
 }
 
 TEST_F(ScreenManagerTest, CheckMirrorModeTransitions) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
       kDefaultMode);
 
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
   EXPECT_FALSE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
       kDefaultMode);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetPrimaryBounds()));
   EXPECT_TRUE(screen_manager_->GetDisplayController(GetSecondaryBounds()));
 }
 
 TEST_F(ScreenManagerTest, MonitorGoneInMirrorMode) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   EXPECT_EQ(2, observer_.num_displays_changed());
   EXPECT_EQ(1, observer_.num_displays_removed());
 
-  screen_manager_->RemoveDisplayController(dri_, kSecondaryCrtc);
+  screen_manager_->RemoveDisplayController(drm_, kSecondaryCrtc);
   EXPECT_TRUE(screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode));
   EXPECT_EQ(3, observer_.num_displays_changed());
   EXPECT_EQ(1, observer_.num_displays_removed());
@@ -262,23 +262,23 @@
 }
 
 TEST_F(ScreenManagerTest, DoNotEnterMirrorModeUnlessSameBounds) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
 
   // Configure displays in extended mode.
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetSecondaryBounds().origin(),
       kDefaultMode);
 
   drmModeModeInfo new_mode = kDefaultMode;
   new_mode.vdisplay = 10;
   // Shouldn't enter mirror mode unless the display bounds are the same.
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       new_mode);
 
   EXPECT_FALSE(
@@ -286,34 +286,34 @@
 }
 
 TEST_F(ScreenManagerTest, ReuseFramebufferIfDisabledThenReEnabled) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  uint32_t framebuffer = dri_->current_framebuffer();
+  uint32_t framebuffer = drm_->current_framebuffer();
 
-  screen_manager_->DisableDisplayController(dri_, kPrimaryCrtc);
-  EXPECT_EQ(0u, dri_->current_framebuffer());
+  screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
+  EXPECT_EQ(0u, drm_->current_framebuffer());
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   // Should reuse existing framebuffer.
-  EXPECT_EQ(framebuffer, dri_->current_framebuffer());
+  EXPECT_EQ(framebuffer, drm_->current_framebuffer());
 }
 
 TEST_F(ScreenManagerTest, CheckMirrorModeAfterBeginReEnabled) {
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
-  screen_manager_->DisableDisplayController(dri_, kPrimaryCrtc);
+  screen_manager_->DisableDisplayController(drm_, kPrimaryCrtc);
 
-  screen_manager_->AddDisplayController(dri_, kSecondaryCrtc,
+  screen_manager_->AddDisplayController(drm_, kSecondaryCrtc,
                                         kSecondaryConnector);
   screen_manager_->ConfigureDisplayController(
-      dri_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
+      drm_, kSecondaryCrtc, kSecondaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
 
   ui::HardwareDisplayController* controller =
@@ -322,7 +322,7 @@
   EXPECT_FALSE(controller->IsMirrored());
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   EXPECT_TRUE(controller);
   EXPECT_TRUE(controller->IsMirrored());
@@ -330,16 +330,16 @@
 
 TEST_F(ScreenManagerTest,
        CheckProperConfigurationWithDifferentDeviceAndSameCrtc) {
-  scoped_refptr<ui::MockDriWrapper> dri2 = new ui::MockDriWrapper();
+  scoped_refptr<ui::MockDrmDevice> drm2 = new ui::MockDrmDevice();
 
-  screen_manager_->AddDisplayController(dri_, kPrimaryCrtc, kPrimaryConnector);
-  screen_manager_->AddDisplayController(dri2, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm_, kPrimaryCrtc, kPrimaryConnector);
+  screen_manager_->AddDisplayController(drm2, kPrimaryCrtc, kPrimaryConnector);
 
   screen_manager_->ConfigureDisplayController(
-      dri_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
+      drm_, kPrimaryCrtc, kPrimaryConnector, GetPrimaryBounds().origin(),
       kDefaultMode);
   screen_manager_->ConfigureDisplayController(
-      dri2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
+      drm2, kPrimaryCrtc, kPrimaryConnector, GetSecondaryBounds().origin(),
       kDefaultMode);
 
   ui::HardwareDisplayController* controller1 =
@@ -348,6 +348,6 @@
       screen_manager_->GetDisplayController(GetSecondaryBounds());
 
   EXPECT_NE(controller1, controller2);
-  EXPECT_EQ(dri_, controller1->crtc_controllers()[0]->drm());
-  EXPECT_EQ(dri2, controller2->crtc_controllers()[0]->drm());
+  EXPECT_EQ(drm_, controller1->crtc_controllers()[0]->drm());
+  EXPECT_EQ(drm2, controller2->crtc_controllers()[0]->drm());
 }
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.cc b/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
deleted file mode 100644
index 4c33e01..0000000
--- a/ui/ozone/platform/dri/test/mock_dri_wrapper.cc
+++ /dev/null
@@ -1,224 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/ozone/platform/dri/test/mock_dri_wrapper.h"
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h"
-
-namespace ui {
-
-namespace {
-
-template<class Object> Object* DrmAllocator() {
-  return static_cast<Object*>(drmMalloc(sizeof(Object)));
-}
-
-class MockHardwareDisplayPlaneManager
-    : public HardwareDisplayPlaneManagerLegacy {
- public:
-  MockHardwareDisplayPlaneManager(DriWrapper* drm,
-                                  std::vector<uint32_t> crtcs,
-                                  size_t planes_per_crtc) {
-    const int kPlaneBaseId = 50;
-    drm_ = drm;
-    crtcs_.swap(crtcs);
-    for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) {
-      for (size_t i = 0; i < planes_per_crtc; i++) {
-        planes_.push_back(
-            new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx));
-      }
-    }
-  }
-};
-
-}  // namespace
-
-MockDriWrapper::MockDriWrapper()
-    : DriWrapper(base::FilePath(), base::File()),
-      get_crtc_call_count_(0),
-      set_crtc_call_count_(0),
-      restore_crtc_call_count_(0),
-      add_framebuffer_call_count_(0),
-      remove_framebuffer_call_count_(0),
-      page_flip_call_count_(0),
-      overlay_flip_call_count_(0),
-      set_crtc_expectation_(true),
-      add_framebuffer_expectation_(true),
-      page_flip_expectation_(true),
-      create_dumb_buffer_expectation_(true),
-      current_framebuffer_(0) {
-  plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
-}
-
-MockDriWrapper::MockDriWrapper(bool use_sync_flips,
-                               std::vector<uint32_t> crtcs,
-                               size_t planes_per_crtc)
-    : DriWrapper(base::FilePath(), base::File()),
-      get_crtc_call_count_(0),
-      set_crtc_call_count_(0),
-      restore_crtc_call_count_(0),
-      add_framebuffer_call_count_(0),
-      remove_framebuffer_call_count_(0),
-      page_flip_call_count_(0),
-      overlay_flip_call_count_(0),
-      overlay_clear_call_count_(0),
-      set_crtc_expectation_(true),
-      add_framebuffer_expectation_(true),
-      page_flip_expectation_(true),
-      create_dumb_buffer_expectation_(true),
-      use_sync_flips_(use_sync_flips),
-      current_framebuffer_(0) {
-  plane_manager_.reset(
-      new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc));
-}
-
-MockDriWrapper::~MockDriWrapper() {
-}
-
-ScopedDrmCrtcPtr MockDriWrapper::GetCrtc(uint32_t crtc_id) {
-  get_crtc_call_count_++;
-  return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>());
-}
-
-bool MockDriWrapper::SetCrtc(uint32_t crtc_id,
-                             uint32_t framebuffer,
-                             std::vector<uint32_t> connectors,
-                             drmModeModeInfo* mode) {
-  current_framebuffer_ = framebuffer;
-  set_crtc_call_count_++;
-  return set_crtc_expectation_;
-}
-
-bool MockDriWrapper::SetCrtc(drmModeCrtc* crtc,
-                             std::vector<uint32_t> connectors) {
-  restore_crtc_call_count_++;
-  return true;
-}
-
-bool MockDriWrapper::DisableCrtc(uint32_t crtc_id) {
-  current_framebuffer_ = 0;
-  return true;
-}
-
-ScopedDrmConnectorPtr MockDriWrapper::GetConnector(uint32_t connector_id) {
-  return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>());
-}
-
-bool MockDriWrapper::AddFramebuffer(uint32_t width,
-                                    uint32_t height,
-                                    uint8_t depth,
-                                    uint8_t bpp,
-                                    uint32_t stride,
-                                    uint32_t handle,
-                                    uint32_t* framebuffer) {
-  add_framebuffer_call_count_++;
-  *framebuffer = add_framebuffer_call_count_;
-  return add_framebuffer_expectation_;
-}
-
-bool MockDriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
-  remove_framebuffer_call_count_++;
-  return true;
-}
-
-ScopedDrmFramebufferPtr MockDriWrapper::GetFramebuffer(uint32_t framebuffer) {
-  return ScopedDrmFramebufferPtr();
-}
-
-bool MockDriWrapper::PageFlip(uint32_t crtc_id,
-                              uint32_t framebuffer,
-                              bool is_sync,
-                              const PageFlipCallback& callback) {
-  page_flip_call_count_++;
-  current_framebuffer_ = framebuffer;
-  if (page_flip_expectation_) {
-    if (use_sync_flips_)
-      callback.Run(0, 0, 0);
-    else
-      callbacks_.push(callback);
-  }
-
-  return page_flip_expectation_;
-}
-
-bool MockDriWrapper::PageFlipOverlay(uint32_t crtc_id,
-                                     uint32_t framebuffer,
-                                     const gfx::Rect& location,
-                                     const gfx::Rect& source,
-                                     int overlay_plane) {
-  if (!framebuffer)
-    overlay_clear_call_count_++;
-  overlay_flip_call_count_++;
-  return true;
-}
-
-ScopedDrmPropertyPtr MockDriWrapper::GetProperty(drmModeConnector* connector,
-                                                 const char* name) {
-  return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
-}
-
-bool MockDriWrapper::SetProperty(uint32_t connector_id,
-                                 uint32_t property_id,
-                                 uint64_t value) {
-  return true;
-}
-
-bool MockDriWrapper::GetCapability(uint64_t capability, uint64_t* value) {
-  return true;
-}
-
-ScopedDrmPropertyBlobPtr MockDriWrapper::GetPropertyBlob(
-    drmModeConnector* connector,
-    const char* name) {
-  return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>());
-}
-
-bool MockDriWrapper::SetCursor(uint32_t crtc_id,
-                               uint32_t handle,
-                               const gfx::Size& size) {
-  return true;
-}
-
-bool MockDriWrapper::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
-  return true;
-}
-
-bool MockDriWrapper::CreateDumbBuffer(const SkImageInfo& info,
-                                      uint32_t* handle,
-                                      uint32_t* stride,
-                                      void** pixels) {
-  if (!create_dumb_buffer_expectation_)
-    return false;
-
-  *handle = 0;
-  *stride = info.minRowBytes();
-  *pixels = new char[info.getSafeSize(*stride)];
-  buffers_.push_back(
-      skia::AdoptRef(SkSurface::NewRasterDirect(info, *pixels, *stride)));
-  buffers_.back()->getCanvas()->clear(SK_ColorBLACK);
-
-  return true;
-}
-
-void MockDriWrapper::DestroyDumbBuffer(const SkImageInfo& info,
-                                       uint32_t handle,
-                                       uint32_t stride,
-                                       void* pixels) {
-  delete[] static_cast<char*>(pixels);
-}
-
-void MockDriWrapper::RunCallbacks() {
-  while (!callbacks_.empty()) {
-    PageFlipCallback callback = callbacks_.front();
-    callbacks_.pop();
-    callback.Run(0, 0, 0);
-  }
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/dri/test/mock_drm_device.cc b/ui/ozone/platform/dri/test/mock_drm_device.cc
new file mode 100644
index 0000000..460ecbb
--- /dev/null
+++ b/ui/ozone/platform/dri/test/mock_drm_device.cc
@@ -0,0 +1,225 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/ozone/platform/dri/test/mock_drm_device.h"
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "ui/ozone/platform/dri/hardware_display_plane_manager_legacy.h"
+
+namespace ui {
+
+namespace {
+
+template <class Object>
+Object* DrmAllocator() {
+  return static_cast<Object*>(drmMalloc(sizeof(Object)));
+}
+
+class MockHardwareDisplayPlaneManager
+    : public HardwareDisplayPlaneManagerLegacy {
+ public:
+  MockHardwareDisplayPlaneManager(DrmDevice* drm,
+                                  std::vector<uint32_t> crtcs,
+                                  size_t planes_per_crtc) {
+    const int kPlaneBaseId = 50;
+    drm_ = drm;
+    crtcs_.swap(crtcs);
+    for (size_t crtc_idx = 0; crtc_idx < crtcs_.size(); crtc_idx++) {
+      for (size_t i = 0; i < planes_per_crtc; i++) {
+        planes_.push_back(
+            new HardwareDisplayPlane(kPlaneBaseId + i, 1 << crtc_idx));
+      }
+    }
+  }
+};
+
+}  // namespace
+
+MockDrmDevice::MockDrmDevice()
+    : DrmDevice(base::FilePath(), base::File()),
+      get_crtc_call_count_(0),
+      set_crtc_call_count_(0),
+      restore_crtc_call_count_(0),
+      add_framebuffer_call_count_(0),
+      remove_framebuffer_call_count_(0),
+      page_flip_call_count_(0),
+      overlay_flip_call_count_(0),
+      set_crtc_expectation_(true),
+      add_framebuffer_expectation_(true),
+      page_flip_expectation_(true),
+      create_dumb_buffer_expectation_(true),
+      current_framebuffer_(0) {
+  plane_manager_.reset(new HardwareDisplayPlaneManagerLegacy());
+}
+
+MockDrmDevice::MockDrmDevice(bool use_sync_flips,
+                             std::vector<uint32_t> crtcs,
+                             size_t planes_per_crtc)
+    : DrmDevice(base::FilePath(), base::File()),
+      get_crtc_call_count_(0),
+      set_crtc_call_count_(0),
+      restore_crtc_call_count_(0),
+      add_framebuffer_call_count_(0),
+      remove_framebuffer_call_count_(0),
+      page_flip_call_count_(0),
+      overlay_flip_call_count_(0),
+      overlay_clear_call_count_(0),
+      set_crtc_expectation_(true),
+      add_framebuffer_expectation_(true),
+      page_flip_expectation_(true),
+      create_dumb_buffer_expectation_(true),
+      use_sync_flips_(use_sync_flips),
+      current_framebuffer_(0) {
+  plane_manager_.reset(
+      new MockHardwareDisplayPlaneManager(this, crtcs, planes_per_crtc));
+}
+
+MockDrmDevice::~MockDrmDevice() {
+}
+
+ScopedDrmCrtcPtr MockDrmDevice::GetCrtc(uint32_t crtc_id) {
+  get_crtc_call_count_++;
+  return ScopedDrmCrtcPtr(DrmAllocator<drmModeCrtc>());
+}
+
+bool MockDrmDevice::SetCrtc(uint32_t crtc_id,
+                            uint32_t framebuffer,
+                            std::vector<uint32_t> connectors,
+                            drmModeModeInfo* mode) {
+  current_framebuffer_ = framebuffer;
+  set_crtc_call_count_++;
+  return set_crtc_expectation_;
+}
+
+bool MockDrmDevice::SetCrtc(drmModeCrtc* crtc,
+                            std::vector<uint32_t> connectors) {
+  restore_crtc_call_count_++;
+  return true;
+}
+
+bool MockDrmDevice::DisableCrtc(uint32_t crtc_id) {
+  current_framebuffer_ = 0;
+  return true;
+}
+
+ScopedDrmConnectorPtr MockDrmDevice::GetConnector(uint32_t connector_id) {
+  return ScopedDrmConnectorPtr(DrmAllocator<drmModeConnector>());
+}
+
+bool MockDrmDevice::AddFramebuffer(uint32_t width,
+                                   uint32_t height,
+                                   uint8_t depth,
+                                   uint8_t bpp,
+                                   uint32_t stride,
+                                   uint32_t handle,
+                                   uint32_t* framebuffer) {
+  add_framebuffer_call_count_++;
+  *framebuffer = add_framebuffer_call_count_;
+  return add_framebuffer_expectation_;
+}
+
+bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
+  remove_framebuffer_call_count_++;
+  return true;
+}
+
+ScopedDrmFramebufferPtr MockDrmDevice::GetFramebuffer(uint32_t framebuffer) {
+  return ScopedDrmFramebufferPtr();
+}
+
+bool MockDrmDevice::PageFlip(uint32_t crtc_id,
+                             uint32_t framebuffer,
+                             bool is_sync,
+                             const PageFlipCallback& callback) {
+  page_flip_call_count_++;
+  current_framebuffer_ = framebuffer;
+  if (page_flip_expectation_) {
+    if (use_sync_flips_)
+      callback.Run(0, 0, 0);
+    else
+      callbacks_.push(callback);
+  }
+
+  return page_flip_expectation_;
+}
+
+bool MockDrmDevice::PageFlipOverlay(uint32_t crtc_id,
+                                    uint32_t framebuffer,
+                                    const gfx::Rect& location,
+                                    const gfx::Rect& source,
+                                    int overlay_plane) {
+  if (!framebuffer)
+    overlay_clear_call_count_++;
+  overlay_flip_call_count_++;
+  return true;
+}
+
+ScopedDrmPropertyPtr MockDrmDevice::GetProperty(drmModeConnector* connector,
+                                                const char* name) {
+  return ScopedDrmPropertyPtr(DrmAllocator<drmModePropertyRes>());
+}
+
+bool MockDrmDevice::SetProperty(uint32_t connector_id,
+                                uint32_t property_id,
+                                uint64_t value) {
+  return true;
+}
+
+bool MockDrmDevice::GetCapability(uint64_t capability, uint64_t* value) {
+  return true;
+}
+
+ScopedDrmPropertyBlobPtr MockDrmDevice::GetPropertyBlob(
+    drmModeConnector* connector,
+    const char* name) {
+  return ScopedDrmPropertyBlobPtr(DrmAllocator<drmModePropertyBlobRes>());
+}
+
+bool MockDrmDevice::SetCursor(uint32_t crtc_id,
+                              uint32_t handle,
+                              const gfx::Size& size) {
+  return true;
+}
+
+bool MockDrmDevice::MoveCursor(uint32_t crtc_id, const gfx::Point& point) {
+  return true;
+}
+
+bool MockDrmDevice::CreateDumbBuffer(const SkImageInfo& info,
+                                     uint32_t* handle,
+                                     uint32_t* stride,
+                                     void** pixels) {
+  if (!create_dumb_buffer_expectation_)
+    return false;
+
+  *handle = 0;
+  *stride = info.minRowBytes();
+  *pixels = new char[info.getSafeSize(*stride)];
+  buffers_.push_back(
+      skia::AdoptRef(SkSurface::NewRasterDirect(info, *pixels, *stride)));
+  buffers_.back()->getCanvas()->clear(SK_ColorBLACK);
+
+  return true;
+}
+
+void MockDrmDevice::DestroyDumbBuffer(const SkImageInfo& info,
+                                      uint32_t handle,
+                                      uint32_t stride,
+                                      void* pixels) {
+  delete[] static_cast<char*>(pixels);
+}
+
+void MockDrmDevice::RunCallbacks() {
+  while (!callbacks_.empty()) {
+    PageFlipCallback callback = callbacks_.front();
+    callbacks_.pop();
+    callback.Run(0, 0, 0);
+  }
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/dri/test/mock_dri_wrapper.h b/ui/ozone/platform/dri/test/mock_drm_device.h
similarity index 85%
rename from ui/ozone/platform/dri/test/mock_dri_wrapper.h
rename to ui/ozone/platform/dri/test/mock_drm_device.h
index 87253d8..d3268e1 100644
--- a/ui/ozone/platform/dri/test/mock_dri_wrapper.h
+++ b/ui/ozone/platform/dri/test/mock_drm_device.h
@@ -2,27 +2,27 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
-#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
+#ifndef UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_
+#define UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_
 
 #include <queue>
 #include <vector>
 
 #include "skia/ext/refptr.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "ui/ozone/platform/dri/dri_wrapper.h"
+#include "ui/ozone/platform/dri/drm_device.h"
 
 namespace ui {
 
 class CrtcController;
 
-// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
-class MockDriWrapper : public ui::DriWrapper {
+// The real DrmDevice makes actual DRM calls which we can't use in unit tests.
+class MockDrmDevice : public ui::DrmDevice {
  public:
-  MockDriWrapper();
-  MockDriWrapper(bool use_sync_flips,
-                 std::vector<uint32_t> crtcs,
-                 size_t planes_per_crtc);
+  MockDrmDevice();
+  MockDrmDevice(bool use_sync_flips,
+                std::vector<uint32_t> crtcs,
+                size_t planes_per_crtc);
 
   int get_get_crtc_call_count() const { return get_crtc_call_count_; }
   int get_set_crtc_call_count() const { return set_crtc_call_count_; }
@@ -47,13 +47,13 @@
 
   uint32_t current_framebuffer() const { return current_framebuffer_; }
 
-  const std::vector<skia::RefPtr<SkSurface> > buffers() const {
+  const std::vector<skia::RefPtr<SkSurface>> buffers() const {
     return buffers_;
   }
 
   void RunCallbacks();
 
-  // DriWrapper:
+  // DrmDevice:
   ScopedDrmCrtcPtr GetCrtc(uint32_t crtc_id) override;
   bool SetCrtc(uint32_t crtc_id,
                uint32_t framebuffer,
@@ -102,7 +102,7 @@
                          void* pixels) override;
 
  private:
-  ~MockDriWrapper() override;
+  ~MockDrmDevice() override;
 
   int get_crtc_call_count_;
   int set_crtc_call_count_;
@@ -122,13 +122,13 @@
 
   uint32_t current_framebuffer_;
 
-  std::vector<skia::RefPtr<SkSurface> > buffers_;
+  std::vector<skia::RefPtr<SkSurface>> buffers_;
 
   std::queue<PageFlipCallback> callbacks_;
 
-  DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
+  DISALLOW_COPY_AND_ASSIGN(MockDrmDevice);
 };
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRI_WRAPPER_H_
+#endif  // UI_OZONE_PLATFORM_DRI_TEST_MOCK_DRM_DEVICE_H_
diff --git a/ui/snapshot/BUILD.gn b/ui/snapshot/BUILD.gn
index b93fc6f..a9e5b0b 100644
--- a/ui/snapshot/BUILD.gn
+++ b/ui/snapshot/BUILD.gn
@@ -56,37 +56,35 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("snapshot_unittests") {
-    sources = [
-      "snapshot_aura_unittest.cc",
-      "snapshot_mac_unittest.mm",
-      "test/run_all_unittests.cc",
-    ]
+test("snapshot_unittests") {
+  sources = [
+    "snapshot_aura_unittest.cc",
+    "snapshot_mac_unittest.mm",
+    "test/run_all_unittests.cc",
+  ]
 
-    deps = [
-      ":snapshot",
-      "//base",
-      "//base/allocator",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/base",
+  deps = [
+    ":snapshot",
+    "//base",
+    "//base/allocator",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/base",
+    "//ui/compositor:test_support",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+  ]
+
+  if (use_aura) {
+    deps += [
+      "//ui/aura:test_support",
+      "//ui/compositor",
       "//ui/compositor:test_support",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
+      "//ui/wm",
     ]
-
-    if (use_aura) {
-      deps += [
-        "//ui/aura:test_support",
-        "//ui/compositor",
-        "//ui/compositor:test_support",
-        "//ui/wm",
-      ]
-    } else {
-      sources -= [ "snapshot_aura_unittest.cc" ]
-    }
+  } else {
+    sources -= [ "snapshot_aura_unittest.cc" ]
   }
 }
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 2d9e813..922ce0c 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -162,104 +162,102 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("views_unittests") {
-    sources = gypi_values.views_unittests_sources
+test("views_unittests") {
+  sources = gypi_values.views_unittests_sources
 
-    deps = [
-      ":test_support",
-      "//base",
-      "//base:i18n",
-      "//base/allocator",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//third_party/icu",
-      "//ui/accessibility",
-      "//ui/aura",
-      "//ui/base",
-      "//ui/base/ime",
-      "//ui/base:test_support",
-      "//ui/compositor:test_support",
-      "//ui/events:test_support",
-      "//ui/events:events_base",
-      "//ui/events/platform",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-      "//ui/resources",
-      "//ui/strings",
-      "//ui/wm",
-      "//url",
+  deps = [
+    ":test_support",
+    "//base",
+    "//base:i18n",
+    "//base/allocator",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//third_party/icu",
+    "//ui/accessibility",
+    "//ui/aura",
+    "//ui/base",
+    "//ui/base/ime",
+    "//ui/base:test_support",
+    "//ui/compositor:test_support",
+    "//ui/events:test_support",
+    "//ui/events:events_base",
+    "//ui/events/platform",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+    "//ui/resources",
+    "//ui/strings",
+    "//ui/wm",
+    "//url",
+  ]
+
+  if (is_win) {
+    deps += [
+      "//third_party/iaccessible2",
+      "//third_party/wtl",
+    ]
+    libs = [
+      "imm32.lib",
+      "oleacc.lib",
+      "comctl32.lib",
     ]
 
-    if (is_win) {
-      deps += [
-        "//third_party/iaccessible2",
-        "//third_party/wtl",
-      ]
-      libs = [
-        "imm32.lib",
-        "oleacc.lib",
-        "comctl32.lib",
-      ]
+    # TOOD(GYP)
+    #'msvs_settings': {
+    #  'VCManifestTool': {
+    #    'AdditionalManifestFiles': [
+    #      '$(ProjectDir)\\test\\views_unittest.manifest',
+    #    ],
+    #  },
+    #},
+  }
 
-      # TOOD(GYP)
-      #'msvs_settings': {
-      #  'VCManifestTool': {
-      #    'AdditionalManifestFiles': [
-      #      '$(ProjectDir)\\test\\views_unittest.manifest',
-      #    ],
-      #  },
-      #},
-    }
+  if (use_x11) {
+    configs += [
+      "//build/config/linux:x11",
+      "//build/config/linux:xext",
+    ]
+    deps += [
+      "//ui/events/devices",
+      "//ui/events/platform/x11",
+      "//ui/gfx/x",
+    ]
+  }
 
-    if (use_x11) {
-      configs += [
-        "//build/config/linux:x11",
-        "//build/config/linux:xext",
-      ]
-      deps += [
-        "//ui/events/devices",
-        "//ui/events/platform/x11",
-        "//ui/gfx/x",
-      ]
-    }
-
-    if (use_aura) {
-      sources += gypi_values.views_unittests_aura_sources
-      deps += [ "//ui/aura:test_support" ]
-      if (!is_chromeos) {
-        sources += gypi_values.views_unittests_desktop_aura_sources
-        if (use_x11) {
-          sources += gypi_values.views_unittests_desktop_aurax11_sources
-        }
+  if (use_aura) {
+    sources += gypi_values.views_unittests_aura_sources
+    deps += [ "//ui/aura:test_support" ]
+    if (!is_chromeos) {
+      sources += gypi_values.views_unittests_desktop_aura_sources
+      if (use_x11) {
+        sources += gypi_values.views_unittests_desktop_aurax11_sources
       }
     }
-    if (!is_chromeos) {
-      sources += gypi_values.views_unittests_desktop_sources
-    }
-    if (use_x11) {
-      deps += [
-        "//ui/events/platform/x11",
-        "//ui/gfx/x",
-      ]
-    }
+  }
+  if (!is_chromeos) {
+    sources += gypi_values.views_unittests_desktop_sources
+  }
+  if (use_x11) {
+    deps += [
+      "//ui/events/platform/x11",
+      "//ui/gfx/x",
+    ]
+  }
 
-    if (is_mac) {
-      # views_unittests not yet compiling on Mac. http://crbug.com/378134
-      sources -= [
-        "bubble/bubble_window_targeter_unittest.cc",
-        "controls/button/custom_button_unittest.cc",
-        "controls/button/menu_button_unittest.cc",
-        "controls/menu/menu_controller_unittest.cc",
-        "controls/native/native_view_host_unittest.cc",
-        "focus/focus_manager_unittest.cc",
-        "ime/input_method_bridge_unittest.cc",
-        "widget/widget_unittest.cc",
-        "widget/window_reorderer_unittest.cc",
-      ]
-    }
+  if (is_mac) {
+    # views_unittests not yet compiling on Mac. http://crbug.com/378134
+    sources -= [
+      "bubble/bubble_window_targeter_unittest.cc",
+      "controls/button/custom_button_unittest.cc",
+      "controls/button/menu_button_unittest.cc",
+      "controls/menu/menu_controller_unittest.cc",
+      "controls/native/native_view_host_unittest.cc",
+      "focus/focus_manager_unittest.cc",
+      "ime/input_method_bridge_unittest.cc",
+      "widget/widget_unittest.cc",
+      "widget/window_reorderer_unittest.cc",
+    ]
   }
 }
 
diff --git a/ui/views/examples/BUILD.gn b/ui/views/examples/BUILD.gn
index 455b06c..b908eb1 100644
--- a/ui/views/examples/BUILD.gn
+++ b/ui/views/examples/BUILD.gn
@@ -88,35 +88,33 @@
   }
 }
 
-if (!is_win || link_chrome_on_windows) {
-  executable("views_examples_exe") {
-    testonly = true
+executable("views_examples_exe") {
+  testonly = true
 
-    sources = [
-      "examples_main.cc",
-    ]
+  sources = [
+    "examples_main.cc",
+  ]
 
-    deps = [
-      ":views_examples_lib",
-      "//base",
-      "//base:i18n",
-      "//ui/base",
-      "//ui/compositor",
-      "//ui/compositor:test_support",
-      "//ui/gfx",
-      "//ui/gl",
-      "//ui/resources:ui_test_pak",
-      "//ui/views",
-      "//ui/views:test_support",
-      "//ui/wm",
-    ]
+  deps = [
+    ":views_examples_lib",
+    "//base",
+    "//base:i18n",
+    "//ui/base",
+    "//ui/compositor",
+    "//ui/compositor:test_support",
+    "//ui/gfx",
+    "//ui/gl",
+    "//ui/resources:ui_test_pak",
+    "//ui/views",
+    "//ui/views:test_support",
+    "//ui/wm",
+  ]
 
-    if (use_aura) {
-      deps += [ "//ui/aura" ]
-    }
-    if (use_x11) {
-      deps += [ "//ui/gfx/x" ]
-    }
+  if (use_aura) {
+    deps += [ "//ui/aura" ]
+  }
+  if (use_x11) {
+    deps += [ "//ui/gfx/x" ]
   }
 }
 
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.css b/ui/webui/resources/cr_elements/cr_input/cr_input.css
new file mode 100644
index 0000000..204e397
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input.css
@@ -0,0 +1,7 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+:host {
+  display: inline-block;
+}
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.html b/ui/webui/resources/cr_elements/cr_input/cr_input.html
new file mode 100644
index 0000000..e0eddc3d
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input.html
@@ -0,0 +1,23 @@
+<link rel="import" href="chrome://resources/polymer/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/paper-input/paper-input-decorator.html">
+<link rel="import" href="chrome://resources/polymer/core-input/core-input.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_events/cr_events.html">
+
+<polymer-element name="cr-input">
+  <template>
+    <link rel="stylesheet" href="cr_input.css">
+    <cr-events id="events"></cr-events>
+
+    <!-- TODO(jlklein): Use 'autoValidate' instead of isInvalid binding when
+         updated to 0.5.4. -->
+    <paper-input-decorator id="decorator" label="{{label}}"
+        floatingLabel="{{floatingLabel}}" value="{{value}}"
+        disabled?="{{disabled}}" error="{{error}}"
+        isInvalid="{{!$.input.validity.valid}}">
+      <input is="core-input" id="input" value="{{value}}"
+          committedValue="{{committedValue}}" disabled?="{{disabled}}"
+          required?="{{required}}" type="{{type}}">
+    </paper-input-decorator>
+  </template>
+  <script src="cr_input.js"></script>
+</polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input.js b/ui/webui/resources/cr_elements/cr_input/cr_input.js
new file mode 100644
index 0000000..3f8f253
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input.js
@@ -0,0 +1,128 @@
+/* Copyright 2015 The Chromium Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file. */
+
+/**
+ * @fileoverview
+ * 'cr-input' is a single-line text field for user input. It is a convenience
+ * element composed of a 'paper-input-decorator' and a 'input is="core-input"'.
+ *
+ * Example:
+ *
+ *    <cr-input></cr-input>
+ *
+ * @group Chrome Elements
+ * @element cr-input
+ */
+Polymer('cr-input', {
+  publish: {
+    /**
+     * The label for this input. It normally appears as grey text inside
+     * the text input and disappears once the user enters text.
+     *
+     * @attribute label
+     * @type string
+     * @default ''
+     */
+    label: '',
+
+    /**
+     * If true, the label will "float" above the text input once the
+     * user enters text instead of disappearing.
+     *
+     * @attribute floatingLabel
+     * @type boolean
+     * @default true
+     */
+    floatingLabel: true,
+
+    /**
+     * Set to true to style the element as disabled.
+     *
+     * @attribute disabled
+     * @type boolean
+     * @default false
+     */
+    disabled: {value: false, reflect: true},
+
+    /**
+     * Set to true to mark the input as required.
+     *
+     * @attribute required
+     * @type boolean
+     * @default false
+     */
+    required: {value: false, reflect: true},
+
+    /**
+     * The current value of the input.
+     *
+     * @attribute value
+     * @type string
+     * @default ''
+     */
+    value: '',
+
+    /**
+     * The validation pattern for the input.
+     *
+     * @attribute pattern
+     * @type string
+     * @default ''
+     */
+    pattern: '',
+
+    /**
+     * The type of the input (password, date, etc.).
+     *
+     * @attribute type
+     * @type string
+     * @default 'text'
+     */
+    type: 'text',
+
+    /**
+     * The message to display if the input value fails validation. If this
+     * is unset or the empty string, a default message is displayed depending
+     * on the type of validation error.
+     *
+     * @attribute error
+     * @type string
+     * @default ''
+     */
+    error: '',
+
+    /**
+     * The most recently committed value of the input.
+     *
+     * @attribute committedValue
+     * @type string
+     * @default ''
+     */
+    committedValue: ''
+  },
+
+  /**
+   * Focuses the 'input' element.
+   */
+  focus: function() {
+    this.$.input.focus();
+  },
+
+  valueChanged: function() {
+    this.$.decorator.updateLabelVisibility(this.value);
+  },
+
+  patternChanged: function() {
+    if (this.pattern)
+      this.$.input.pattern = this.pattern;
+    else
+      this.$.input.removeAttribute('pattern');
+  },
+
+  /** @override */
+  ready: function() {
+    this.$.events.forward(this.$.input, ['change']);
+    this.patternChanged();
+  },
+});
diff --git a/ui/webui/resources/cr_elements/cr_input/demo.html b/ui/webui/resources/cr_elements/cr_input/demo.html
new file mode 100644
index 0000000..0934e48
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_input/demo.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<head>
+  <link href="cr_input.html" rel="import">
+</head>
+<body unresolved>
+  <cr-input label="Blah"></cr-input>
+  <cr-input label="This is required" required error="Put something here!">
+  </cr-input>
+  <cr-input label="Only numbers" pattern="^[0-9]*$"
+      error="Only numbers allowed!"></cr-input>
+  <cr-input label="Password" type="password"></cr-input>
+</body>
+</html>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png
new file mode 100644
index 0000000..cfe578b
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_3g.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png
new file mode 100644
index 0000000..0729051
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_4g.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png
new file mode 100644
index 0000000..1620182
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_edge.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png
new file mode 100644
index 0000000..7742ace
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_evdo.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png
new file mode 100644
index 0000000..b6690aa
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_gsm.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png
new file mode 100644
index 0000000..c1760fe
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png
new file mode 100644
index 0000000..ff2ac509
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_hspa_plus.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png
new file mode 100644
index 0000000..16d3157
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png
new file mode 100644
index 0000000..d97c035d
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_lte_advanced.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png
new file mode 100644
index 0000000..7036c55
--- /dev/null
+++ b/ui/webui/resources/cr_elements/cr_network_icon/badge_roaming.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/secure.png b/ui/webui/resources/cr_elements/cr_network_icon/badge_secure.png
similarity index 100%
rename from ui/webui/resources/cr_elements/cr_network_icon/secure.png
rename to ui/webui/resources/cr_elements/cr_network_icon/badge_secure.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
index 3406bcc..1ba4729 100644
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
+++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.css
@@ -4,8 +4,10 @@
 
 :host {
   display: inline-block;
+  height: 50px;
   overflow: hidden;
   position: relative;
+  width: 50px;
 }
 
 #icon {
@@ -38,10 +40,39 @@
   top: -400%;
 }
 
+/* Connecting animation */
+
+#icon.connecting {
+  -webkit-animation: levels 1s infinite;
+  -webkit-animation-timing-function: steps(4, start);
+}
+
+@-webkit-keyframes levels {
+  from {
+    top: 0%;
+  }
+  to {
+    top: -400%;
+  }
+}
+
+/* Badges. */
+/* Note: These use left/right because we do not reverse the badges for RTL. */
+
+/* Upper-left corner */
+#technology {
+  height: 40%;
+  left: 0px;
+  position: absolute;
+  top: 0px;
+}
+
+/* Lower-right corner */
+#roaming,
 #secure {
   height: 40%;
-  margin-left: 60%;
-  margin-top: 60%;
+  left: 60%;
   position: absolute;
+  top: 60%;
   width: 40%;
 }
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
index a8a53fb2..4762f6c 100644
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
+++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.html
@@ -3,9 +3,15 @@
 <polymer-element name="cr-network-icon">
   <template>
     <link rel="stylesheet" href="cr_network_icon.css">
-    <img id="icon">
+    <img id="icon" src="{{iconType | toImageSrc}}">
+    <img id="technology" src="{{technology | toBadgeImageSrc}}"
+        hidden?="{{!technology}}">
+    <img id="roaming"
+        src="chrome://resources/cr_elements/cr_network_icon/badge_roaming.png"
+        hidden?="{{!roaming}}">
     <img id="secure"
-        src="chrome://resources/cr_elements/cr_network_icon/secure.png">
+        src="chrome://resources/cr_elements/cr_network_icon/badge_secure.png"
+        hidden?="{{!secure}}">
   </template>
   <script src="cr_network_icon.js"></script>
 </polymer-element>
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
index 4f6c4d5f..c70079e 100644
--- a/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
+++ b/ui/webui/resources/cr_elements/cr_network_icon/cr_network_icon.js
@@ -10,10 +10,8 @@
 (function() {
 /**
  * @typedef {{
+ *   showBadges: boolean,
  *   showDisconnected: boolean,
- *   iconType: string,
- *   connected: boolean,
- *   secure: boolean,
  *   strength: number
  * }}
  */
@@ -51,6 +49,30 @@
  * @element cr-network-icon
  */
 Polymer('cr-network-icon', {
+  /**
+   * The icon type to use for the base image of the icon.
+   * @type string
+   */
+  iconType: 'ethernet',
+
+  /**
+   * Set to true to show a badge for roaming networks.
+   * @type boolean
+   */
+  roaming: false,
+
+  /**
+   * Set to true to show a badge for secure networks.
+   * @type boolean
+   */
+  secure: false,
+
+  /**
+   * Set to the name of a technology to show show a badge.
+   * @type string
+   */
+  technology: '',
+
   publish: {
     /**
      * If set, the ONC data properties will be used to display the icon.
@@ -85,9 +107,7 @@
   /** @override */
   attached: function() {
     var params = /** @type {IconParams} */ {
-      connected: false,
-      iconType: 'ethernet',
-      secure: false,
+      showBadges: false,
       showDisconnected: true,
       strength: 0,
     };
@@ -99,12 +119,9 @@
    * network state.
    */
   networkStateChanged: function() {
-    var iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
+    this.iconType = getIconTypeFromNetworkType(this.networkState.data.Type);
     var params = /** @type {IconParams} */ {
-      connected: this.networkState.data.ConnectionState == 'Connected',
-      iconType: iconType,
-      secure: iconType == 'wifi' &&
-          this.networkState.getWiFiSecurity() != 'None',
+      showBadges: true,
       showDisconnected: !this.isListItem,
       strength: this.networkState.getStrength(),
     };
@@ -116,10 +133,9 @@
    * of network, showing a disconnected icon where appropriate and no badges.
    */
   networkTypeChanged: function() {
+    this.iconType = getIconTypeFromNetworkType(this.networkType);
     var params = /** @type {IconParams} */ {
-      connected: false,
-      iconType: getIconTypeFromNetworkType(this.networkType),
-      secure: false,
+      showBadges: false,
       showDisconnected: true,
       strength: 0,
     };
@@ -127,32 +143,126 @@
   },
 
   /**
+   * Returns the url for an image based on identifier |id|.
+   * @param {string} src The identifier describing the image.
+   * @return {string} The url to use for the image 'src' property.
+   */
+  toImageSrc: function(id) {
+    return id ? RESOURCE_IMAGE_BASE + id + RESOURCE_IMAGE_EXT : '';
+  },
+
+  /**
+   * Returns the url for a badge image based on identifier |id|.
+   * @param {string} id The identifier describing the badge.
+   * @return {string} The url to use for the badge image 'src' property.
+   */
+  toBadgeImageSrc: function(id) {
+    return id ? this.toImageSrc('badge_' + id) : '';
+  },
+
+  /**
    * Sets the icon and badge based on the current state and |strength|.
    * @param {!IconParams} params The set of params describing the icon.
    * @private
    */
   setIcon_: function(params) {
     var icon = this.$.icon;
-    if (params.iconType)
-      icon.src = RESOURCE_IMAGE_BASE + params.iconType + RESOURCE_IMAGE_EXT;
 
-    var multiLevel, strength;
-    if (params.iconType == 'wifi' || params.iconType == 'mobile') {
-      multiLevel = true;
-      strength = (params.showDisconnected && !params.connected) ?
-          -1 : params.strength;
+    var multiLevel = (this.iconType == 'wifi' || this.iconType == 'mobile');
+
+    if (this.networkState && multiLevel) {
+      this.setMultiLevelIcon_(params);
     } else {
-      multiLevel = false;
-      strength = -1;
+      icon.className = multiLevel ? 'multi-level level0' : '';
     }
-    icon.classList.toggle('multi-level', multiLevel);
+
+    this.setIconBadges_(params);
+  },
+
+  /**
+   * Toggles icon classes based on strength and connecting properties.
+   * |this.networkState| is expected to be specified.
+   * @param {!IconParams} params The set of params describing the icon.
+   * @private
+   */
+  setMultiLevelIcon_: function(params) {
+    // Set the strength or connecting properties.
+    var networkState = this.networkState;
+
+    var connecting = false;
+    var strength = -1;
+    if (networkState.connecting()) {
+      strength = 0;
+      connecting = true;
+    } else if (networkState.connected() || !params.showDisconnected) {
+      strength = params.strength || 0;
+    }
+
+    var icon = this.$.icon;
+    icon.classList.toggle('multi-level', true);
+    icon.classList.toggle('connecting', connecting);
     icon.classList.toggle('level0', strength < 0);
     icon.classList.toggle('level1', strength >= 0 && strength <= 25);
     icon.classList.toggle('level2', strength > 25 && strength <= 50);
     icon.classList.toggle('level3', strength > 50 && strength <= 75);
     icon.classList.toggle('level4', strength > 75);
+  },
 
-    this.$.secure.hidden = !params.secure;
+  /**
+   * Sets the icon badge visibility properties: roaming, secure, technology.
+   * @param {!IconParams} params The set of params describing the icon.
+   * @private
+   */
+  setIconBadges_: function(params) {
+    var networkState = this.networkState;
+
+    var type =
+        (params.showBadges && networkState) ? networkState.data.Type : '';
+    if (type == CrOnc.Type.WIFI) {
+      this.roaming = false;
+      this.secure = networkState.getWiFiSecurity() != 'None';
+      this.technology = '';
+    } else if (type == CrOnc.Type.WIMAX) {
+      this.roaming = false;
+      this.secure = false;
+      this.technology = '4g';
+    } else if (type == CrOnc.Type.CELLULAR) {
+      this.roaming =
+          networkState.getCellularRoamingState() == CrOnc.RoamingState.ROAMING;
+      this.secure = false;
+      var oncTechnology = networkState.getCellularTechnology();
+      switch (oncTechnology) {
+        case CrOnc.NetworkTechnology.EDGE:
+          this.technology = 'edge';
+          break;
+        case CrOnc.NetworkTechnology.EVDO:
+          this.technology = 'evdo';
+          break;
+        case CrOnc.NetworkTechnology.GPRS:
+        case CrOnc.NetworkTechnology.GSM:
+          this.technology = 'gsm';
+          break;
+        case CrOnc.NetworkTechnology.HSPA:
+          this.technology = 'hspa';
+          break;
+        case CrOnc.NetworkTechnology.HSPA_PLUS:
+          this.technology = 'hspa_plus';
+          break;
+        case CrOnc.NetworkTechnology.LTE:
+          this.technology = 'lte';
+          break;
+        case CrOnc.NetworkTechnology.LTE_ADVANCED:
+          this.technology = 'lte_advanced';
+          break;
+        case CrOnc.NetworkTechnology.UMTS:
+          this.technology = '3g';
+          break;
+      }
+    } else {
+      this.roaming = false;
+      this.secure = false;
+      this.technology = '';
+    }
   },
 });
 })();
diff --git a/ui/webui/resources/cr_elements/cr_network_icon/mobile.png b/ui/webui/resources/cr_elements/cr_network_icon/mobile.png
index 548ef5f..9c2d026 100644
--- a/ui/webui/resources/cr_elements/cr_network_icon/mobile.png
+++ b/ui/webui/resources/cr_elements/cr_network_icon/mobile.png
Binary files differ
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
index 4bca1d2..01b0f55 100644
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
+++ b/ui/webui/resources/cr_elements/cr_onc/cr_onc_data.js
@@ -22,13 +22,22 @@
     data: null,
   },
 
+  /** @override */
   created: function() {
     this.data = /** @type {CrOnc.NetworkConfigType} */({});
   },
 
-  /**
-   * @return {number} The signal strength of the network.
-   */
+  /** @return {boolean} True if the network is connected. */
+  connected: function() {
+    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTED;
+  },
+
+  /** @return {boolean} True if the network is connecting. */
+  connecting: function() {
+    return this.data.ConnectionState == CrOnc.ConnectionState.CONNECTING;
+  },
+
+  /** @return {number} The signal strength of the network. */
   getStrength: function() {
     var type = this.data.Type;
     var strength = 0;
@@ -41,12 +50,21 @@
     return strength;
   },
 
-  /**
-   * Returns the WiFi security type. Undefined or empty defaults to 'None'.
-   * @return {string} The WiFi security type.
-   */
+  /** @return {CrOnc.Security} The ONC security type. */
   getWiFiSecurity: function() {
     return (this.data.WiFi && this.data.WiFi.Security) ?
-        this.data.WiFi.Security : 'None';
+        this.data.WiFi.Security : CrOnc.Security.NONE;
+  },
+
+  /** @return {CrOnc.RoamingState} The ONC roaming state. */
+  getCellularRoamingState: function() {
+    return (this.data.Cellular && this.data.Cellular.RoamingState) ?
+        this.data.Cellular.RoamingState : CrOnc.RoamingState.UNKNOWN;
+  },
+
+  /** @return {CrOnc.NetworkTechnology} The ONC network technology. */
+  getCellularTechnology: function() {
+    return (this.data.Cellular && this.data.Cellular.NetworkTechnology) ?
+        this.data.Cellular.NetworkTechnology : CrOnc.NetworkTechnology.UNKNOWN;
   }
 });
diff --git a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js b/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
index 8c010ac..714d4593 100644
--- a/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
+++ b/ui/webui/resources/cr_elements/cr_onc/cr_onc_types.js
@@ -12,16 +12,67 @@
 
 var CrOnc = {};
 
+/** @enum {string} */
+CrOnc.Type = {
+  CELLULAR: 'Cellular',
+  ETHERNET: 'Ethernet',
+  VPN: 'VPN',
+  WIFI: 'WiFi',
+  WIMAX: 'WiMAX',
+};
+
+/** @enum {string} */
+CrOnc.ConnectionState = {
+  CONNECTED: 'Connected',
+  CONNECTING: 'Connecting',
+  NOT_CONNECTED: 'NotConnected',
+};
+
+/** @enum {string} */
+CrOnc.NetworkTechnology = {
+  EDGE: 'EDGE',
+  EVDO: 'EVDO',
+  GPRS: 'GPRS',
+  GSM: 'GSM',
+  HSPA: 'HSPA',
+  HSPA_PLUS: 'HSPA+',
+  LTE: 'LTE',
+  LTE_ADVANCED: 'LTE Advanced',
+  UMTS: 'UMTS',
+  UNKNOWN: 'Unknown',
+};
+
+/** @enum {string} */
+CrOnc.RoamingState = {
+  HOME: 'Home',
+  REQUIRED: 'Required',
+  ROAMING: 'Roaming',
+  UNKNOWN: 'Unknown',
+};
+
+/** @enum {string} */
+CrOnc.Security = {
+  NONE: 'None',
+  WEP_8021X: 'WEP-8021X',
+  WEP_PSK: 'WEP-PSK',
+  WPA_EAP: 'WPA-EAP',
+  WPA_PSK: 'WPA-PSK',
+};
+
 /** @typedef {string|!Object} */
 CrOnc.ManagedStringType;
 
 /**
- * @typedef {{NetworkTechnology: string, Strength: number}}
+ * @typedef {{
+ *   NetworkTechnology: CrOnc.NetworkTechnology,
+ *   RoamingState: CrOnc.RoamingState,
+ *   Strength: number
+ * }}
  */
 CrOnc.CellularType;
 
 /**
- * @typedef {{Security: string, Strength: number}}
+ * @typedef {{Security: CrOnc.Security, Strength: number}}
  */
 CrOnc.WiFiType;
 
@@ -30,22 +81,13 @@
  */
 CrOnc.WiMAXType;
 
-/** @enum {string} */
-CrOnc.Type = {
-  CELLULAR: "Cellular",
-  ETHERNET: "Ethernet",
-  VPN: "VPN",
-  WIFI: "WiFi",
-  WIMAX: "WiMAX",
-};
-
 /**
  * @typedef {{
  *   Cellular: CrOnc.CellularType,
- *   ConnectionState: string,
+ *   ConnectionState: CrOnc.ConnectionState,
  *   GUID: string,
  *   Name: CrOnc.ManagedStringType,
- *   Type: string,
+ *   Type: CrOnc.Type,
  *   WiFi: CrOnc.WiFiType,
  *   WiMAX: CrOnc.WiMAXType
  * }}
diff --git a/ui/webui/resources/cr_elements_images.grdp b/ui/webui/resources/cr_elements_images.grdp
index de2116d..46a3689 100644
--- a/ui/webui/resources/cr_elements_images.grdp
+++ b/ui/webui/resources/cr_elements_images.grdp
@@ -1,18 +1,48 @@
 <?xml version="1.0" encoding="utf-8"?>
 <grit-part>
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_3G"
+           file="cr_elements/cr_network_icon/badge_3g.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_4G"
+           file="cr_elements/cr_network_icon/badge_4g.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EDGE"
+           file="cr_elements/cr_network_icon/badge_edge.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_EVDO"
+           file="cr_elements/cr_network_icon/badge_evdo.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_GPRS"
+           file="cr_elements/cr_network_icon/badge_gsm.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA"
+           file="cr_elements/cr_network_icon/badge_hspa.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_HSPA_PLUS"
+           file="cr_elements/cr_network_icon/badge_hspa_plus.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE"
+           file="cr_elements/cr_network_icon/badge_lte.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_LTE_ADVANCED"
+           file="cr_elements/cr_network_icon/badge_lte_advanced.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_ROAMING"
+           file="cr_elements/cr_network_icon/badge_roaming.png" 
+           type="BINDATA" />
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_BADGE_SECURE"
+           file="cr_elements/cr_network_icon/badge_secure.png" 
+           type="BINDATA" />
   <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_ETHERNET"
            file="cr_elements/cr_network_icon/ethernet.png" 
            type="BINDATA" />
-  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI"
-           file="cr_elements/cr_network_icon/wifi.png" 
-           type="BINDATA" />
   <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_MOBILE"
            file="cr_elements/cr_network_icon/mobile.png" 
            type="BINDATA" />
   <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_VPN"
            file="cr_elements/cr_network_icon/vpn.png" 
            type="BINDATA" />
-  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_SECURE"
-           file="cr_elements/cr_network_icon/secure.png" 
+  <include name="IDR_WEBUI_CR_ELEMENTS_NETWORK_ICON_WIFI"
+           file="cr_elements/cr_network_icon/wifi.png" 
            type="BINDATA" />
 </grit-part>
diff --git a/ui/webui/resources/cr_elements_resources.grdp b/ui/webui/resources/cr_elements_resources.grdp
index 8eb2787a..f1b89bf 100644
--- a/ui/webui/resources/cr_elements_resources.grdp
+++ b/ui/webui/resources/cr_elements_resources.grdp
@@ -37,29 +37,38 @@
              file="../../webui/resources/cr_elements/cr_dropdown_menu/cr_dropdown_menu.js"
              type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_CSS"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.css" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.css"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_HTML"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.html" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.html"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_NETWORK_ICON_JS"
-             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_network_icon/cr_network_icon.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_ONC_TYPES_JS"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_onc/cr_onc_types.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_HTML"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.html" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.html"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_ONC_DATA_JS"
-             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.js" 
-             type="chrome_html" /> 
+             file="../../webui/resources/cr_elements/cr_onc/cr_onc_data.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_EVENTS_HTML"
              file="../../webui/resources/cr_elements/cr_events/cr_events.html"
              type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_EVENTS_JS"
              file="../../webui/resources/cr_elements/cr_events/cr_events.js"
              type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_CR_INPUT_CSS"
+             file="../../webui/resources/cr_elements/cr_input/cr_input.css"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_CR_INPUT_HTML"
+             file="../../webui/resources/cr_elements/cr_input/cr_input.html"
+             type="chrome_html" />
+  <structure name="IDR_CR_ELEMENTS_CR_INPUT_JS"
+             file="../../webui/resources/cr_elements/cr_input/cr_input.js"
+             type="chrome_html" />
   <structure name="IDR_CR_ELEMENTS_CR_TOGGLE_BUTTON_CSS"
              file="../../webui/resources/cr_elements/cr_toggle_button/cr_toggle_button.css"
              type="chrome_html" />
diff --git a/ui/wm/BUILD.gn b/ui/wm/BUILD.gn
index 290a90f9..74fea7c1 100644
--- a/ui/wm/BUILD.gn
+++ b/ui/wm/BUILD.gn
@@ -115,39 +115,37 @@
   ]
 }
 
-if (!is_win || link_chrome_on_windows) {
-  test("wm_unittests") {
-    sources = [
-      "core/capture_controller_unittest.cc",
-      "core/compound_event_filter_unittest.cc",
-      "core/cursor_manager_unittest.cc",
-      "core/focus_controller_unittest.cc",
-      "core/image_grid_unittest.cc",
-      "core/input_method_event_filter_unittest.cc",
-      "core/nested_accelerator_controller_unittest.cc",
-      "core/shadow_controller_unittest.cc",
-      "core/transient_window_manager_unittest.cc",
-      "core/transient_window_stacking_client_unittest.cc",
-      "core/visibility_controller_unittest.cc",
-      "core/window_animations_unittest.cc",
-      "test/run_all_unittests.cc",
-    ]
+test("wm_unittests") {
+  sources = [
+    "core/capture_controller_unittest.cc",
+    "core/compound_event_filter_unittest.cc",
+    "core/cursor_manager_unittest.cc",
+    "core/focus_controller_unittest.cc",
+    "core/image_grid_unittest.cc",
+    "core/input_method_event_filter_unittest.cc",
+    "core/nested_accelerator_controller_unittest.cc",
+    "core/shadow_controller_unittest.cc",
+    "core/transient_window_manager_unittest.cc",
+    "core/transient_window_stacking_client_unittest.cc",
+    "core/visibility_controller_unittest.cc",
+    "core/window_animations_unittest.cc",
+    "test/run_all_unittests.cc",
+  ]
 
-    deps = [
-      ":test_support",
-      ":wm",
-      "//base",
-      "//base/test:test_support",
-      "//skia",
-      "//testing/gtest",
-      "//ui/aura:test_support",
-      "//ui/base:test_support",
-      "//ui/compositor:test_support",
-      "//ui/events:test_support",
-      "//ui/events/platform",
-      "//ui/gfx",
-      "//ui/gfx/geometry",
-      "//ui/gl",
-    ]
-  }
+  deps = [
+    ":test_support",
+    ":wm",
+    "//base",
+    "//base/test:test_support",
+    "//skia",
+    "//testing/gtest",
+    "//ui/aura:test_support",
+    "//ui/base:test_support",
+    "//ui/compositor:test_support",
+    "//ui/events:test_support",
+    "//ui/events/platform",
+    "//ui/gfx",
+    "//ui/gfx/geometry",
+    "//ui/gl",
+  ]
 }