Merge "Revert "Downstream Workaround for Qualcomm Bug 10205015""
diff --git a/.DEPS.git b/.DEPS.git
index de7fe08..acce559 100644
--- a/.DEPS.git
+++ b/.DEPS.git
@@ -11,7 +11,7 @@
     'git_url':
          'https://chromium.googlesource.com',
     'webkit_rev':
-         '@224e93089f131d160474b7de59b6d2b2b23e01dd'
+         '@88c9a95505973e4bc340d847a42caaae3e709774'
 }
 
 deps = {
@@ -98,11 +98,11 @@
     'src/third_party/sfntly/cpp/src':
         Var('git_url') + '/external/sfntly/cpp/src.git@cfb2f1743f0169ad8d01035458617bce97107539',
     'src/third_party/skia/gyp':
-        Var('git_url') + '/external/skia/gyp.git@67b4c8c19afc9520f1d3a3decd4f012c50c32d0f',
+        Var('git_url') + '/external/skia/gyp.git@dccf47acbdb65e21ed989fa3f45e638caffa6ce6',
     'src/third_party/skia/include':
-        Var('git_url') + '/external/skia/include.git@35fdbf8a5dd166a876e7fd81d55adc49343f1bf5',
+        Var('git_url') + '/external/skia/include.git@970ef2af6ab2e1d6554207e3f66cce934cd091d5',
     'src/third_party/skia/src':
-        Var('git_url') + '/external/skia/src.git@3e45b0d5d63c5b8623679a2fb937d8f27d271699',
+        Var('git_url') + '/external/skia/src.git@d2da8bcbed4791ae93c3070c50e89865b6398e10',
     'src/third_party/smhasher/src':
         Var('git_url') + '/external/smhasher.git@6f63a4882e6b2cf87e8eec1a3ef8644e0d963283',
     'src/third_party/snappy/src':
@@ -136,7 +136,7 @@
     'src/tools/swarm_client':
         Var('git_url') + '/chromium/tools/swarm_client.git@86681e9a54c88972dba217b4f1007222dd8936a4',
     'src/v8':
-        Var('git_url') + '/external/v8.git@307dd6ea3b729c8058ada645b42a1cf083c92128',
+        Var('git_url') + '/external/v8.git@54d8a9855f2c6a6c3c33b5b66cbfbbac2cbcaa00',
     'src/webkit/renderer/media/crypto/ppapi/cdm':
         Var('git_url') + '/chromium/cdm.git@c2b192a02546916d28233cfd8b7717ffcdcc8347',
 }
@@ -341,7 +341,7 @@
         'src/third_party/swig/win':
             Var('git_url') + '/chromium/deps/swig/win.git@986f013ba518541adf5c839811efb35630a31031',
         'src/third_party/syzygy/binaries':
-            Var('git_url') + '/external/sawbuck/syzygy/binaries.git@bcae0722f0e45aa098e7d2eee350234749efba8f',
+            Var('git_url') + '/external/sawbuck/syzygy/binaries.git@d25845b9eb9b5e2b42e60e8dadcfc711987ebd18',
         'src/third_party/xulrunner-sdk':
             Var('git_url') + '/chromium/deps/xulrunner-sdk.git@e9b241c183fa4e7af838ecd70714069ca0eb150c',
         'src/third_party/yasm/binaries':
diff --git a/.merged-revisions b/.merged-revisions
index 564cf9d..42fbfad 100644
--- a/.merged-revisions
+++ b/.merged-revisions
@@ -18,3 +18,4 @@
 a36e5920737c6adbddd3e43b760e5de8431db6e0 34378da0e9429d394aafdaa771301aff58447cb1 87e3b917949080e5708cfb3ff328511ed38c972a
 2385ea399aae016c0806a4f9ef3c9cfe3d2a39df 8ee924b76946696c0f52e56d28cc5ab741919041 996b4a6775d74008bcb457f0d4322d4fa166a9e1
 3240926e260ce088908e02ac07a6cf7b0c0cbf44 3b21a50ee4fe6f71bb117cbee9998a4f465eea9d 26544a2724df91bb82e179e9ba29312d3abc9e26
+bb1529ce867d8845a77ec7cdf3e3003ef1771a40 c95505573d864f17cabf515e32f5b8e0831ae237 fab21778635f3b2de43dc3bc5cdf3dbc594ac2e3
diff --git a/DEPS b/DEPS
index f66cd70..7798439 100644
--- a/DEPS
+++ b/DEPS
@@ -8,9 +8,10 @@
   "sourceforge_url": "http://svn.code.sf.net/p/%(repo)s/code",
   "webkit_trunk": "http://src.chromium.org/blink/trunk",
   "nacl_trunk": "http://src.chromium.org/native_client/trunk",
-  "webkit_revision": "155634",
+  "webkit_revision": "155688",
   "chromium_git": "https://chromium.googlesource.com",
   "chromiumos_git": "https://chromium.googlesource.com/chromiumos",
+  "skia_git": "https://skia.googlesource.com",
   "swig_revision": "69281",
   "nacl_revision": "11930",
   # After changing nacl_revision, run 'glient sync' and check native_client/DEPS
@@ -28,11 +29,12 @@
   "ffmpeg_hash": "894e6f715645528e815aee2dad45b59704238dcd",
 
   "sfntly_revision": "134",
-  "skia_revision": "10553",
+  "skia_revision": "10602",
+  "skia_hash": "6d04e64f56b658635eeb46fcdb02188ce54f1567",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and V8 without interference from each other.
-  "v8_revision": "16065",
+  "v8_revision": "16104",
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling WebRTC
   # and V8 without interference from each other.
@@ -312,7 +314,7 @@
     # Binary level profile guided optimizations. This points to the
     # latest release binaries for the toolchain.
     "src/third_party/syzygy/binaries":
-      (Var("googlecode_url") % "sawbuck") + "/trunk/syzygy/binaries@1689",
+      (Var("googlecode_url") % "sawbuck") + "/trunk/syzygy/binaries@1718",
 
     # Binaries for nacl sdk.
     "src/third_party/nacl_sdk_binaries":
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index c2f23a3..237712a 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -111,6 +111,8 @@
         'browser/aw_download_manager_delegate.h',
         'browser/aw_form_database_service.cc',
         'browser/aw_form_database_service.h',
+        'browser/aw_gl_surface.cc',
+        'browser/aw_gl_surface.h',
         'browser/aw_http_auth_handler_base.cc',
         'browser/aw_http_auth_handler_base.h',
         'browser/aw_javascript_dialog_manager.cc',
diff --git a/android_webview/android_webview_common.target.darwin-arm.mk b/android_webview/android_webview_common.target.darwin-arm.mk
index 57a845e..5e3624e 100644
--- a/android_webview/android_webview_common.target.darwin-arm.mk
+++ b/android_webview/android_webview_common.target.darwin-arm.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/android_webview_common.target.darwin-mips.mk b/android_webview/android_webview_common.target.darwin-mips.mk
index 4c6073b..c775bc5 100644
--- a/android_webview/android_webview_common.target.darwin-mips.mk
+++ b/android_webview/android_webview_common.target.darwin-mips.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/android_webview_common.target.darwin-x86.mk b/android_webview/android_webview_common.target.darwin-x86.mk
index 0d4f41d..0044f93 100644
--- a/android_webview/android_webview_common.target.darwin-x86.mk
+++ b/android_webview/android_webview_common.target.darwin-x86.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/android_webview_common.target.linux-arm.mk b/android_webview/android_webview_common.target.linux-arm.mk
index 57a845e..5e3624e 100644
--- a/android_webview/android_webview_common.target.linux-arm.mk
+++ b/android_webview/android_webview_common.target.linux-arm.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/android_webview_common.target.linux-mips.mk b/android_webview/android_webview_common.target.linux-mips.mk
index 4c6073b..c775bc5 100644
--- a/android_webview/android_webview_common.target.linux-mips.mk
+++ b/android_webview/android_webview_common.target.linux-mips.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/android_webview_common.target.linux-x86.mk b/android_webview/android_webview_common.target.linux-x86.mk
index 0d4f41d..0044f93 100644
--- a/android_webview/android_webview_common.target.linux-x86.mk
+++ b/android_webview/android_webview_common.target.linux-x86.mk
@@ -35,6 +35,7 @@
 	android_webview/browser/aw_devtools_delegate.cc \
 	android_webview/browser/aw_download_manager_delegate.cc \
 	android_webview/browser/aw_form_database_service.cc \
+	android_webview/browser/aw_gl_surface.cc \
 	android_webview/browser/aw_http_auth_handler_base.cc \
 	android_webview/browser/aw_javascript_dialog_manager.cc \
 	android_webview/browser/aw_login_delegate.cc \
diff --git a/android_webview/browser/aw_gl_surface.cc b/android_webview/browser/aw_gl_surface.cc
new file mode 100644
index 0000000..5ff9272
--- /dev/null
+++ b/android_webview/browser/aw_gl_surface.cc
@@ -0,0 +1,48 @@
+// 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 "android_webview/browser/aw_gl_surface.h"
+
+namespace android_webview {
+
+AwGLSurface::AwGLSurface() : fbo_(0) {}
+
+AwGLSurface::~AwGLSurface() {}
+
+void AwGLSurface::Destroy() {
+}
+
+bool AwGLSurface::IsOffscreen() {
+  return false;
+}
+
+unsigned int AwGLSurface::GetBackingFrameBufferObject() {
+  return fbo_;
+}
+
+bool AwGLSurface::SwapBuffers() {
+  return true;
+}
+
+gfx::Size AwGLSurface::GetSize() {
+  return gfx::Size(1, 1);
+}
+
+void* AwGLSurface::GetHandle() {
+  return NULL;
+}
+
+void* AwGLSurface::GetDisplay() {
+  return NULL;
+}
+
+void AwGLSurface::SetBackingFrameBufferObject(unsigned int fbo) {
+  fbo_ = fbo;
+}
+
+void AwGLSurface::ResetBackingFrameBufferObject() {
+  fbo_ = 0;
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/aw_gl_surface.h b/android_webview/browser/aw_gl_surface.h
new file mode 100644
index 0000000..99b8a1d
--- /dev/null
+++ b/android_webview/browser/aw_gl_surface.h
@@ -0,0 +1,42 @@
+// 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 ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_
+#define ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_
+
+#include "ui/gl/gl_surface.h"
+
+namespace android_webview {
+
+// This surface is used to represent the underlying surface provided by the App
+// inside a hardware draw. Note that offscreen contexts will not be using this
+// GLSurface.
+class GL_EXPORT AwGLSurface : public gfx::GLSurface {
+ public:
+  AwGLSurface();
+
+  // Implement GLSurface.
+  virtual void Destroy() OVERRIDE;
+  virtual bool IsOffscreen() OVERRIDE;
+  virtual unsigned int GetBackingFrameBufferObject() OVERRIDE;
+  virtual bool SwapBuffers() OVERRIDE;
+  virtual gfx::Size GetSize() OVERRIDE;
+  virtual void* GetHandle() OVERRIDE;
+  virtual void* GetDisplay() OVERRIDE;
+
+  void SetBackingFrameBufferObject(unsigned int fbo);
+  void ResetBackingFrameBufferObject();
+
+ protected:
+  virtual ~AwGLSurface();
+
+ private:
+  unsigned int fbo_;
+
+  DISALLOW_COPY_AND_ASSIGN(AwGLSurface);
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_AW_GL_SURFACE_H_
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index a714956..3e25680 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -6,6 +6,7 @@
 
 #include <android/bitmap.h>
 
+#include "android_webview/browser/aw_gl_surface.h"
 #include "android_webview/browser/scoped_app_gl_state_restore.h"
 #include "android_webview/common/aw_switches.h"
 #include "android_webview/public/browser/draw_gl.h"
@@ -289,6 +290,19 @@
   return result;
 }
 
+bool InProcessViewRenderer::InitializeHwDraw() {
+  TRACE_EVENT0("android_webview", "InitializeHwDraw");
+  DCHECK(!gl_surface_);
+  gl_surface_  = new AwGLSurface;
+  hardware_failed_ = !compositor_->InitializeHwDraw(gl_surface_);
+  hardware_initialized_ = true;
+
+  if (hardware_failed_)
+    gl_surface_ = NULL;
+
+  return !hardware_failed_;
+}
+
 void InProcessViewRenderer::DrawGL(AwDrawGLInfo* draw_info) {
   TRACE_EVENT0("android_webview", "InProcessViewRenderer::DrawGL");
   DCHECK(visible_);
@@ -309,13 +323,11 @@
   ScopedAllowGL allow_gl;
 
   if (attached_to_window_ && compositor_ && !hardware_initialized_) {
-    TRACE_EVENT0("android_webview", "InitializeHwDraw");
-    hardware_failed_ = !compositor_->InitializeHwDraw();
-    hardware_initialized_ = true;
-    last_egl_context_ = current_context;
-
-    if (hardware_failed_)
+    if (InitializeHwDraw()) {
+      last_egl_context_ = current_context;
+    } else {
       return;
+    }
   }
 
   if (draw_info->mode == AwDrawGLInfo::kModeProcess)
@@ -330,7 +342,6 @@
     TRACE_EVENT_INSTANT0(
         "android_webview", "EGLContextChanged", TRACE_EVENT_SCOPE_THREAD);
   }
-  last_egl_context_ = current_context;
 
   if (!compositor_) {
     TRACE_EVENT_INSTANT0(
@@ -338,21 +349,26 @@
     return;
   }
 
+  DCHECK(gl_surface_);
+  gl_surface_->SetBackingFrameBufferObject(
+      state_restore.framebuffer_binding_ext());
+
   gfx::Transform transform;
   transform.matrix().setColMajorf(draw_info->transform);
   transform.Translate(scroll_at_start_of_frame_.x(),
                       scroll_at_start_of_frame_.y());
-  // TODO(joth): Check return value.
-  block_invalidates_ = true;
   gfx::Rect clip_rect(draw_info->clip_left,
                       draw_info->clip_top,
                       draw_info->clip_right - draw_info->clip_left,
                       draw_info->clip_bottom - draw_info->clip_top);
+  block_invalidates_ = true;
+  // TODO(joth): Check return value.
   compositor_->DemandDrawHw(gfx::Size(draw_info->width, draw_info->height),
                             transform,
                             clip_rect,
                             state_restore.stencil_enabled());
   block_invalidates_ = false;
+  gl_surface_->ResetBackingFrameBufferObject();
 
   UpdateCachedGlobalVisibleRect();
   bool drew_full_visible_rect = clip_rect.Contains(cached_global_visible_rect_);
@@ -554,6 +570,7 @@
     hardware_initialized_ = false;
   }
 
+  gl_surface_ = NULL;
   attached_to_window_ = false;
 }
 
diff --git a/android_webview/browser/in_process_view_renderer.h b/android_webview/browser/in_process_view_renderer.h
index 6e66a84..8bb2c60 100644
--- a/android_webview/browser/in_process_view_renderer.h
+++ b/android_webview/browser/in_process_view_renderer.h
@@ -23,6 +23,8 @@
 
 namespace android_webview {
 
+class AwGLSurface;
+
 // Provides RenderViewHost wrapper functionality for sending WebView-specific
 // IPC messages to the renderer and from there to WebKit.
 class InProcessViewRenderer : public BrowserViewRenderer,
@@ -93,6 +95,8 @@
 
   void NoLongerExpectsDrawGL();
 
+  bool InitializeHwDraw();
+
   // For debug tracing or logging. Return the string representation of this
   // view renderer's state and the |draw_info| if provided.
   std::string ToString(AwDrawGLInfo* draw_info) const;
@@ -127,6 +131,7 @@
   bool attached_to_window_;
   bool hardware_initialized_;
   bool hardware_failed_;
+  scoped_refptr<AwGLSurface> gl_surface_;
 
   // Used only for detecting Android View System context changes.
   // Not to be used between draw calls.
diff --git a/android_webview/browser/scoped_app_gl_state_restore.cc b/android_webview/browser/scoped_app_gl_state_restore.cc
index cb8d128..e0c8fed 100644
--- a/android_webview/browser/scoped_app_gl_state_restore.cc
+++ b/android_webview/browser/scoped_app_gl_state_restore.cc
@@ -132,6 +132,7 @@
   glGetIntegerv(GL_STENCIL_VALUE_MASK, &stencil_mask_);
   glGetIntegerv(GL_STENCIL_REF, &stencil_ref_);
 
+  glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &framebuffer_binding_ext_);
 
   if (!g_gl_max_texture_units) {
     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &g_gl_max_texture_units);
@@ -155,6 +156,7 @@
   TRACE_EVENT0("android_webview", "AppGLStateRestore");
   MakeAppContextCurrent();
 
+  glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_binding_ext_);
   glBindBuffer(GL_ARRAY_BUFFER, vertex_array_buffer_binding_);
   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_buffer_binding_);
 
diff --git a/android_webview/browser/scoped_app_gl_state_restore.h b/android_webview/browser/scoped_app_gl_state_restore.h
index 7840fbf..93b5ad5 100644
--- a/android_webview/browser/scoped_app_gl_state_restore.h
+++ b/android_webview/browser/scoped_app_gl_state_restore.h
@@ -25,6 +25,7 @@
   ~ScopedAppGLStateRestore();
 
   bool stencil_enabled() const { return stencil_test_; }
+  GLint framebuffer_binding_ext() const { return framebuffer_binding_ext_; }
 
  private:
   const CallMode mode_;
@@ -83,6 +84,8 @@
   GLint stencil_mask_;
   GLint stencil_ref_;
 
+  GLint framebuffer_binding_ext_;
+
   struct TextureBindings {
     GLint texture_2d;
     GLint texture_cube_map;
diff --git a/android_webview/native/aw_autofill_manager_delegate.cc b/android_webview/native/aw_autofill_manager_delegate.cc
index 3791122..37640cb 100644
--- a/android_webview/native/aw_autofill_manager_delegate.cc
+++ b/android_webview/native/aw_autofill_manager_delegate.cc
@@ -187,11 +187,12 @@
   NOTIMPLEMENTED();
 }
 
-void AwAutofillManagerDelegate::ShowAutocheckoutBubble(
+bool AwAutofillManagerDelegate::ShowAutocheckoutBubble(
     const gfx::RectF& bounding_box,
     bool is_google_user,
     const base::Callback<void(autofill::AutocheckoutBubbleState)>& callback) {
   NOTIMPLEMENTED();
+  return false;
 }
 
 void AwAutofillManagerDelegate::HideAutocheckoutBubble() {
diff --git a/android_webview/native/aw_autofill_manager_delegate.h b/android_webview/native/aw_autofill_manager_delegate.h
index 1292ccb..b39eb70 100644
--- a/android_webview/native/aw_autofill_manager_delegate.h
+++ b/android_webview/native/aw_autofill_manager_delegate.h
@@ -73,7 +73,7 @@
       const autofill::AutofillMetrics& metric_logger,
       const autofill::CreditCard& credit_card,
       const base::Closure& save_card_callback) OVERRIDE;
-  virtual void ShowAutocheckoutBubble(
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounds,
       bool is_google_user,
       const base::Callback<void(
diff --git a/apps/DEPS b/apps/DEPS
index dbcf7e7..0100480 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -5,6 +5,7 @@
   "+components/user_prefs/pref_registry_syncable.h",
   "+components/web_modal",
   "+extensions",
+  "+net/base",
   "+skia/ext",
   "+third_party/skia/include",
   "+ui",
@@ -14,6 +15,7 @@
   "+chrome/browser/browser_process.h",
   "+chrome/browser/browser_shutdown.h",
   "+chrome/browser/chrome_notification_types.h",
+  "+chrome/browser/chromeos/drive",
   "+chrome/browser/extensions",
   "+chrome/browser/lifetime/application_lifetime.h",
   "+chrome/browser/profiles",
diff --git a/apps/OWNERS b/apps/OWNERS
index 8391787..ba62226 100644
--- a/apps/OWNERS
+++ b/apps/OWNERS
@@ -2,5 +2,6 @@
 asargent@chromium.org
 benwells@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 tapted@chromium.org
diff --git a/apps/app_launch_for_metro_restart_win.cc b/apps/app_launch_for_metro_restart_win.cc
index 9d6cb22..2b10274 100644
--- a/apps/app_launch_for_metro_restart_win.cc
+++ b/apps/app_launch_for_metro_restart_win.cc
@@ -4,6 +4,7 @@
 
 #include "apps/app_launch_for_metro_restart_win.h"
 
+#include "apps/launcher.h"
 #include "apps/pref_names.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "win8/util/win8_util.h"
diff --git a/apps/app_load_service.cc b/apps/app_load_service.cc
index 982822e..d2423c0 100644
--- a/apps/app_load_service.cc
+++ b/apps/app_load_service.cc
@@ -5,12 +5,12 @@
 #include "apps/app_load_service.h"
 
 #include "apps/app_load_service_factory.h"
+#include "apps/launcher.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -89,13 +89,13 @@
 
       switch (it->second.action_type) {
         case LAUNCH:
-          extensions::LaunchPlatformApp(profile_, extension);
+          LaunchPlatformApp(profile_, extension);
           break;
         case RESTART:
-          extensions::RestartPlatformApp(profile_, extension);
+          RestartPlatformApp(profile_, extension);
           break;
         case LAUNCH_WITH_COMMAND_LINE:
-          extensions::LaunchPlatformAppWithCommandLine(
+          LaunchPlatformAppWithCommandLine(
               profile_, extension, &it->second.command_line,
               it->second.current_dir);
           break;
diff --git a/apps/app_restore_service.cc b/apps/app_restore_service.cc
index 2ed8c47..e2d5a85 100644
--- a/apps/app_restore_service.cc
+++ b/apps/app_restore_service.cc
@@ -6,6 +6,7 @@
 
 #include "apps/app_lifetime_monitor_factory.h"
 #include "apps/app_restore_service_factory.h"
+#include "apps/launcher.h"
 #include "apps/saved_files_service.h"
 #include "apps/shell_window.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -14,7 +15,6 @@
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_set.h"
 
@@ -138,7 +138,7 @@
 }
 
 void AppRestoreService::RestoreApp(const Extension* extension) {
-  extensions::RestartPlatformApp(profile_, extension);
+  RestartPlatformApp(profile_, extension);
 }
 
 void AppRestoreService::StartObservingAppLifetime() {
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc
index 44a6df5..c3bac8f 100644
--- a/apps/app_restore_service_browsertest.cc
+++ b/apps/app_restore_service_browsertest.cc
@@ -92,7 +92,14 @@
   ASSERT_TRUE(file_entries.empty());
 }
 
-IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsRestored) {
+// Flaky: crbug.com/269613
+#if defined(OS_LINUX)
+#define MAYBE_FileAccessIsRestored DISABLED_FileAccessIsRestored
+#else
+#define MAYBE_FileAccessIsRestored FileAccessIsRestored
+#endif
+
+IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_FileAccessIsRestored) {
   content::WindowedNotificationObserver extension_suspended(
       chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
       content::NotificationService::AllSources());
diff --git a/apps/apps.gypi b/apps/apps.gypi
index 2a1bc99..59f4c75 100644
--- a/apps/apps.gypi
+++ b/apps/apps.gypi
@@ -54,6 +54,8 @@
         'app_window_contents.h',
         'field_trial_names.cc',
         'field_trial_names.h',
+        'launcher.cc',
+        'launcher.h',
         'metrics_names.h',
         'native_app_window.h',
         'pref_names.cc',
@@ -72,6 +74,13 @@
         'switches.h',
       ],
       'conditions': [
+        ['chromeos==1',
+          {
+            'dependencies': [
+              'browser_chromeos',
+            ]
+          }
+        ],
         ['enable_extensions==0',
           {
             'sources/': [
diff --git a/chrome/browser/extensions/platform_app_launcher.cc b/apps/launcher.cc
similarity index 91%
rename from chrome/browser/extensions/platform_app_launcher.cc
rename to apps/launcher.cc
index 9a8dd0c..d892da6 100644
--- a/chrome/browser/extensions/platform_app_launcher.cc
+++ b/apps/launcher.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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/extensions/platform_app_launcher.h"
+#include "apps/launcher.h"
 
 #include "base/command_line.h"
 #include "base/file_util.h"
@@ -23,7 +23,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/lazy_background_task_queue.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_messages.h"
 #include "content/public/browser/browser_thread.h"
@@ -31,7 +30,6 @@
 #include "content/public/browser/web_contents.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_util.h"
-#include "webkit/common/fileapi/file_system_types.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
@@ -50,8 +48,11 @@
 using extensions::app_file_handler_util::FirstFileHandlerForFile;
 using extensions::app_file_handler_util::CreateFileEntry;
 using extensions::app_file_handler_util::GrantedFileEntry;
+using extensions::Extension;
+using extensions::ExtensionHost;
+using extensions::ExtensionSystem;
 
-namespace extensions {
+namespace apps {
 
 namespace {
 
@@ -202,7 +203,7 @@
 
   void LaunchWithMimeType(const std::string& mime_type) {
     // Find file handler from the platform app for the file being opened.
-    const FileHandlerInfo* handler = NULL;
+    const extensions::FileHandlerInfo* handler = NULL;
     if (!handler_id_.empty())
       handler = FileHandlerForId(*extension_, handler_id_);
     else
@@ -231,7 +232,7 @@
     // available, or it might be in the process of being unloaded, in which case
     // the lazy background task queue is used to load the extension and then
     // call back to us.
-    LazyBackgroundTaskQueue* queue =
+    extensions::LazyBackgroundTaskQueue* queue =
         ExtensionSystem::Get(profile_)->lazy_background_task_queue();
     if (queue->ShouldEnqueueTask(profile_, extension_)) {
       queue->AddPendingTask(profile_, extension_->id(), base::Bind(
@@ -262,7 +263,7 @@
         host->render_process_host()->GetID(),
         file_path_,
         false);
-    AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
+    extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
         profile_, extension_, handler_id_, mime_type, file_entry);
   }
 
@@ -284,17 +285,6 @@
                                       const Extension* extension,
                                       const CommandLine* command_line,
                                       const base::FilePath& current_directory) {
-#if defined(OS_WIN)
-  // On Windows 8's single window Metro mode we can not launch platform apps.
-  // Offer to switch Chrome to desktop mode.
-  if (win8::IsSingleWindowMetroMode()) {
-    AppMetroInfoBarDelegateWin::Create(
-        profile, AppMetroInfoBarDelegateWin::LAUNCH_PACKAGED_APP,
-        extension->id());
-    return;
-  }
-#endif
-
   base::FilePath path;
   if (!GetAbsolutePathFromCommandLine(command_line, current_directory, &path)) {
     LaunchPlatformAppWithNoData(profile, extension);
@@ -339,22 +329,24 @@
   extensions::EventRouter* event_router =
       ExtensionSystem::Get(profile)->event_router();
   bool listening_to_restart = event_router->
-      ExtensionHasEventListener(extension->id(), event_names::kOnRestarted);
+      ExtensionHasEventListener(extension->id(),
+                                extensions::event_names::kOnRestarted);
 
   if (listening_to_restart) {
     extensions::AppEventRouter::DispatchOnRestartedEvent(profile, extension);
     return;
   }
 
-  ExtensionPrefs* extension_prefs = ExtensionSystem::Get(profile)->
+  extensions::ExtensionPrefs* extension_prefs = ExtensionSystem::Get(profile)->
       extension_service()->extension_prefs();
   bool had_windows = extension_prefs->IsActive(extension->id());
   extension_prefs->SetIsActive(extension->id(), false);
   bool listening_to_launch = event_router->
-      ExtensionHasEventListener(extension->id(), event_names::kOnLaunched);
+      ExtensionHasEventListener(extension->id(),
+                                extensions::event_names::kOnLaunched);
 
   if (listening_to_launch && had_windows)
     LaunchPlatformAppWithNoData(profile, extension);
 }
 
-}  // namespace extensions
+}  // namespace apps
diff --git a/chrome/browser/extensions/platform_app_launcher.h b/apps/launcher.h
similarity index 66%
rename from chrome/browser/extensions/platform_app_launcher.h
rename to apps/launcher.h
index 460c3e8..9412c11 100644
--- a/chrome/browser/extensions/platform_app_launcher.h
+++ b/apps/launcher.h
@@ -1,12 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
-#define CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
+#ifndef APPS_LAUNCHER_H_
+#define APPS_LAUNCHER_H_
 
 #include <string>
-#include <vector>
 
 class CommandLine;
 class Profile;
@@ -15,41 +14,41 @@
 class FilePath;
 }
 
-namespace content {
-class WebContents;
+namespace extensions {
+class Extension;
 }
 
-namespace extensions {
-
-class Extension;
+namespace apps {
 
 // Launches the platform app |extension|. Creates appropriate launch data for
 // the |command_line| fields present. |extension| and |profile| must not be
 // NULL. A NULL |command_line| means there is no launch data. If non-empty,
 // |current_directory| is used to expand any relative paths on the command line.
 void LaunchPlatformAppWithCommandLine(Profile* profile,
-                                      const Extension* extension,
+                                      const extensions::Extension* extension,
                                       const CommandLine* command_line,
                                       const base::FilePath& current_directory);
 
 // Launches the platform app |extension| with the contents of |file_path|
 // available through the launch data.
 void LaunchPlatformAppWithPath(Profile* profile,
-                               const Extension* extension,
+                               const extensions::Extension* extension,
                                const base::FilePath& file_path);
 
 // Launches the platform app |extension| with no launch data.
-void LaunchPlatformApp(Profile* profile, const Extension* extension);
+void LaunchPlatformApp(Profile* profile,
+                       const extensions::Extension* extension);
 
 // Launches the platform app |extension| with the contents of |file_path|
 // available through the launch data.
 void LaunchPlatformAppWithFileHandler(Profile* profile,
-                                      const Extension* extension,
+                                      const extensions::Extension* extension,
                                       const std::string& handler_id,
                                       const base::FilePath& file_path);
 
-void RestartPlatformApp(Profile* profile, const Extension* extension);
+void RestartPlatformApp(Profile* profile,
+                        const extensions::Extension* extension);
 
-}  // namespace extensions
+}  // namespace apps
 
-#endif  // CHROME_BROWSER_EXTENSIONS_PLATFORM_APP_LAUNCHER_H_
+#endif  // APPS_LAUNCHER_H_
diff --git a/ash/drag_drop/drag_drop_tracker_unittest.cc b/ash/drag_drop/drag_drop_tracker_unittest.cc
index acb87a4..c0a9e91 100644
--- a/ash/drag_drop/drag_drop_tracker_unittest.cc
+++ b/ash/drag_drop/drag_drop_tracker_unittest.cc
@@ -19,7 +19,7 @@
  public:
   virtual void SetUp() OVERRIDE {
     AshTestBase::SetUp();
-    UpdateDisplay("200x200,200x200");
+    UpdateDisplay("200x200,300x300");
   }
 
   aura::Window* CreateTestWindow(const gfx::Rect& bounds) {
diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc
index 03e7ff8..3dd2a14 100644
--- a/ash/launcher/launcher.cc
+++ b/ash/launcher/launcher.cc
@@ -186,4 +186,8 @@
   return launcher_view_->bounds();
 }
 
+app_list::ApplicationDragAndDropHost* Launcher::GetDragAndDropHostForAppList() {
+  return launcher_view_;
+}
+
 }  // namespace ash
diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h
index f9bdcc0..c670801 100644
--- a/ash/launcher/launcher.h
+++ b/ash/launcher/launcher.h
@@ -13,6 +13,10 @@
 #include "ui/gfx/size.h"
 #include "ui/views/widget/widget_observer.h"
 
+namespace app_list {
+class ApplicationDragAndDropHost;
+}
+
 namespace aura {
 class Window;
 }
@@ -103,6 +107,9 @@
   void SetLauncherViewBounds(gfx::Rect bounds);
   gfx::Rect GetLauncherViewBounds() const;
 
+  // Returns ApplicationDragAndDropHost for this Launcher.
+  app_list::ApplicationDragAndDropHost* GetDragAndDropHostForAppList();
+
  private:
   // LauncherView used to display icons.
   internal::LauncherView* launcher_view_;
diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc
index ea027f6..3d32892 100644
--- a/ash/launcher/launcher_view.cc
+++ b/ash/launcher/launcher_view.cc
@@ -25,7 +25,6 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell_delegate.h"
 #include "base/auto_reset.h"
-#include "base/command_line.h"
 #include "base/memory/scoped_ptr.h"
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
@@ -1524,11 +1523,6 @@
         Shell::GetInstance()->delegate()->RecordUserMetricsAction(
             UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON);
         Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView());
-        // By setting us as DnD recipient, the app list knows that we can
-        // handle items.
-        if (!CommandLine::ForCurrentProcess()->HasSwitch(
-                 ash::switches::kAshDisableDragAndDropAppListToLauncher))
-          Shell::GetInstance()->SetDragAndDropHostOfCurrentAppList(this);
         break;
     }
   }
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 33e6873..6d5fb62 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -48,7 +48,9 @@
 #include "ui/aura/client/tooltip_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
+#include "ui/aura/window_delegate.h"
 #include "ui/aura/window_observer.h"
+#include "ui/base/hit_test.h"
 #include "ui/base/models/menu_model.h"
 #include "ui/gfx/screen.h"
 #include "ui/keyboard/keyboard_controller.h"
@@ -137,6 +139,64 @@
   container->SetProperty(internal::kStayInSameRootWindowKey, true);
 }
 
+// A window delegate which does nothing. Used to create a window that
+// is a event target, but do nothing.
+class EmptyWindowDelegate : public aura::WindowDelegate {
+ public:
+  EmptyWindowDelegate() {}
+  virtual ~EmptyWindowDelegate() {}
+
+  // aura::WindowDelegate overrides:
+  virtual gfx::Size GetMinimumSize() const OVERRIDE {
+    return gfx::Size();
+  }
+  virtual gfx::Size GetMaximumSize() const OVERRIDE {
+    return gfx::Size();
+  }
+  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
+                               const gfx::Rect& new_bounds) OVERRIDE {
+  }
+  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
+    return gfx::kNullCursor;
+  }
+  virtual int GetNonClientComponent(
+      const gfx::Point& point) const OVERRIDE {
+    return HTNOWHERE;
+  }
+  virtual bool ShouldDescendIntoChildForEventHandling(
+      aura::Window* child,
+      const gfx::Point& location) OVERRIDE {
+    return false;
+  }
+  virtual bool CanFocus() OVERRIDE {
+    return false;
+  }
+  virtual void OnCaptureLost() OVERRIDE {
+  }
+  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
+  }
+  virtual void OnDeviceScaleFactorChanged(
+      float device_scale_factor) OVERRIDE {
+  }
+  virtual void OnWindowDestroying() OVERRIDE {}
+  virtual void OnWindowDestroyed() OVERRIDE {
+    delete this;
+  }
+  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {
+  }
+  virtual bool HasHitTestMask() const OVERRIDE {
+    return false;
+  }
+  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
+  virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE {
+    NOTREACHED();
+    return scoped_refptr<ui::Texture>();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate);
+};
+
 }  // namespace
 
 namespace internal {
@@ -278,6 +338,8 @@
 
 void RootWindowController::UpdateAfterLoginStatusChange(
     user::LoginStatus status) {
+  if (status != user::LOGGED_IN_NONE)
+    mouse_event_target_.reset();
   if (shelf_->status_area_widget())
     shelf_->status_area_widget()->UpdateAfterLoginStatusChange(status);
 }
@@ -316,6 +378,8 @@
 }
 
 void RootWindowController::CloseChildWindows() {
+  mouse_event_target_.reset();
+
   if (!shelf_.get())
     return;
   // panel_layout_manager_ needs to be shut down before windows are destroyed.
@@ -460,6 +524,19 @@
   shelf_.reset(new ShelfWidget(
       shelf_container, status_container, workspace_controller()));
 
+  if (!Shell::GetInstance()->session_state_delegate()->
+      IsActiveUserSessionStarted()) {
+    // This window exists only to be a event target on login screen.
+    // It does not have to handle events, nor be visible.
+    mouse_event_target_.reset(new aura::Window(new EmptyWindowDelegate));
+    mouse_event_target_->Init(ui::LAYER_NOT_DRAWN);
+
+    aura::Window* lock_background_container =
+        GetContainer(internal::kShellWindowId_LockScreenBackgroundContainer);
+    lock_background_container->AddChild(mouse_event_target_.get());
+    mouse_event_target_->Show();
+  }
+
   // Create Docked windows layout manager
   aura::Window* docked_container = GetContainer(
       internal::kShellWindowId_DockedContainer);
diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h
index 05ab29f..bbf29ce 100644
--- a/ash/root_window_controller.h
+++ b/ash/root_window_controller.h
@@ -241,6 +241,13 @@
   // The shelf for managing the launcher and the status widget.
   scoped_ptr<ShelfWidget> shelf_;
 
+  // An invisible/empty window used as a event target for
+  // |MouseCursorEventFilter| before a user logs in.
+  // (crbug.com/266987)
+  // Its container is |LockScreenBackgroundContainer| and
+  // this must be deleted before the container is deleted.
+  scoped_ptr<aura::Window> mouse_event_target_;
+
   // Manages layout of docked windows. Owned by DockedContainer.
   DockedWindowLayoutManager* docked_layout_manager_;
 
diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc
index b27cc52..0d40125 100644
--- a/ash/root_window_controller_unittest.cc
+++ b/ash/root_window_controller_unittest.cc
@@ -473,5 +473,24 @@
   }
 }
 
+typedef test::NoSessionAshTestBase NoSessionRootWindowControllerTest;
+
+// Make sure that an event handler exists for entire display area.
+TEST_F(NoSessionRootWindowControllerTest, Event) {
+  aura::RootWindow* root = Shell::GetPrimaryRootWindow();
+  const gfx::Size size = root->bounds().size();
+  aura::Window* event_target = root->GetEventHandlerForPoint(gfx::Point(0, 0));
+  EXPECT_TRUE(event_target);
+  EXPECT_EQ(event_target,
+            root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
+  EXPECT_EQ(event_target,
+            root->GetEventHandlerForPoint(gfx::Point(size.width() - 1, 0)));
+  EXPECT_EQ(event_target,
+            root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1)));
+  EXPECT_EQ(event_target,
+            root->GetEventHandlerForPoint(
+                gfx::Point(size.width() - 1, size.height() - 1)));
+}
+
 }  // namespace test
 }  // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 82f2b20..c0e5f77 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -60,6 +60,18 @@
 // keep the shelf from hiding.
 const int kNotificationBubbleGapHeight = 6;
 
+// The maximum size of the region on the display opposing the shelf managed by
+// this ShelfLayoutManager which can trigger showing the shelf.
+// For instance:
+// - Primary display is left of secondary display.
+// - Shelf is left aligned
+// - This ShelfLayoutManager manages the shelf for the secondary display.
+// |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region
+// from the right edge of the primary display which can trigger showing the
+// auto hidden shelf. The region is used to make it easier to trigger showing
+// the auto hidden shelf when the shelf is on the boundary between displays.
+const int kMaxAutoHideShowShelfRegionSize = 10;
+
 ui::Layer* GetLayer(views::Widget* widget) {
   return widget->GetNativeView()->layer();
 }
@@ -187,6 +199,7 @@
       shelf_(shelf),
       workspace_controller_(NULL),
       window_overlaps_shelf_(false),
+      mouse_over_shelf_when_auto_hide_timer_started_(false),
       bezel_event_filter_(new ShelfBezelEventFilter(this)),
       gesture_drag_status_(GESTURE_DRAG_NONE),
       gesture_drag_amount_(0.f),
@@ -332,14 +345,18 @@
       // Hides happen immediately.
       SetState(state_.visibility_state);
     } else {
-      auto_hide_timer_.Stop();
+      if (!auto_hide_timer_.IsRunning()) {
+        mouse_over_shelf_when_auto_hide_timer_started_ =
+            shelf_->GetWindowBoundsInScreen().Contains(
+                Shell::GetScreen()->GetCursorScreenPoint());
+      }
       auto_hide_timer_.Start(
           FROM_HERE,
           base::TimeDelta::FromMilliseconds(kAutoHideDelayMS),
           this, &ShelfLayoutManager::UpdateAutoHideStateNow);
     }
   } else {
-    auto_hide_timer_.Stop();
+    StopAutoHideTimer();
   }
 }
 
@@ -575,7 +592,7 @@
     auto_hide_event_filter_.reset(NULL);
   }
 
-  auto_hide_timer_.Stop();
+  StopAutoHideTimer();
 
   // The transition of background from auto-hide to visible is janky if the
   // transition also cause the shelf's slide animation from the bottom edge.
@@ -889,6 +906,34 @@
 
 void ShelfLayoutManager::UpdateAutoHideStateNow() {
   SetState(state_.visibility_state);
+
+  // If the state did not change, the auto hide timer may still be running.
+  StopAutoHideTimer();
+}
+
+void ShelfLayoutManager::StopAutoHideTimer() {
+  auto_hide_timer_.Stop();
+  mouse_over_shelf_when_auto_hide_timer_started_ = false;
+}
+
+gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const {
+  gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen();
+  gfx::Vector2d offset = SelectValueForShelfAlignment(
+      gfx::Vector2d(0, shelf_bounds_in_screen.height()),
+      gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0),
+      gfx::Vector2d(shelf_bounds_in_screen.width(), 0),
+      gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize));
+
+  gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen;
+  show_shelf_region_in_screen += offset;
+  if (IsHorizontalAlignment())
+    show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize);
+  else
+    show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize);
+
+  // TODO: Figure out if we need any special handling when the keyboard is
+  // visible.
+  return show_shelf_region_in_screen;
 }
 
 ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState(
@@ -936,9 +981,30 @@
                            -kNotificationBubbleGapHeight : 0);
   }
 
-  if (shelf_region.Contains(Shell::GetScreen()->GetCursorScreenPoint()))
+  gfx::Point cursor_position_in_screen =
+      Shell::GetScreen()->GetCursorScreenPoint();
+  if (shelf_region.Contains(cursor_position_in_screen))
     return SHELF_AUTO_HIDE_SHOWN;
 
+  // When the shelf is auto hidden and the shelf is on the boundary between two
+  // displays, it is hard to trigger showing the shelf. For instance, if a
+  // user's primary display is left of their secondary display, it is hard to
+  // unautohide a left aligned shelf on the secondary display.
+  // It is hard because:
+  // - It is hard to stop the cursor in the shelf "light bar" and not overshoot.
+  // - The cursor is warped to the other display if the cursor gets to the edge
+  //   of the display.
+  // Show the shelf if the cursor started on the shelf and the user overshot the
+  // shelf slightly to make it easier to show the shelf in this situation. We
+  // do not check |auto_hide_timer_|.IsRunning() because it returns false when
+  // the timer's task is running.
+  if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN ||
+       mouse_over_shelf_when_auto_hide_timer_started_) &&
+      GetAutoHideShowShelfRegionInScreen().Contains(
+          cursor_position_in_screen)) {
+    return SHELF_AUTO_HIDE_SHOWN;
+  }
+
   const std::vector<aura::Window*> windows =
       ash::MruWindowTracker::BuildWindowList(false);
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index ce69366..467fe1a 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -277,6 +277,16 @@
   // Updates the auto hide state immediately.
   void UpdateAutoHideStateNow();
 
+  // Stops the auto hide timer and clears
+  // |mouse_over_shelf_when_auto_hide_timer_started_|.
+  void StopAutoHideTimer();
+
+  // Returns the bounds of an additional region which can trigger showing the
+  // shelf. This region exists to make it easier to trigger showing the shelf
+  // when the shelf is auto hidden and the shelf is on the boundary between
+  // two displays.
+  gfx::Rect GetAutoHideShowShelfRegionInScreen() const;
+
   // Returns the AutoHideState. This value is determined from the launcher and
   // tray.
   ShelfAutoHideState CalculateAutoHideState(
@@ -330,6 +340,10 @@
 
   base::OneShotTimer<ShelfLayoutManager> auto_hide_timer_;
 
+  // Whether the mouse was over the shelf when the auto hide timer started.
+  // False when neither the auto hide timer nor the timer task are running.
+  bool mouse_over_shelf_when_auto_hide_timer_started_;
+
   // EventFilter used to detect when user moves the mouse over the launcher to
   // trigger showing the launcher.
   scoped_ptr<AutoHideEventFilter> auto_hide_event_filter_;
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 0a82ceb..2781e6c 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -7,6 +7,7 @@
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_table.h"
 #include "ash/ash_switches.h"
+#include "ash/display/display_controller.h"
 #include "ash/display/display_manager.h"
 #include "ash/focus_cycler.h"
 #include "ash/launcher/launcher.h"
@@ -777,6 +778,99 @@
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
 }
 
+// Test the behavior of the shelf when it is auto hidden and it is on the
+// boundary between the primary and the secondary display.
+TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnScreenBoundary) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  UpdateDisplay("800x600,800x600");
+  DisplayLayout display_layout(DisplayLayout::RIGHT, 0);
+  Shell::GetInstance()->display_controller()->SetLayoutForCurrentDisplays(
+      display_layout);
+  // Put the primary monitor's shelf on the display boundary.
+  ShelfLayoutManager* shelf = GetShelfLayoutManager();
+  shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT);
+
+  // Create a window because the shelf is always shown when no windows are
+  // visible.
+  CreateTestWidget();
+
+  Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
+  ASSERT_EQ(root_windows[0],
+            GetShelfWidget()->GetNativeWindow()->GetRootWindow());
+
+  shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+  EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state());
+
+  int right_edge = root_windows[0]->GetBoundsInScreen().right() - 1;
+  int y = root_windows[0]->GetBoundsInScreen().y();
+
+  // Start off the mouse nowhere near the shelf; the shelf should be hidden.
+  aura::test::EventGenerator& generator(GetEventGenerator());
+  generator.MoveMouseTo(right_edge - 50, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+
+  // Moving the mouse over the light bar (but not to the edge of the screen)
+  // should show the shelf.
+  generator.MoveMouseTo(right_edge - 1, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+  EXPECT_EQ(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x());
+
+  // Moving the mouse off the light bar should hide the shelf.
+  generator.MoveMouseTo(right_edge - 50, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+
+  // Moving the mouse to the right edge of the screen crossing the light bar
+  // should show the shelf despite the mouse cursor getting warped to the
+  // secondary display.
+  generator.MoveMouseTo(right_edge - 1, y);
+  generator.MoveMouseTo(right_edge, y);
+  UpdateAutoHideStateNow();
+  EXPECT_NE(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x());
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+
+  // Hide the shelf.
+  generator.MoveMouseTo(right_edge - 50, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+
+  // Moving the mouse to the right edge of the screen crossing the light bar and
+  // overshooting by a lot should keep the shelf hidden.
+  generator.MoveMouseTo(right_edge - 1, y);
+  generator.MoveMouseTo(right_edge + 50, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+
+  // Moving the mouse to the right edge of the screen crossing the light bar and
+  // overshooting a bit should show the shelf.
+  generator.MoveMouseTo(right_edge - 1, y);
+  generator.MoveMouseTo(right_edge + 2, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+
+  // Keeping the mouse close to the left edge of the secondary display after the
+  // shelf is shown should keep the shelf shown.
+  generator.MoveMouseTo(right_edge + 2, y + 1);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
+
+  // Moving the mouse far from the left edge of the secondary display should
+  // hide the shelf.
+  generator.MoveMouseTo(right_edge + 50, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+
+  // Moving to the left edge of the secondary display without first crossing
+  // the primary display's right aligned shelf first should not show the shelf.
+  generator.MoveMouseTo(right_edge + 2, y);
+  UpdateAutoHideStateNow();
+  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
+}
+
 // Assertions around the lock screen showing.
 TEST_F(ShelfLayoutManagerTest, VisibleWhenLockScreenShowing) {
   // Since ShelfLayoutManager queries for mouse location, move the mouse so
diff --git a/ash/shell.cc b/ash/shell.cc
index c7b4b1f..1bade43 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -675,13 +675,6 @@
   app_list_controller_->SetVisible(!app_list_controller_->IsVisible(), window);
 }
 
-void Shell::SetDragAndDropHostOfCurrentAppList(
-    app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
-  if (app_list_controller_.get())
-    app_list_controller_->SetDragAndDropHostOfCurrentAppList(
-        drag_and_drop_host);
-}
-
 bool Shell::GetAppListTargetVisibility() const {
   return app_list_controller_.get() &&
       app_list_controller_->GetTargetVisibility();
diff --git a/ash/shell.h b/ash/shell.h
index 237a1a8..c3adade 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -27,9 +27,6 @@
 
 class CommandLine;
 
-namespace app_list {
-class ApplicationDragAndDropHost;
-}
 namespace aura {
 class EventFilter;
 class RootWindow;
@@ -224,11 +221,6 @@
   // will be used.
   void ToggleAppList(aura::Window* anchor);
 
-  // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
-  // operations outside the application list.
-  void SetDragAndDropHostOfCurrentAppList(
-      app_list::ApplicationDragAndDropHost* drag_and_drop_host);
-
   // Returns app list target visibility.
   bool GetAppListTargetVisibility() const;
 
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 318873c..20d0a7f 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -231,16 +231,6 @@
 void ShellDelegateImpl::HandleMediaPrevTrack() {
 }
 
-base::string16 ShellDelegateImpl::GetTimeRemainingString(
-    base::TimeDelta delta) {
-  return base::string16();
-}
-
-base::string16 ShellDelegateImpl::GetTimeDurationLongString(
-    base::TimeDelta delta) {
-  return base::string16();
-}
-
 void ShellDelegateImpl::SaveScreenMagnifierScale(double scale) {
 }
 
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index c01b201..7a4e5d6 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -71,9 +71,6 @@
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) OVERRIDE;
-  virtual base::string16 GetTimeDurationLongString(
-      base::TimeDelta delta) OVERRIDE;
   virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
   virtual double GetSavedScreenMagnifierScale() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 2bf08c1..38164f2 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -12,7 +12,6 @@
 #include "ash/shell.h"
 #include "base/callback.h"
 #include "base/strings/string16.h"
-#include "base/time/time.h"
 
 namespace app_list {
 class AppListViewDelegate;
@@ -235,14 +234,6 @@
   // Handles the Previous Track Media shortcut key.
   virtual void HandleMediaPrevTrack() = 0;
 
-  // Produces l10n-ed text of remaining time, e.g.: "13 minutes left" or
-  // "13 Minuten links".
-  // Used, for example, to display the remaining battery life.
-  virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) = 0;
-
-  // Produces l10n-ed text for time duration, e.g.: "13 minutes" or "2 hours".
-  virtual base::string16 GetTimeDurationLongString(base::TimeDelta delta) = 0;
-
   // Saves the zoom scale of the full screen magnifier.
   virtual void SaveScreenMagnifierScale(double scale) = 0;
 
diff --git a/ash/system/chromeos/audio/tray_audio.cc b/ash/system/chromeos/audio/tray_audio.cc
index 20cc1ef..6ad4362 100644
--- a/ash/system/chromeos/audio/tray_audio.cc
+++ b/ash/system/chromeos/audio/tray_audio.cc
@@ -153,12 +153,12 @@
   BarSeparator() {}
   virtual ~BarSeparator() {}
 
- private:
   // Overriden from views::View.
   virtual gfx::Size GetPreferredSize() OVERRIDE {
     return gfx::Size(kBarSeparatorWidth, kBarSeparatorHeight);
   }
 
+ private:
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
     canvas->FillRect(gfx::Rect(width() / 2, 0, 1, height()),
                      kButtonStrokeColor);
@@ -189,12 +189,12 @@
     slider_ = new VolumeSlider(this);
     AddChildView(slider_);
 
-    device_type_ = new views::ImageView;
-    AddChildView(device_type_);
-
     bar_ = new BarSeparator;
     AddChildView(bar_);
 
+    device_type_ = new views::ImageView;
+    AddChildView(device_type_);
+
     more_ = new views::ImageView;
     more_->EnableCanvasFlippingForRTLUI(true);
     more_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
@@ -252,15 +252,14 @@
     if (!audio_handler->GetActiveOutputDevice(&device))
       return;
     int device_icon = GetAudioDeviceIconId(device.type);
+    bar_->SetVisible(show_more);
     if (device_icon != kNoAudioDeviceIcon) {
       device_type_->SetVisible(true);
       device_type_->SetImage(
           ui::ResourceBundle::GetSharedInstance().GetImageNamed(
               device_icon).ToImageSkia());
-      bar_->SetVisible(false);
     } else {
       device_type_->SetVisible(false);
-      bar_->SetVisible(show_more);
     }
   }
 
@@ -302,24 +301,33 @@
     bounds.set_y((height() - size.height()) / 2);
     more_->SetBoundsRect(bounds);
 
-    // Layout bar_ or device_type_ at the left of the more_ button.
+    // Layout either bar_ or device_type_ at the left of the more_ button.
     views::View* view_left_to_more;
-    if (bar_->visible())
-      view_left_to_more = bar_;
-    else
+    if (device_type_->visible())
       view_left_to_more = device_type_;
-    gfx::Size bar_size = view_left_to_more->GetPreferredSize();
-    gfx::Rect bar_bounds(bar_size);
-    bar_bounds.set_x(more_->bounds().x() - bar_size.width() -
+    else
+      view_left_to_more = bar_;
+    gfx::Size view_size = view_left_to_more->GetPreferredSize();
+    gfx::Rect view_bounds(view_size);
+    view_bounds.set_x(more_->bounds().x() - view_size.width() -
                      kExtraPaddingBetweenBarAndMore);
-    bar_bounds.set_y((height() - bar_size.height()) / 2);
-    view_left_to_more->SetBoundsRect(bar_bounds);
+    view_bounds.set_y((height() - view_size.height()) / 2);
+    view_left_to_more->SetBoundsRect(view_bounds);
 
+    // Layout vertical bar next to view_left_to_more if device_type_ is visible.
+    if (device_type_->visible()) {
+      gfx::Size bar_size = bar_->GetPreferredSize();
+      gfx::Rect bar_bounds(bar_size);
+      bar_bounds.set_x(view_left_to_more->bounds().x() - bar_size.width());
+      bar_bounds.set_y((height() - bar_size.height()) / 2);
+      bar_->SetBoundsRect(bar_bounds);
+    }
 
     // Layout slider, calculate slider width.
     gfx::Rect slider_bounds = slider_->bounds();
     slider_bounds.set_width(
-        view_left_to_more->bounds().x() - kTrayPopupPaddingBetweenItems
+        bar_->bounds().x()
+        - (device_type_->visible() ? 0 : kTrayPopupPaddingBetweenItems)
         - slider_bounds.x());
     slider_->SetBoundsRect(slider_bounds);
   }
diff --git a/ash/system/chromeos/power/power_status.cc b/ash/system/chromeos/power/power_status.cc
index a9f4dbf..0283a0c 100644
--- a/ash/system/chromeos/power/power_status.cc
+++ b/ash/system/chromeos/power/power_status.cc
@@ -17,6 +17,7 @@
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia_operations.h"
@@ -47,19 +48,15 @@
 base::string16 GetBatteryTimeAccessibilityString(int hour, int min) {
   DCHECK(hour || min);
   if (hour && !min) {
-    return Shell::GetInstance()->delegate()->GetTimeDurationLongString(
-        base::TimeDelta::FromHours(hour));
+    return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour));
   }
   if (min && !hour) {
-    return Shell::GetInstance()->delegate()->GetTimeDurationLongString(
-        base::TimeDelta::FromMinutes(min));
+    return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min));
   }
   return l10n_util::GetStringFUTF16(
       IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE,
-      Shell::GetInstance()->delegate()->GetTimeDurationLongString(
-          base::TimeDelta::FromHours(hour)),
-      Shell::GetInstance()->delegate()->GetTimeDurationLongString(
-          base::TimeDelta::FromMinutes(min)));
+      ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour)),
+      ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min)));
 }
 
 static PowerStatus* g_power_status = NULL;
diff --git a/ash/system/chromeos/power/power_status_view.cc b/ash/system/chromeos/power/power_status_view.cc
index a38d315..5323f5c 100644
--- a/ash/system/chromeos/power/power_status_view.cc
+++ b/ash/system/chromeos/power/power_status_view.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
@@ -193,13 +194,8 @@
     } else {
       // This is a low battery warning prompting the user in minutes.
       min = hour * 60 + min;
-      ShellDelegate* delegate = Shell::GetInstance()->delegate();
-      if (delegate) {
-        time_label_->SetText(delegate->GetTimeRemainingString(
-            base::TimeDelta::FromMinutes(min)));
-      } else {
-        time_label_->SetText(base::string16());
-      }
+      time_label_->SetText(ui::TimeFormat::TimeRemaining(
+          base::TimeDelta::FromMinutes(min)));
     }
   } else {
     time_label_->SetText(base::string16());
diff --git a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
index f375bf7..6563e4b 100644
--- a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
+++ b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc
@@ -8,9 +8,19 @@
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+
+using message_center::Notification;
 
 namespace ash {
 namespace internal {
+namespace {
+
+const char kScreenCaptureNotificationId[] = "chrome://screen/capture";
+
+}  // namespace
 
 ScreenCaptureTrayItem::ScreenCaptureTrayItem(SystemTray* system_tray)
     : ScreenTrayItem(system_tray) {
@@ -33,7 +43,6 @@
     user::LoginStatus status) {
   set_default_view(new tray::ScreenStatusView(
       this,
-      tray::ScreenStatusView::VIEW_DEFAULT,
       IDR_AURA_UBER_TRAY_DISPLAY,
       screen_capture_status_,
       l10n_util::GetStringUTF16(
@@ -41,15 +50,27 @@
   return default_view();
 }
 
-views::View* ScreenCaptureTrayItem::CreateNotificationView(
-    user::LoginStatus status) {
-  set_notification_view(new tray::ScreenNotificationView(
-      this,
-      IDR_AURA_UBER_TRAY_DISPLAY,
+void ScreenCaptureTrayItem::CreateOrUpdateNotification() {
+  message_center::RichNotificationData data;
+  data.buttons.push_back(message_center::ButtonInfo(
+      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP)));
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<Notification> notification(new Notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE,
+      kScreenCaptureNotificationId,
       screen_capture_status_,
-      l10n_util::GetStringUTF16(
-          IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP)));
-  return notification_view();
+      base::string16() /* body is blank */,
+      resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
+      base::string16() /* display_source */,
+      std::string() /* extension_id */,
+      data,
+      new tray::ScreenNotificationDelegate(this)));
+  notification->SetSystemPriority();
+  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
+}
+
+std::string ScreenCaptureTrayItem::GetNotificationId() {
+  return kScreenCaptureNotificationId;
 }
 
 void ScreenCaptureTrayItem::OnScreenCaptureStart(
diff --git a/ash/system/chromeos/screen_security/screen_capture_tray_item.h b/ash/system/chromeos/screen_security/screen_capture_tray_item.h
index f1fb4b5..92f6c8a 100644
--- a/ash/system/chromeos/screen_security/screen_capture_tray_item.h
+++ b/ash/system/chromeos/screen_security/screen_capture_tray_item.h
@@ -22,11 +22,13 @@
   virtual ~ScreenCaptureTrayItem();
 
  private:
-  // Overridden from ScreenTrayItem.
+  // Overridden from SystemTrayItem.
   virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
   virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
-  virtual views::View* CreateNotificationView(
-      user::LoginStatus status) OVERRIDE;
+
+  // Overridden from ScreenTrayItem.
+  virtual void CreateOrUpdateNotification() OVERRIDE;
+  virtual std::string GetNotificationId() OVERRIDE;
 
   // Overridden from ScreenCaptureObserver.
   virtual void OnScreenCaptureStart(
diff --git a/ash/system/chromeos/screen_security/screen_share_tray_item.cc b/ash/system/chromeos/screen_security/screen_share_tray_item.cc
index 3e10763..18dd317 100644
--- a/ash/system/chromeos/screen_security/screen_share_tray_item.cc
+++ b/ash/system/chromeos/screen_security/screen_share_tray_item.cc
@@ -8,9 +8,19 @@
 #include "grit/ash_resources.h"
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/notification.h"
+
+using message_center::Notification;
 
 namespace ash {
 namespace internal {
+namespace {
+
+const char kScreenShareNotificationId[] = "chrome://screen/share";
+
+}
 
 ScreenShareTrayItem::ScreenShareTrayItem(SystemTray* system_tray)
     : ScreenTrayItem(system_tray) {
@@ -32,7 +42,6 @@
 views::View* ScreenShareTrayItem::CreateDefaultView(user::LoginStatus status) {
   set_default_view(new tray::ScreenStatusView(
       this,
-      tray::ScreenStatusView::VIEW_DEFAULT,
       IDR_AURA_UBER_TRAY_DISPLAY,
       l10n_util::GetStringUTF16(
           IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED),
@@ -41,8 +50,7 @@
   return default_view();
 }
 
-views::View* ScreenShareTrayItem::CreateNotificationView(
-    user::LoginStatus status) {
+void ScreenShareTrayItem::CreateOrUpdateNotification() {
   base::string16 help_label_text;
   if (!helper_name_.empty()) {
     help_label_text = l10n_util::GetStringFUTF16(
@@ -53,13 +61,26 @@
         IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED);
   }
 
-  set_notification_view(new tray::ScreenNotificationView(
-      this,
-      IDR_AURA_UBER_TRAY_DISPLAY,
+  message_center::RichNotificationData data;
+  data.buttons.push_back(message_center::ButtonInfo(
+      l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP)));
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  scoped_ptr<Notification> notification(new Notification(
+      message_center::NOTIFICATION_TYPE_SIMPLE,
+      kScreenShareNotificationId,
       help_label_text,
-      l10n_util::GetStringUTF16(
-          IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP)));
-  return notification_view();
+      base::string16() /* body is blank */,
+      resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY),
+      base::string16() /* display_source */,
+      std::string() /* extension_id */,
+      data,
+      new tray::ScreenNotificationDelegate(this)));
+  notification->SetSystemPriority();
+  message_center::MessageCenter::Get()->AddNotification(notification.Pass());
+}
+
+std::string ScreenShareTrayItem::GetNotificationId() {
+  return kScreenShareNotificationId;
 }
 
 void ScreenShareTrayItem::OnScreenShareStart(
diff --git a/ash/system/chromeos/screen_security/screen_share_tray_item.h b/ash/system/chromeos/screen_security/screen_share_tray_item.h
index 4624ac2..14f26e5 100644
--- a/ash/system/chromeos/screen_security/screen_share_tray_item.h
+++ b/ash/system/chromeos/screen_security/screen_share_tray_item.h
@@ -25,8 +25,10 @@
   // Overridden from SystemTrayItem.
   virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE;
   virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE;
-  virtual views::View* CreateNotificationView(
-      user::LoginStatus status) OVERRIDE;
+
+  // Overridden from ScreenTrayItem.
+  virtual void CreateOrUpdateNotification() OVERRIDE;
+  virtual std::string GetNotificationId() OVERRIDE;
 
   // Overridden from ScreenShareObserver.
   virtual void OnScreenShareStart(
diff --git a/ash/system/chromeos/screen_security/screen_tray_item.cc b/ash/system/chromeos/screen_security/screen_tray_item.cc
index 8c845e7..4b10a27 100644
--- a/ash/system/chromeos/screen_security/screen_tray_item.cc
+++ b/ash/system/chromeos/screen_security/screen_tray_item.cc
@@ -7,14 +7,12 @@
 #include "ash/system/tray/fixed_sized_image_view.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/message_center/message_center.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 
 namespace {
-const int kStopButtonRightPaddingDefaultView = 18;
-const int kStopButtonRightPaddingNotificationView = 0;
-const int kStopButtonLeftPaddingNotificationView = 4;
-const int kVerticalPaddingScreenCaptureNotitification = 12;
+const int kStopButtonRightPadding = 18;
 }  // namespace
 
 namespace ash {
@@ -43,7 +41,6 @@
 
 // ScreenStatusView implementations.
 ScreenStatusView::ScreenStatusView(ScreenTrayItem* screen_tray_item,
-                                   ViewType view_type,
                                    int icon_id,
                                    const base::string16& label_text,
                                    const base::string16& stop_button_text)
@@ -51,7 +48,6 @@
       icon_(NULL),
       label_(NULL),
       stop_button_(NULL),
-      view_type_(view_type),
       icon_id_(icon_id),
       label_text_(label_text),
       stop_button_text_(stop_button_text) {
@@ -65,18 +61,10 @@
 void ScreenStatusView::Layout() {
   views::View::Layout();
 
-  int stop_button_right_padding =
-      view_type_ == VIEW_DEFAULT ?
-          kStopButtonRightPaddingDefaultView :
-          kStopButtonRightPaddingNotificationView;
-  int stop_button_left_padding =
-      view_type_ == VIEW_DEFAULT ?
-          kTrayPopupPaddingBetweenItems :
-          kStopButtonLeftPaddingNotificationView;
   // Give the stop button the space it requests.
   gfx::Size stop_size = stop_button_->GetPreferredSize();
   gfx::Rect stop_bounds(stop_size);
-  stop_bounds.set_x(width() - stop_size.width() - stop_button_right_padding);
+  stop_bounds.set_x(width() - stop_size.width() - kStopButtonRightPadding);
   stop_bounds.set_y((height() - stop_size.height()) / 2);
   stop_button_->SetBoundsRect(stop_bounds);
 
@@ -84,7 +72,7 @@
   if (label_->bounds().Intersects(stop_button_->bounds())) {
     gfx::Rect label_bounds = label_->bounds();
     label_bounds.set_width(
-        stop_button_->x() - stop_button_left_padding - label_->x());
+        stop_button_->x() - kTrayPopupPaddingBetweenItems - label_->x());
     label_->SetBoundsRect(label_bounds);
   }
 }
@@ -99,22 +87,13 @@
 void ScreenStatusView::CreateItems() {
   set_background(views::Background::CreateSolidBackground(kBackgroundColor));
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  if (view_type_ == VIEW_DEFAULT) {
-    SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
-                                          kTrayPopupPaddingHorizontal,
-                                          0,
-                                          kTrayPopupPaddingBetweenItems));
-    icon_ = new FixedSizedImageView(0, kTrayPopupItemHeight);
-    icon_->SetImage(bundle.GetImageNamed(icon_id_).ToImageSkia());
-    AddChildView(icon_);
-  } else {
-    SetLayoutManager(
-        new views::BoxLayout(views::BoxLayout::kHorizontal,
-                             0,
-                             kVerticalPaddingScreenCaptureNotitification,
-                             0));
-  }
-
+  SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal,
+                                        kTrayPopupPaddingHorizontal,
+                                        0,
+                                        kTrayPopupPaddingBetweenItems));
+  icon_ = new FixedSizedImageView(0, kTrayPopupItemHeight);
+  icon_->SetImage(bundle.GetImageNamed(icon_id_).ToImageSkia());
+  AddChildView(icon_);
   label_ = new views::Label;
   label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   label_->SetMultiLine(true);
@@ -126,40 +105,34 @@
 }
 
 void ScreenStatusView::Update() {
-  if (view_type_ == VIEW_DEFAULT) {
-    // Hide the notification bubble when the ash tray bubble opens.
-    screen_tray_item_->HideNotificationView();
-    SetVisible(screen_tray_item_->is_started());
-  }
+  // Hide the notification bubble when the ash tray bubble opens.
+  screen_tray_item_->HideNotificationView();
+  SetVisible(screen_tray_item_->is_started());
 }
 
-
-// ScreenNotificationView implementations.
-ScreenNotificationView::ScreenNotificationView(
-    ScreenTrayItem* screen_tray_item,
-    int icon_id,
-    const base::string16& label_text,
-    const base::string16& stop_button_text)
-        : TrayNotificationView(screen_tray_item, icon_id),
-          screen_tray_item_(screen_tray_item) {
-  screen_status_view_ = new ScreenStatusView(
-      screen_tray_item,
-      ScreenStatusView::VIEW_NOTIFICATION,
-      icon_id,
-      label_text,
-      stop_button_text);
-  InitView(screen_status_view_);
-  Update();
+ScreenNotificationDelegate::ScreenNotificationDelegate(
+    ScreenTrayItem* screen_tray)
+  : screen_tray_(screen_tray) {
 }
 
-ScreenNotificationView::~ScreenNotificationView() {
+ScreenNotificationDelegate::~ScreenNotificationDelegate() {
 }
 
-void ScreenNotificationView::Update() {
-  if (screen_tray_item_->is_started())
-    screen_status_view_->Update();
-  else
-    screen_tray_item_->HideNotificationView();
+void ScreenNotificationDelegate::Display() {
+}
+
+void ScreenNotificationDelegate::Error() {
+}
+
+void ScreenNotificationDelegate::Close(bool by_user) {
+}
+
+void ScreenNotificationDelegate::Click() {
+}
+
+void ScreenNotificationDelegate::ButtonClick(int button_index) {
+  DCHECK_EQ(0, button_index);
+  screen_tray_->Stop();
 }
 
 }  // namespace tray
@@ -168,7 +141,6 @@
     : SystemTrayItem(system_tray),
       tray_view_(NULL),
       default_view_(NULL),
-      notification_view_(NULL),
       is_started_(false),
       stop_callback_(base::Bind(&base::DoNothing)) {
 }
@@ -180,8 +152,12 @@
     tray_view_->Update();
   if (default_view_)
     default_view_->Update();
-  if (notification_view_)
-    notification_view_->Update();
+  if (is_started_) {
+    CreateOrUpdateNotification();
+  } else {
+    message_center::MessageCenter::Get()->RemoveNotification(
+        GetNotificationId(), false /* by_user */);
+  }
 }
 
 void ScreenTrayItem::Start(const base::Closure& stop_callback) {
@@ -196,7 +172,7 @@
 
   if (!system_tray()->HasSystemBubbleType(
       SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) {
-    ShowNotificationView();
+    CreateOrUpdateNotification();
   }
 }
 
@@ -220,9 +196,5 @@
   default_view_ = NULL;
 }
 
-void ScreenTrayItem::DestroyNotificationView() {
-  notification_view_ = NULL;
-}
-
 }  // namespace internal
 }  // namespace ash
diff --git a/ash/system/chromeos/screen_security/screen_tray_item.h b/ash/system/chromeos/screen_security/screen_tray_item.h
index 03b8435..f078a39 100644
--- a/ash/system/chromeos/screen_security/screen_tray_item.h
+++ b/ash/system/chromeos/screen_security/screen_tray_item.h
@@ -11,6 +11,7 @@
 #include "ash/system/tray/tray_item_view.h"
 #include "ash/system/tray/tray_notification_view.h"
 #include "ash/system/tray/tray_popup_label_button.h"
+#include "ui/message_center/notification_delegate.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/image_view.h"
 
@@ -41,13 +42,7 @@
 class ScreenStatusView : public views::View,
                          public views::ButtonListener {
  public:
-  enum ViewType {
-      VIEW_DEFAULT,
-      VIEW_NOTIFICATION
-  };
-
   ScreenStatusView(ScreenTrayItem* screen_tray_item,
-                   ViewType view_type,
                    int icon_id,
                    const base::string16& label_text,
                    const base::string16& stop_button_text);
@@ -68,7 +63,6 @@
   views::ImageView* icon_;
   views::Label* label_;
   TrayPopupLabelButton* stop_button_;
-  ViewType view_type_;
   int icon_id_;
   base::string16 label_text_;
   base::string16 stop_button_text_;
@@ -76,21 +70,24 @@
   DISALLOW_COPY_AND_ASSIGN(ScreenStatusView);
 };
 
-class ScreenNotificationView : public TrayNotificationView {
+class ScreenNotificationDelegate : public message_center::NotificationDelegate {
  public:
-  ScreenNotificationView(ScreenTrayItem* screen_tray_item,
-                         int icon_id,
-                         const base::string16& label_text,
-                         const base::string16& stop_button_text);
-  virtual ~ScreenNotificationView();
+  explicit ScreenNotificationDelegate(ScreenTrayItem* screen_tray);
 
-  void Update();
+  // message_center::NotificationDelegate overrides:
+  virtual void Display() OVERRIDE;
+  virtual void Error() OVERRIDE;
+  virtual void Close(bool by_user) OVERRIDE;
+  virtual void Click() OVERRIDE;
+  virtual void ButtonClick(int button_index) OVERRIDE;
+
+ protected:
+  virtual ~ScreenNotificationDelegate();
 
  private:
-  ScreenTrayItem* screen_tray_item_;
-  ScreenStatusView* screen_status_view_;
+  ScreenTrayItem* screen_tray_;
 
-  DISALLOW_COPY_AND_ASSIGN(ScreenNotificationView);
+  DISALLOW_COPY_AND_ASSIGN(ScreenNotificationDelegate);
 };
 
 }  // namespace tray
@@ -114,13 +111,6 @@
     default_view_ = default_view;
   }
 
-  tray::ScreenNotificationView* notification_view() {
-    return notification_view_;
-  }
-  void set_notification_view(tray::ScreenNotificationView* notification_view) {
-    notification_view_ = notification_view;
-  }
-
   bool is_started() const { return is_started_; }
   void set_is_started(bool is_started) { is_started_ = is_started; }
 
@@ -128,20 +118,21 @@
   void Start(const base::Closure& stop_callback);
   void Stop();
 
+  // Creates or updates the notification for the tray item.
+  virtual void CreateOrUpdateNotification() = 0;
+
+  // Returns the id of the notification for the tray item.
+  virtual std::string GetNotificationId() = 0;
+
   // Overridden from SystemTrayItem.
   virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE = 0;
   virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE = 0;
-  virtual views::View* CreateNotificationView(
-      user::LoginStatus status) OVERRIDE = 0;
-
   virtual void DestroyTrayView() OVERRIDE;
   virtual void DestroyDefaultView() OVERRIDE;
-  virtual void DestroyNotificationView() OVERRIDE;
 
  private:
   tray::ScreenTrayView* tray_view_;
   tray::ScreenStatusView* default_view_;
-  tray::ScreenNotificationView* notification_view_;
   bool is_started_;
   base::Closure stop_callback_;
 
diff --git a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
index d95bed9..e51a91f 100644
--- a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
+++ b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ui/base/events/event.h"
 #include "ui/gfx/point.h"
+#include "ui/message_center/message_center.h"
 #include "ui/views/view.h"
 
 namespace ash {
@@ -177,12 +178,9 @@
   ScreenTrayItem* tray_item = test->tray_item();
 
   test->StartSession();
-  EXPECT_TRUE(tray_item->notification_view()->visible());
-
-  // Clicking on the notification view should dismiss the view
-  ClickViewCenter(tray_item->notification_view());
-  EXPECT_FALSE(tray_item->notification_view());
-
+  message_center::MessageCenter* message_center =
+      message_center::MessageCenter::Get();
+  EXPECT_TRUE(message_center->HasNotification(tray_item->GetNotificationId()));
   test->StopSession();
 }
 
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index 85ba7ae..2b0b32a 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -84,7 +84,8 @@
 
 AshTestBase::AshTestBase()
     : setup_called_(false),
-      teardown_called_(false) {
+      teardown_called_(false),
+      start_session_(true) {
   // Must initialize |ash_test_helper_| here because some tests rely on
   // AshTestBase methods before they call AshTestBase::SetUp().
   ash_test_helper_.reset(new AshTestHelper(base::MessageLoopForUI::current()));
@@ -109,7 +110,7 @@
 #endif
   ui::InitializeInputMethodForTesting();
 
-  ash_test_helper_->SetUp();
+  ash_test_helper_->SetUp(start_session_);
 
   Shell::GetPrimaryRootWindow()->Show();
   Shell::GetPrimaryRootWindow()->ShowRootWindow();
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index c0567be..5e8fdd2 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -110,6 +110,8 @@
   // or false otherwise (e.g. win8 bot).
   static bool SupportsHostWindowResize();
 
+  void set_start_session(bool start_session) { start_session_ = start_session; }
+
   void RunAllPendingInMessageLoop();
 
   // Utility methods to emulate user logged in or not, session started or not
@@ -127,6 +129,8 @@
  private:
   bool setup_called_;
   bool teardown_called_;
+  // |SetUp()| doesn't activate session if this is set to false.
+  bool start_session_;
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<AshTestHelper> ash_test_helper_;
   scoped_ptr<aura::test::EventGenerator> event_generator_;
@@ -141,6 +145,17 @@
   DISALLOW_COPY_AND_ASSIGN(AshTestBase);
 };
 
+class NoSessionAshTestBase : public AshTestBase {
+ public:
+  NoSessionAshTestBase() {
+    set_start_session(false);
+  }
+  virtual ~NoSessionAshTestBase() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NoSessionAshTestBase);
+};
+
 }  // namespace test
 }  // namespace ash
 
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 1d8c7d1..45a1740 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -39,7 +39,7 @@
 AshTestHelper::~AshTestHelper() {
 }
 
-void AshTestHelper::SetUp() {
+void AshTestHelper::SetUp(bool start_session) {
   // Disable animations during tests.
   zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
@@ -60,9 +60,12 @@
 
   ash::Shell::CreateInstance(test_shell_delegate_);
   Shell* shell = Shell::GetInstance();
-  test_shell_delegate_->test_session_state_delegate()->
-      SetActiveUserSessionStarted(true);
-  test_shell_delegate_->test_session_state_delegate()->SetHasActiveUser(true);
+  if (start_session) {
+    test_shell_delegate_->test_session_state_delegate()->
+        SetActiveUserSessionStarted(true);
+    test_shell_delegate_->test_session_state_delegate()->
+        SetHasActiveUser(true);
+  }
 
   test::DisplayManagerTestApi(shell->display_manager()).
       DisableChangeDisplayUponHostResize();
diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h
index 669ec29..f4d7706 100644
--- a/ash/test/ash_test_helper.h
+++ b/ash/test/ash_test_helper.h
@@ -33,7 +33,9 @@
   ~AshTestHelper();
 
   // Creates the ash::Shell and performs associated initialization.
-  void SetUp();
+  // Set |start_session| to true if the user should log in before
+  // the test is run.
+  void SetUp(bool start_session);
 
   // Destroys the ash::Shell and performs associated cleanup.
   void TearDown();
diff --git a/ash/test/ash_test_helper_unittest.cc b/ash/test/ash_test_helper_unittest.cc
index fdb27f9..0de950f 100644
--- a/ash/test/ash_test_helper_unittest.cc
+++ b/ash/test/ash_test_helper_unittest.cc
@@ -18,7 +18,7 @@
   virtual void SetUp() OVERRIDE {
     testing::Test::SetUp();
     ash_test_helper_.reset(new ash::test::AshTestHelper(&message_loop_));
-    ash_test_helper_->SetUp();
+    ash_test_helper_->SetUp(true);
   }
 
   virtual void TearDown() OVERRIDE {
diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc
index 532876e..9b51e6a 100644
--- a/ash/test/test_shell_delegate.cc
+++ b/ash/test/test_shell_delegate.cc
@@ -191,16 +191,6 @@
 void TestShellDelegate::HandleMediaPrevTrack() {
 }
 
-base::string16 TestShellDelegate::GetTimeRemainingString(
-    base::TimeDelta delta) {
-  return base::string16();
-}
-
-base::string16 TestShellDelegate::GetTimeDurationLongString(
-    base::TimeDelta delta) {
-  return base::string16();
-}
-
 void TestShellDelegate::SaveScreenMagnifierScale(double scale) {
 }
 
diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h
index b8a618b..dc8875b 100644
--- a/ash/test/test_shell_delegate.h
+++ b/ash/test/test_shell_delegate.h
@@ -74,9 +74,6 @@
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) OVERRIDE;
-  virtual base::string16 GetTimeDurationLongString(
-      base::TimeDelta delta) OVERRIDE;
   virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
   virtual double GetSavedScreenMagnifierScale() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root) OVERRIDE;
diff --git a/ash/wm/app_list_controller.cc b/ash/wm/app_list_controller.cc
index 45a6bcf..ea5e4f4 100644
--- a/ash/wm/app_list_controller.cc
+++ b/ash/wm/app_list_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/shell_delegate.h"
 #include "ash/shell_window_ids.h"
 #include "ash/wm/property_util.h"
+#include "base/command_line.h"
 #include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/pagination_model.h"
 #include "ui/app_list/views/app_list_view.h"
@@ -192,6 +193,13 @@
           true /* border_accepts_events */);
     }
     SetView(view);
+    // By setting us as DnD recipient, the app list knows that we can
+    // handle items.
+    if (!CommandLine::ForCurrentProcess()->HasSwitch(
+            ash::switches::kAshDisableDragAndDropAppListToLauncher)) {
+      SetDragAndDropHostOfCurrentAppList(
+          Launcher::ForWindow(window)->GetDragAndDropHostForAppList());
+    }
   }
 }
 
@@ -203,15 +211,15 @@
   return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL;
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// AppListController, private:
+
 void AppListController::SetDragAndDropHostOfCurrentAppList(
     app_list::ApplicationDragAndDropHost* drag_and_drop_host) {
   if (view_ && is_visible_)
     view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// AppListController, private:
-
 void AppListController::SetView(app_list::AppListView* view) {
   DCHECK(view_ == NULL);
   DCHECK(is_visible_);
diff --git a/ash/wm/app_list_controller.h b/ash/wm/app_list_controller.h
index 8aa7e30..b2c7961 100644
--- a/ash/wm/app_list_controller.h
+++ b/ash/wm/app_list_controller.h
@@ -62,12 +62,12 @@
   // Returns app list window or NULL if it is not visible.
   aura::Window* GetWindow();
 
+ private:
   // If |drag_and_drop_host| is not NULL it will be called upon drag and drop
   // operations outside the application list.
   void SetDragAndDropHostOfCurrentAppList(
       app_list::ApplicationDragAndDropHost* drag_and_drop_host);
 
- private:
   // Sets the app list view and attempts to show it.
   void SetView(app_list::AppListView* view);
 
diff --git a/ash/wm/base_layout_manager.cc b/ash/wm/base_layout_manager.cc
index 10f8311..6842f3e 100644
--- a/ash/wm/base_layout_manager.cc
+++ b/ash/wm/base_layout_manager.cc
@@ -107,7 +107,8 @@
 // BaseLayoutManager, ash::ShellObserver overrides:
 
 void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() {
-  AdjustWindowSizesForScreenChange(ADJUST_WINDOW_DISPLAY_INSETS_CHANGED);
+  AdjustAllWindowsBoundsForWorkAreaChange(
+      ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED);
 }
 
 /////////////////////////////////////////////////////////////////////////////
@@ -145,7 +146,7 @@
                                               const gfx::Rect& old_bounds,
                                               const gfx::Rect& new_bounds) {
   if (root_window_ == window)
-    AdjustWindowSizesForScreenChange(ADJUST_WINDOW_SCREEN_SIZE_CHANGED);
+    AdjustAllWindowsBoundsForWorkAreaChange(ADJUST_WINDOW_DISPLAY_SIZE_CHANGED);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -192,12 +193,12 @@
   }
 }
 
-void BaseLayoutManager::AdjustWindowSizesForScreenChange(
+void BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(
     AdjustWindowReason reason) {
   // Don't do any adjustments of the insets while we are in screen locked mode.
   // This would happen if the launcher was auto hidden before the login screen
   // was shown and then gets shown when the login screen gets presented.
-  if (reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED &&
+  if (reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED &&
       Shell::GetInstance()->session_state_delegate()->IsScreenLocked())
     return;
 
@@ -209,11 +210,11 @@
   for (WindowSet::const_iterator it = windows_.begin();
        it != windows_.end();
        ++it) {
-    AdjustWindowSizeForScreenChange(*it, reason);
+    AdjustWindowBoundsForWorkAreaChange(*it, reason);
   }
 }
 
-void BaseLayoutManager::AdjustWindowSizeForScreenChange(
+void BaseLayoutManager::AdjustWindowBoundsForWorkAreaChange(
     aura::Window* window,
     AdjustWindowReason reason) {
   if (wm::IsWindowMaximized(window)) {
diff --git a/ash/wm/base_layout_manager.h b/ash/wm/base_layout_manager.h
index 7fe25e5..0fc2b36 100644
--- a/ash/wm/base_layout_manager.h
+++ b/ash/wm/base_layout_manager.h
@@ -77,27 +77,29 @@
 
  protected:
   enum AdjustWindowReason {
-    ADJUST_WINDOW_SCREEN_SIZE_CHANGED,
-    ADJUST_WINDOW_DISPLAY_INSETS_CHANGED,
-    ADJUST_WINDOW_WINDOW_ADDED
+    ADJUST_WINDOW_DISPLAY_SIZE_CHANGED,
+    ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED,
   };
 
   // Invoked from OnWindowPropertyChanged() if |kShowStateKey| changes.
   virtual void ShowStateChanged(aura::Window* window,
                                 ui::WindowShowState last_show_state);
 
-  // Adjusts the window sizes when the screen changes its size or its
-  // work area insets. If this is called for a screen size change (i.e. |reason|
-  // is ADJUST_WINDOW_SCREEN_SIZE_CHANGED), the non-maximized/non-fullscreen
+  // Adjusts the window's bounds when the display area changes for given
+  // window. This happens when the display size, work area insets or
+  // the display on which the window exists has changed.
+  // If this is called for a display size change (i.e. |reason|
+  // is ADJUST_WINDOW_DISPLAY_SIZE_CHANGED), the non-maximized/non-fullscreen
   // windows are readjusted to make sure the window is completely within the
   // display region. Otherwise, it makes sure at least some parts of the window
   // is on display.
-  virtual void AdjustWindowSizesForScreenChange(AdjustWindowReason reason);
+  virtual void AdjustAllWindowsBoundsForWorkAreaChange(
+      AdjustWindowReason reason);
 
   // Adjusts the sizes of the specific window in respond to a screen change or
   // display-area size change.
-  virtual void AdjustWindowSizeForScreenChange(aura::Window* window,
-                                               AdjustWindowReason reason);
+  virtual void AdjustWindowBoundsForWorkAreaChange(aura::Window* window,
+                                                   AdjustWindowReason reason);
 
   aura::RootWindow* root_window() { return root_window_; }
 
diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc
index d9d1c07..d73a0cc 100644
--- a/ash/wm/dock/docked_window_layout_manager.cc
+++ b/ash/wm/dock/docked_window_layout_manager.cc
@@ -15,6 +15,7 @@
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/auto_reset.h"
+#include "third_party/skia/include/core/SkColor.h"
 #include "ui/aura/client/activation_client.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/focus_manager.h"
@@ -33,6 +34,39 @@
 
 namespace {
 
+const SkColor kDockBackgroundColor = SkColorSetARGB(0xff, 0x10, 0x10, 0x10);
+const float kDockBackgroundOpacity = 0.5f;
+
+class DockedBackgroundWidget : public views::Widget {
+ public:
+  explicit DockedBackgroundWidget(aura::Window* container) {
+    InitWidget(container);
+  }
+
+ private:
+  void InitWidget(aura::Window* parent) {
+    views::Widget::InitParams params;
+    params.type = views::Widget::InitParams::TYPE_POPUP;
+    params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
+    params.can_activate = false;
+    params.keep_on_top = false;
+    params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+    params.parent = parent;
+    params.accept_events = false;
+    set_focus_on_creation(false);
+    Init(params);
+    DCHECK_EQ(GetNativeView()->GetRootWindow(), parent->GetRootWindow());
+    views::View* content_view = new views::View;
+    content_view->set_background(
+        views::Background::CreateSolidBackground(kDockBackgroundColor));
+    SetContentsView(content_view);
+    GetNativeWindow()->layer()->SetOpacity(kDockBackgroundOpacity);
+    Hide();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DockedBackgroundWidget);
+};
+
 DockedWindowLayoutManager* GetDockLayoutManager(aura::Window* window,
                                                 const gfx::Point& location) {
   gfx::Rect near_location(location, gfx::Size());
@@ -69,7 +103,8 @@
       shelf_hidden_(false),
       docked_width_(0),
       alignment_(DOCKED_ALIGNMENT_NONE),
-      last_active_window_(NULL) {
+      last_active_window_(NULL),
+      background_widget_(new DockedBackgroundWidget(dock_container_)) {
   DCHECK(dock_container);
   aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())->
       AddObserver(this);
@@ -546,6 +581,17 @@
       DockedWindowLayoutManagerObserver,
       observer_list_,
       OnDockBoundsChanging(bounds));
+
+  // Show or hide background for docked area.
+  gfx::Rect background_bounds(docked_bounds_);
+  const gfx::Rect work_area =
+      Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area();
+  background_bounds.set_height(work_area.height());
+  background_widget_->SetBounds(background_bounds);
+  if (docked_width_ > 0)
+    background_widget_->Show();
+  else
+    background_widget_->Hide();
 }
 
 void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) {
@@ -571,13 +617,15 @@
   for (aura::Window::Windows::const_iterator it =
            dock_container_->children().begin();
        it != dock_container_->children().end(); ++it) {
+    if (!IsUsedByLayout(*it))
+      continue;
     gfx::Rect bounds = (*it)->bounds();
     window_ordering.insert(std::make_pair(bounds.y() + bounds.height() / 2,
                                           *it));
   }
   int active_center_y = active_window->bounds().CenterPoint().y();
 
-  aura::Window* previous_window = NULL;
+  aura::Window* previous_window = background_widget_->GetNativeWindow();
   for (std::map<int, aura::Window*>::const_iterator it =
        window_ordering.begin();
        it != window_ordering.end() && it->first < active_center_y; ++it) {
diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h
index 28c81fc..aa02b34 100644
--- a/ash/wm/dock/docked_window_layout_manager.h
+++ b/ash/wm/dock/docked_window_layout_manager.h
@@ -13,6 +13,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/observer_list.h"
 #include "ui/aura/client/activation_change_observer.h"
 #include "ui/aura/layout_manager.h"
@@ -28,6 +29,10 @@
 class Point;
 }
 
+namespace views {
+class Widget;
+}
+
 namespace ash {
 class Launcher;
 
@@ -182,6 +187,9 @@
   // are currently focused.
   aura::Window* last_active_window_;
 
+  // Widget used to paint a background for the docked area.
+  scoped_ptr<views::Widget> background_widget_;
+
   // Observers of dock bounds changes.
   ObserverList<DockedWindowLayoutManagerObserver> observer_list_;
 
diff --git a/ash/wm/property_util.h b/ash/wm/property_util.h
index adb983d..32ae278 100644
--- a/ash/wm/property_util.h
+++ b/ash/wm/property_util.h
@@ -24,7 +24,7 @@
 // Sets the restore bounds property on |window| in the virtual screen
 // coordinates.  Deletes existing bounds value if exists.
 ASH_EXPORT void SetRestoreBoundsInScreen(aura::Window* window,
-                                       const gfx::Rect& screen_bounds);
+                                         const gfx::Rect& screen_bounds);
 // Same as |SetRestoreBoundsInScreen| except that the bounds is in the
 // parent's coordinates.
 ASH_EXPORT void SetRestoreBoundsInParent(aura::Window* window,
diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc
index f11b3bc..67dcd95 100644
--- a/ash/wm/window_util.cc
+++ b/ash/wm/window_util.cc
@@ -173,21 +173,19 @@
                                           gfx::Rect* bounds) {
   bounds->set_width(std::min(bounds->width(), work_area.width()));
   bounds->set_height(std::min(bounds->height(), work_area.height()));
-  if (!work_area.Intersects(*bounds)) {
-    int y_offset = 0;
-    if (work_area.bottom() < bounds->y()) {
-      y_offset = work_area.bottom() - bounds->y() - min_height;
-    } else if (bounds->bottom() < work_area.y()) {
-      y_offset = work_area.y() - bounds->bottom() + min_height;
-    }
 
-    int x_offset = 0;
-    if (work_area.right() < bounds->x()) {
-      x_offset = work_area.right() - bounds->x() - min_width;
-    } else if (bounds->right() < work_area.x()) {
-      x_offset = work_area.x() - bounds->right() + min_width;
-    }
-    bounds->Offset(x_offset, y_offset);
+  min_width = std::min(min_width, work_area.width());
+  min_height = std::min(min_height, work_area.height());
+
+  if (bounds->x() + min_width > work_area.right()) {
+    bounds->set_x(work_area.right() - min_width);
+  } else if (bounds->right() - min_width < 0) {
+    bounds->set_x(min_width - bounds->width());
+  }
+  if (bounds->y() + min_height > work_area.bottom()) {
+    bounds->set_y(work_area.bottom() - min_height);
+  } else if (bounds->bottom() - min_height < 0) {
+    bounds->set_y(min_height - bounds->height());
   }
 }
 
diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc
index f970385..e592ad5 100644
--- a/ash/wm/workspace/workspace_event_handler_unittest.cc
+++ b/ash/wm/workspace/workspace_event_handler_unittest.cc
@@ -248,20 +248,21 @@
 
 TEST_F(WorkspaceEventHandlerTest, DoubleClickCaptionTogglesMaximize) {
   aura::test::TestWindowDelegate wd;
-  scoped_ptr<aura::Window> window(CreateTestWindow(&wd, gfx::Rect(1, 2, 3, 4)));
+  scoped_ptr<aura::Window> window(
+      CreateTestWindow(&wd, gfx::Rect(1, 2, 30, 40)));
   window->SetProperty(aura::client::kCanMaximizeKey, true);
   wd.set_window_component(HTCAPTION);
   EXPECT_FALSE(wm::IsWindowMaximized(window.get()));
   aura::RootWindow* root = Shell::GetPrimaryRootWindow();
   aura::test::EventGenerator generator(root, window.get());
   generator.DoubleClickLeftButton();
-  EXPECT_NE("1,2 3x4", window->bounds().ToString());
+  EXPECT_NE("1,2 30x40", window->bounds().ToString());
 
   EXPECT_TRUE(wm::IsWindowMaximized(window.get()));
   generator.DoubleClickLeftButton();
 
   EXPECT_FALSE(wm::IsWindowMaximized(window.get()));
-  EXPECT_EQ("1,2 3x4", window->bounds().ToString());
+  EXPECT_EQ("1,2 30x40", window->bounds().ToString());
 
   // Double-clicking the middle button shouldn't toggle the maximized state.
   WindowPropertyObserver observer(window.get());
@@ -275,7 +276,7 @@
   root->AsRootWindowHostDelegate()->OnHostMouseEvent(&release);
 
   EXPECT_FALSE(wm::IsWindowMaximized(window.get()));
-  EXPECT_EQ("1,2 3x4", window->bounds().ToString());
+  EXPECT_EQ("1,2 30x40", window->bounds().ToString());
   EXPECT_FALSE(observer.DidPropertyChange(aura::client::kShowStateKey));
 }
 
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 21aa08c..2fd56af 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -32,9 +32,9 @@
 
 namespace {
 
-// This specifies how much percent (2/3=66%) of a window must be visible when
-// the window is added to the workspace.
-const float kMinimumPercentOnScreenArea = 0.66f;
+// This specifies how much percent 30% of a window rect (width / height)
+// must be visible when the window is added to the workspace.
+const float kMinimumPercentOnScreenArea = 0.3f;
 
 bool IsMaximizedState(ui::WindowShowState state) {
   return state == ui::SHOW_STATE_MAXIMIZED ||
@@ -59,8 +59,14 @@
 }
 
 void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) {
-  // Adjust window bounds in case that the new child is out of the workspace.
-  AdjustWindowSizeForScreenChange(child, ADJUST_WINDOW_WINDOW_ADDED);
+  // Adjust window bounds in case that the new child is given the bounds that
+  // is out of the workspace. Exclude the case where bounds is empty
+  // (this happens when a views::Widget is created), or the window
+  // is added with the bounds because a user explicitly moved to
+  // this position (drag and drop for example).
+  if (!child->bounds().IsEmpty() &&
+      !wm::HasUserChangedWindowPositionOrSize(child))
+    AdjustWindowBoundsWhenAdded(child);
   BaseLayoutManager::OnWindowAddedToLayout(child);
   UpdateDesktopVisibility();
   RearrangeVisibleWindowOnShow(child);
@@ -110,8 +116,10 @@
 void WorkspaceLayoutManager::OnDisplayWorkAreaInsetsChanged() {
   const gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
       window_->parent()));
-  if (work_area != work_area_)
-    AdjustWindowSizesForScreenChange(ADJUST_WINDOW_DISPLAY_INSETS_CHANGED);
+  if (work_area != work_area_) {
+    AdjustAllWindowsBoundsForWorkAreaChange(
+        ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED);
+  }
 }
 
 void WorkspaceLayoutManager::OnWindowPropertyChanged(Window* window,
@@ -170,13 +178,13 @@
   UpdateDesktopVisibility();
 }
 
-void WorkspaceLayoutManager::AdjustWindowSizesForScreenChange(
+void WorkspaceLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(
     AdjustWindowReason reason) {
   work_area_ = ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_->parent());
-  BaseLayoutManager::AdjustWindowSizesForScreenChange(reason);
+  BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(reason);
 }
 
-void WorkspaceLayoutManager::AdjustWindowSizeForScreenChange(
+void WorkspaceLayoutManager::AdjustWindowBoundsForWorkAreaChange(
     Window* window,
     AdjustWindowReason reason) {
   if (!GetTrackedByWorkspace(window))
@@ -190,7 +198,7 @@
   // cross fade. I think this is better, but should reconsider if someone
   // raises voice for this.
   if (wm::IsWindowMaximized(window) &&
-      reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED) {
+      reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED) {
     CrossFadeToBounds(window, ScreenAsh::GetMaximizedWindowBoundsInParent(
         window->parent()->parent()));
     return;
@@ -200,22 +208,38 @@
     return;
 
   gfx::Rect bounds = window->bounds();
-  if (reason == ADJUST_WINDOW_SCREEN_SIZE_CHANGED) {
-    // The work area may be smaller than the full screen.  Put as much of the
-    // window as possible within the display area.
-    bounds.AdjustToFit(work_area_);
-  } else if (reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED) {
-    ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_, &bounds);
-  } else if (reason == ADJUST_WINDOW_WINDOW_ADDED) {
-    int min_width = bounds.width() * kMinimumPercentOnScreenArea;
-    int min_height = bounds.height() * kMinimumPercentOnScreenArea;
-    ash::wm::AdjustBoundsToEnsureWindowVisibility(
-        work_area_, min_width, min_height, &bounds);
+  switch (reason) {
+    case ADJUST_WINDOW_DISPLAY_SIZE_CHANGED:
+      // The work area may be smaller than the full screen.  Put as much of the
+      // window as possible within the display area.
+      bounds.AdjustToFit(work_area_);
+      break;
+    case ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED:
+      ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_, &bounds);
+      break;
   }
   if (window->bounds() != bounds)
     window->SetBounds(bounds);
 }
 
+void WorkspaceLayoutManager::AdjustWindowBoundsWhenAdded(
+    Window* window) {
+  if (!GetTrackedByWorkspace(window))
+    return;
+
+  if (SetMaximizedOrFullscreenBounds(window))
+    return;
+
+  gfx::Rect bounds = window->bounds();
+  int min_width = bounds.width() * kMinimumPercentOnScreenArea;
+  int min_height = bounds.height() * kMinimumPercentOnScreenArea;
+  ash::wm::AdjustBoundsToEnsureWindowVisibility(
+      work_area_, min_width, min_height, &bounds);
+
+  if (window->bounds() != bounds)
+    window->SetBounds(bounds);
+}
+
 void WorkspaceLayoutManager::UpdateDesktopVisibility() {
   if (shelf_)
     shelf_->UpdateVisibilityState();
@@ -229,10 +253,27 @@
     case ui::SHOW_STATE_DEFAULT:
     case ui::SHOW_STATE_NORMAL: {
       const gfx::Rect* restore = GetRestoreBoundsInScreen(window);
+      // Make sure that the part of the window is always visible
+      // when restored.
+      gfx::Rect bounds_in_parent;
       if (restore) {
-        gfx::Rect bounds_in_parent =
+        bounds_in_parent =
             ScreenAsh::ConvertRectFromScreen(window->parent()->parent(),
                                              *restore);
+
+        ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(
+            work_area_, &bounds_in_parent);
+      } else {
+        // Minimized windows have no restore bounds.
+        // Use the current bounds instead.
+        bounds_in_parent = window->bounds();
+        ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(
+            work_area_, &bounds_in_parent);
+        // Don't start animation if the bounds didn't change.
+        if (bounds_in_parent == window->bounds())
+          bounds_in_parent.SetRect(0, 0, 0, 0);
+      }
+      if (!bounds_in_parent.IsEmpty()) {
         CrossFadeToBounds(
             window,
             BaseLayoutManager::BoundsWithScreenEdgeVisible(
diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h
index a599d87..4476ddc 100644
--- a/ash/wm/workspace/workspace_layout_manager.h
+++ b/ash/wm/workspace/workspace_layout_manager.h
@@ -60,12 +60,14 @@
   // Overridden from BaseLayoutManager:
   virtual void ShowStateChanged(aura::Window* window,
                                 ui::WindowShowState last_show_state) OVERRIDE;
-  virtual void AdjustWindowSizesForScreenChange(
+  virtual void AdjustAllWindowsBoundsForWorkAreaChange(
       AdjustWindowReason reason) OVERRIDE;
-  virtual void AdjustWindowSizeForScreenChange(
+  virtual void AdjustWindowBoundsForWorkAreaChange(
       aura::Window* window,
       AdjustWindowReason reason) OVERRIDE;
 
+  void AdjustWindowBoundsWhenAdded(aura::Window* window);
+
   void UpdateDesktopVisibility();
 
   // Updates the bounds of the window from a show state change.
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index 30cdf6b..3e3a1c7 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -62,6 +62,42 @@
       Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
 }
 
+TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) {
+  if (!SupportsHostWindowResize())
+    return;
+  scoped_ptr<aura::Window> window(
+      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40)));
+  // Maximized -> Normal transition.
+  wm::MaximizeWindow(window.get());
+  SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40));
+  wm::RestoreWindow(window.get());
+  EXPECT_TRUE(
+      Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
+  EXPECT_EQ("-20,-30 30x40", window->bounds().ToString());
+
+  // Minimized -> Normal transition.
+  window->SetBounds(gfx::Rect(-100, -100, 30, 40));
+  wm::MinimizeWindow(window.get());
+  EXPECT_FALSE(
+      Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
+  EXPECT_EQ("-100,-100 30x40", window->bounds().ToString());
+  window->Show();
+  EXPECT_TRUE(
+      Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
+  EXPECT_EQ("-20,-30 30x40", window->bounds().ToString());
+
+  // Fullscreen -> Normal transition.
+  window->SetBounds(gfx::Rect(0, 0, 30, 40));  // reset bounds.
+  ASSERT_EQ("0,0 30x40", window->bounds().ToString());
+  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
+  EXPECT_EQ(window->bounds(), window->GetRootWindow()->bounds());
+  SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40));
+  wm::RestoreWindow(window.get());
+  EXPECT_TRUE(
+      Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds()));
+  EXPECT_EQ("-20,-30 30x40", window->bounds().ToString());
+}
+
 // WindowObserver implementation used by DontClobberRestoreBoundsWindowObserver.
 // This code mirrors what BrowserFrameAura does. In particular when this code
 // sees the window was maximized it changes the bounds of a secondary
@@ -110,7 +146,7 @@
   window->AddObserver(&window_observer);
   SetDefaultParentByPrimaryRootWindow(window.get());
   window->Show();
-  ash::wm::ActivateWindow(window.get());
+  wm::ActivateWindow(window.get());
 
   scoped_ptr<aura::Window> window2(
       CreateTestWindowInShellWithBounds(gfx::Rect(12, 20, 30, 40)));
@@ -128,12 +164,12 @@
   scoped_ptr<aura::Window> window(
       CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 30, 40)));
   window->Show();
-  ash::wm::ActivateWindow(window.get());
+  wm::ActivateWindow(window.get());
   scoped_ptr<aura::Window> child_window(
       aura::test::CreateTestWindowWithBounds(gfx::Rect(5, 6, 7, 8),
                                              window.get()));
   child_window->Show();
-  ash::wm::MaximizeWindow(window.get());
+  wm::MaximizeWindow(window.get());
   EXPECT_EQ("5,6 7x8", child_window->bounds().ToString());
 }
 
@@ -146,7 +182,7 @@
 
   // If the window is out of the workspace, it would be moved on screen.
   gfx::Rect root_window_bounds =
-      ash::Shell::GetInstance()->GetPrimaryRootWindow()->bounds();
+      Shell::GetInstance()->GetPrimaryRootWindow()->bounds();
   window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height());
   ASSERT_FALSE(window_bounds.Intersects(root_window_bounds));
   scoped_ptr<aura::Window> out_window(
@@ -154,9 +190,45 @@
   EXPECT_EQ(window_bounds.size(), out_window->bounds().size());
   gfx::Rect bounds = out_window->bounds();
   bounds.Intersect(root_window_bounds);
-  // 2/3 of the window must be visible.
-  EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.6);
-  EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.6);
+
+  // 30% of the window edge must be visible.
+  EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
+  EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
+
+  // Make sure we always make more than 1/3 of the window edge visible even
+  // if the initial bounds intersects with display.
+  window_bounds.SetRect(-150, -150, 200, 200);
+  bounds = window_bounds;
+  bounds.Intersect(root_window_bounds);
+
+  // Make sure that the initial bounds' visible area is less than 26%
+  // so that the auto adjustment logic kicks in.
+  ASSERT_LT(bounds.width(), out_window->bounds().width() * 0.26);
+  ASSERT_LT(bounds.height(), out_window->bounds().height() * 0.26);
+  ASSERT_TRUE(window_bounds.Intersects(root_window_bounds));
+
+  scoped_ptr<aura::Window> partially_out_window(
+      CreateTestWindowInShellWithBounds(window_bounds));
+  EXPECT_EQ(window_bounds.size(), partially_out_window->bounds().size());
+  bounds = partially_out_window->bounds();
+  bounds.Intersect(root_window_bounds);
+  EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
+  EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
+
+  // Make sure the window whose 30% width/height is bigger than display
+  // will be placed correctly.
+  window_bounds.SetRect(-1900, -1900, 3000, 3000);
+  scoped_ptr<aura::Window> window_bigger_than_display(
+      CreateTestWindowInShellWithBounds(window_bounds));
+  EXPECT_GE(root_window_bounds.width(),
+            window_bigger_than_display->bounds().width());
+  EXPECT_GE(root_window_bounds.height(),
+            window_bigger_than_display->bounds().height());
+
+  bounds = window_bigger_than_display->bounds();
+  bounds.Intersect(root_window_bounds);
+  EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29);
+  EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29);
 }
 
 // Verifies the size of a window is enforced to be smaller than the work area.
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
index ea4c37b..0645c73 100644
--- a/base/android/base_jni_registrar.cc
+++ b/base/android/base_jni_registrar.cc
@@ -8,6 +8,7 @@
 #include "base/android/build_info.h"
 #include "base/android/cpu_features.h"
 #include "base/android/important_file_writer_android.h"
+#include "base/android/java_handler_thread.h"
 #include "base/android/jni_android.h"
 #include "base/android/jni_registrar.h"
 #include "base/android/memory_pressure_listener_android.h"
@@ -38,6 +39,7 @@
     base::android::RegisterImportantFileWriterAndroid },
   { "MemoryPressureListenerAndroid",
       base::android::MemoryPressureListenerAndroid::Register },
+  { "JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings },
   { "PathService", base::android::RegisterPathService },
   { "PathUtils", base::android::RegisterPathUtils },
   { "SystemMessageHandler", base::MessagePumpForUI::RegisterBindings },
diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
new file mode 100644
index 0000000..5f9960e
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
@@ -0,0 +1,41 @@
+// 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.base;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+
+/**
+ * This class is an internal detail of the native counterpart.
+ * It is instantiated and owned by the native object.
+ */
+@JNINamespace("base::android")
+class JavaHandlerThread {
+    final HandlerThread mThread;
+
+    private JavaHandlerThread(String name) {
+        mThread = new HandlerThread(name);
+    }
+
+    @CalledByNative
+    private static JavaHandlerThread create(String name) {
+        return new JavaHandlerThread(name);
+    }
+
+    @CalledByNative
+    private void start(final int nativeThread, final int nativeEvent) {
+        mThread.start();
+        new Handler(mThread.getLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                nativeInitializeThread(nativeThread, nativeEvent);
+            }
+        });
+    }
+
+    private native void nativeInitializeThread(int nativeJavaHandlerThread, int nativeEvent);
+}
\ No newline at end of file
diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc
new file mode 100644
index 0000000..0528fe7
--- /dev/null
+++ b/base/android/java_handler_thread.cc
@@ -0,0 +1,62 @@
+// 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 "base/android/java_handler_thread.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "jni/JavaHandlerThread_jni.h"
+
+namespace base {
+
+namespace android {
+
+JavaHandlerThread::JavaHandlerThread(const char* name) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  java_thread_.Reset(Java_JavaHandlerThread_create(
+      env, ConvertUTF8ToJavaString(env, name).Release()));
+}
+
+JavaHandlerThread::~JavaHandlerThread() {
+}
+
+void JavaHandlerThread::Start() {
+  // Check the thread has not already been started.
+  DCHECK(!message_loop_);
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::WaitableEvent initialize_event(false, false);
+  Java_JavaHandlerThread_start(env,
+                               java_thread_.obj(),
+                               reinterpret_cast<jint>(this),
+                               reinterpret_cast<jint>(&initialize_event));
+  // Wait for thread to be initialized so it is ready to be used when Start
+  // returns.
+  base::ThreadRestrictions::ScopedAllowWait wait_allowed;
+  initialize_event.Wait();
+}
+
+void JavaHandlerThread::Stop() {
+}
+
+void JavaHandlerThread::InitializeThread(JNIEnv* env, jobject obj, jint event) {
+  // TYPE_JAVA to get the Android java style message loop.
+  message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA));
+  static_cast<MessageLoopForUI*>(message_loop_.get())->Start();
+  reinterpret_cast<base::WaitableEvent*>(event)->Signal();
+}
+
+// static
+bool JavaHandlerThread::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h
new file mode 100644
index 0000000..9f66d66
--- /dev/null
+++ b/base/android/java_handler_thread.h
@@ -0,0 +1,48 @@
+// 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 BASE_THREADING_JAVA_THREAD_H_
+#define BASE_THREADING_JAVA_THREAD_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class MessageLoop;
+class WaitableEvent;
+
+namespace android {
+
+// A Java Thread with a native message loop. To run tasks, post them
+// to the message loop and they will be scheduled along with Java tasks
+// on the thread.
+// This is useful for callbacks where the receiver expects a thread
+// with a prepared Looper.
+class BASE_EXPORT JavaHandlerThread {
+ public:
+  JavaHandlerThread(const char* name);
+  virtual ~JavaHandlerThread();
+
+  base::MessageLoop* message_loop() const { return message_loop_.get(); }
+  void Start();
+  void Stop();
+
+  // Called from java on the newly created thread.
+  // Start() will not return before this methods has finished.
+  void InitializeThread(JNIEnv* env, jobject obj, jint event);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  scoped_ptr<base::MessageLoop> message_loop_;
+  ScopedJavaGlobalRef<jobject> java_thread_;
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_THREADING_JAVA_THREAD_H_
diff --git a/base/base.gyp b/base/base.gyp
index 15776f3..4b92a91 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -1160,6 +1160,7 @@
             'android/java/src/org/chromium/base/CpuFeatures.java',
             'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java',
             'android/java/src/org/chromium/base/MemoryPressureListener.java',
+            'android/java/src/org/chromium/base/JavaHandlerThread.java',
             'android/java/src/org/chromium/base/PathService.java',
             'android/java/src/org/chromium/base/PathUtils.java',
             'android/java/src/org/chromium/base/PowerMonitor.java',
diff --git a/base/base.gypi b/base/base.gypi
index fef37a1..bfe5a57 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -58,6 +58,8 @@
           'android/jni_string.h',
           'android/memory_pressure_listener_android.cc',
           'android/memory_pressure_listener_android.h',
+          'android/java_handler_thread.cc',
+          'android/java_handler_thread.h',
           'android/path_service_android.cc',
           'android/path_service_android.h',
           'android/path_utils.cc',
diff --git a/base/base.target.darwin-arm.mk b/base/base.target.darwin-arm.mk
index ce676e3..dfa23a3 100644
--- a/base/base.target.darwin-arm.mk
+++ b/base/base.target.darwin-arm.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base.target.darwin-mips.mk b/base/base.target.darwin-mips.mk
index 9023fcc..2847ad4 100644
--- a/base/base.target.darwin-mips.mk
+++ b/base/base.target.darwin-mips.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base.target.darwin-x86.mk b/base/base.target.darwin-x86.mk
index 71cd04d..d3c3e49 100644
--- a/base/base.target.darwin-x86.mk
+++ b/base/base.target.darwin-x86.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base.target.linux-arm.mk b/base/base.target.linux-arm.mk
index ce676e3..dfa23a3 100644
--- a/base/base.target.linux-arm.mk
+++ b/base/base.target.linux-arm.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base.target.linux-mips.mk b/base/base.target.linux-mips.mk
index 9023fcc..2847ad4 100644
--- a/base/base.target.linux-mips.mk
+++ b/base/base.target.linux-mips.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base.target.linux-x86.mk b/base/base.target.linux-x86.mk
index 71cd04d..d3c3e49 100644
--- a/base/base.target.linux-x86.mk
+++ b/base/base.target.linux-x86.mk
@@ -53,6 +53,7 @@
 	base/android/jni_registrar.cc \
 	base/android/jni_string.cc \
 	base/android/memory_pressure_listener_android.cc \
+	base/android/java_handler_thread.cc \
 	base/android/path_service_android.cc \
 	base/android/path_utils.cc \
 	base/android/sys_utils.cc \
diff --git a/base/base_jni_headers.target.darwin-arm.mk b/base/base_jni_headers.target.darwin-arm.mk
index 84ff247..3e81dc6 100644
--- a/base/base_jni_headers.target.darwin-arm.mk
+++ b/base/base_jni_headers.target.darwin-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/base_jni_headers.target.darwin-mips.mk b/base/base_jni_headers.target.darwin-mips.mk
index 47fe61d..e996126 100644
--- a/base/base_jni_headers.target.darwin-mips.mk
+++ b/base/base_jni_headers.target.darwin-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/base_jni_headers.target.darwin-x86.mk b/base/base_jni_headers.target.darwin-x86.mk
index 521691e..c97c9dd 100644
--- a/base/base_jni_headers.target.darwin-x86.mk
+++ b/base/base_jni_headers.target.darwin-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/base_jni_headers.target.linux-arm.mk b/base/base_jni_headers.target.linux-arm.mk
index 84ff247..3e81dc6 100644
--- a/base/base_jni_headers.target.linux-arm.mk
+++ b/base/base_jni_headers.target.linux-arm.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/base_jni_headers.target.linux-mips.mk b/base/base_jni_headers.target.linux-mips.mk
index 47fe61d..e996126 100644
--- a/base/base_jni_headers.target.linux-mips.mk
+++ b/base/base_jni_headers.target.linux-mips.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/base_jni_headers.target.linux-x86.mk b/base/base_jni_headers.target.linux-x86.mk
index 521691e..c97c9dd 100644
--- a/base/base_jni_headers.target.linux-x86.mk
+++ b/base/base_jni_headers.target.linux-x86.mk
@@ -15,7 +15,7 @@
 
 
 ### Generated for rule "base_base_gyp_base_jni_headers_target_generate_jni_headers":
-# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
+# "{'inputs': ['../base/android/jni_generator/jni_generator.py', '../android_webview/build/jarjar-rules.txt'], 'process_outputs_as_sources': '1', 'extension': 'java', 'outputs': ['$(gyp_shared_intermediate_dir)/base/jni/%(INPUT_ROOT)s_jni.h'], 'rule_name': 'generate_jni_headers', 'rule_sources': ['android/java/src/org/chromium/base/ActivityStatus.java', 'android/java/src/org/chromium/base/BuildInfo.java', 'android/java/src/org/chromium/base/CpuFeatures.java', 'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java', 'android/java/src/org/chromium/base/MemoryPressureListener.java', 'android/java/src/org/chromium/base/JavaHandlerThread.java', 'android/java/src/org/chromium/base/PathService.java', 'android/java/src/org/chromium/base/PathUtils.java', 'android/java/src/org/chromium/base/PowerMonitor.java', 'android/java/src/org/chromium/base/SystemMessageHandler.java', 'android/java/src/org/chromium/base/SysUtils.java', 'android/java/src/org/chromium/base/ThreadUtils.java'], 'action': ['../base/android/jni_generator/jni_generator.py', '--input_file', '$(RULE_SOURCES)', '--output_dir', '$(gyp_shared_intermediate_dir)/base/jni', '--optimize_generation', '0', '--jarjar', '../android_webview/build/jarjar-rules.txt'], 'message': 'Generating JNI bindings from $(RULE_SOURCES)'}":
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/ActivityStatus_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -66,6 +66,16 @@
 .PHONY: base_base_jni_headers_gyp_rule_trigger
 base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h
 
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_local_path := $(LOCAL_PATH)
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: export PATH := $(subst $(ANDROID_BUILD_PATHS),,$(PATH))
+$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h: $(LOCAL_PATH)/base/android/java/src/org/chromium/base/JavaHandlerThread.java $(LOCAL_PATH)/base/android/jni_generator/jni_generator.py $(LOCAL_PATH)/android_webview/build/jarjar-rules.txt $(GYP_TARGET_DEPENDENCIES)
+	mkdir -p $(gyp_shared_intermediate_dir)/base/jni; cd $(gyp_local_path)/base; ../base/android/jni_generator/jni_generator.py --input_file android/java/src/org/chromium/base/JavaHandlerThread.java --output_dir "$(gyp_shared_intermediate_dir)/base/jni" --optimize_generation 0 --jarjar ../android_webview/build/jarjar-rules.txt
+
+.PHONY: base_base_jni_headers_gyp_rule_trigger
+base_base_jni_headers_gyp_rule_trigger: $(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h
+
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_local_path := $(LOCAL_PATH)
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_intermediate_dir := $(abspath $(gyp_intermediate_dir))
 $(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h: gyp_shared_intermediate_dir := $(abspath $(gyp_shared_intermediate_dir))
@@ -134,6 +144,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
@@ -150,6 +161,7 @@
 	$(gyp_shared_intermediate_dir)/base/jni/CpuFeatures_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/ImportantFileWriterAndroid_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/MemoryPressureListener_jni.h \
+	$(gyp_shared_intermediate_dir)/base/jni/JavaHandlerThread_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathService_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PathUtils_jni.h \
 	$(gyp_shared_intermediate_dir)/base/jni/PowerMonitor_jni.h \
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
index 0615e0d..2a2b52f 100644
--- a/base/containers/hash_tables.h
+++ b/base/containers/hash_tables.h
@@ -118,36 +118,6 @@
 using BASE_HASH_NAMESPACE::hash_multimap;
 using BASE_HASH_NAMESPACE::hash_multiset;
 using BASE_HASH_NAMESPACE::hash_set;
-}
-
-
-// Implement methods for hashing a pair of integers, so they can be used as
-// keys in STL containers.
-
-#if defined(COMPILER_MSVC)
-
-#define DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) \
-    template<> \
-    inline std::size_t hash_value<std::pair<type1, type2> >( \
-        const std::pair<type1, type2>& value)
-
-#define DEFINE_PAIR_HASH_FUNCTION_END()
-
-#elif defined(COMPILER_GCC)
-
-#define DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) \
-    template<> \
-    struct hash<std::pair<type1, type2> > { \
-      std::size_t operator()(std::pair<type1, type2> value) const
-
-#define DEFINE_PAIR_HASH_FUNCTION_END() \
-    };
-
-#else
-#error define DEFINE_PAIR_HASH_FUNCTION_START for your compiler
-#endif  // COMPILER
-
-namespace BASE_HASH_NAMESPACE {
 
 // Implement hashing for pairs of at-most 32 bit integer values.
 // When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
@@ -158,24 +128,61 @@
 //   h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
 //
 // Contact danakj@chromium.org for any questions.
-#define DEFINE_32BIT_PAIR_HASH(type1, type2) \
-    DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) { \
-      uint64 first = value.first; \
-      uint32 second = value.second; \
-      uint64 hash64 = (first << 32) | second; \
-      \
-      if (sizeof(std::size_t) >= sizeof(uint64)) \
-        return static_cast<std::size_t>(hash64); \
-      \
-      uint64 odd_random = 481046412LL << 32 | 1025306954LL; \
-      uint32 shift_random = 10121U << 16; \
-      \
-      hash64 = hash64 * odd_random + shift_random; \
-      std::size_t high_bits = static_cast<std::size_t>( \
-          hash64 >> (sizeof(uint64) - sizeof(std::size_t))); \
-      return high_bits; \
-    } \
-  DEFINE_PAIR_HASH_FUNCTION_END();
+inline std::size_t HashInts32(uint32 value1, uint32 value2) {
+  uint64 value1_64 = value1;
+  uint64 hash64 = (value1_64 << 32) | value2;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 481046412LL << 32 | 1025306955LL;
+  uint32 shift_random = 10121U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (sizeof(uint64) - sizeof(std::size_t)));
+  return high_bits;
+}
+
+// Implement hashing for pairs of up-to 64-bit integer values.
+// We use the compound integer hash method to produce a 64-bit hash code, by
+// breaking the two 64-bit inputs into 4 32-bit values:
+// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+// Then we reduce our result to 32 bits if required, similar to above.
+inline std::size_t HashInts64(uint64 value1, uint64 value2) {
+  uint32 short_random1 = 842304669U;
+  uint32 short_random2 = 619063811U;
+  uint32 short_random3 = 937041849U;
+  uint32 short_random4 = 3309708029U;
+
+  uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
+  uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
+  uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
+  uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
+
+  uint64 product1 = static_cast<uint64>(value1a) * short_random1;
+  uint64 product2 = static_cast<uint64>(value1b) * short_random2;
+  uint64 product3 = static_cast<uint64>(value2a) * short_random3;
+  uint64 product4 = static_cast<uint64>(value2b) * short_random4;
+
+  uint64 hash64 = product1 + product2 + product3 + product4;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 1578233944LL << 32 | 194370989LL;
+  uint32 shift_random = 20591U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (sizeof(uint64) - sizeof(std::size_t)));
+  return high_bits;
+}
+
+#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts32(value1, value2); \
+}
 
 DEFINE_32BIT_PAIR_HASH(int16, int16);
 DEFINE_32BIT_PAIR_HASH(int16, uint16);
@@ -196,44 +203,10 @@
 
 #undef DEFINE_32BIT_PAIR_HASH
 
-// Implement hashing for pairs of up-to 64-bit integer values.
-// We use the compound integer hash method to produce a 64-bit hash code, by
-// breaking the two 64-bit inputs into 4 32-bit values:
-// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
-// Then we reduce our result to 32 bits if required, similar to above.
-#define DEFINE_64BIT_PAIR_HASH(type1, type2) \
-    DEFINE_PAIR_HASH_FUNCTION_START(type1, type2) { \
-      uint32 short_random1 = 842304669U; \
-      uint32 short_random2 = 619063811U; \
-      uint32 short_random3 = 937041849U; \
-      uint32 short_random4 = 3309708029U; \
-      \
-      uint64 value1 = value.first; \
-      uint64 value2 = value.second; \
-      uint32 value1a = static_cast<uint32>(value1 & 0xffffffff); \
-      uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff); \
-      uint32 value2a = static_cast<uint32>(value2 & 0xffffffff); \
-      uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff); \
-      \
-      uint64 product1 = static_cast<uint64>(value1a) * short_random1; \
-      uint64 product2 = static_cast<uint64>(value1b) * short_random2; \
-      uint64 product3 = static_cast<uint64>(value2a) * short_random3; \
-      uint64 product4 = static_cast<uint64>(value2b) * short_random4; \
-      \
-      uint64 hash64 = product1 + product2 + product3 + product4; \
-      \
-      if (sizeof(std::size_t) >= sizeof(uint64)) \
-        return static_cast<std::size_t>(hash64); \
-      \
-      uint64 odd_random = 1578233944LL << 32 | 194370989LL; \
-      uint32 shift_random = 20591U << 16; \
-      \
-      hash64 = hash64 * odd_random + shift_random; \
-      std::size_t high_bits = static_cast<std::size_t>( \
-          hash64 >> (sizeof(uint64) - sizeof(std::size_t))); \
-      return high_bits; \
-    } \
-  DEFINE_PAIR_HASH_FUNCTION_END();
+#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts64(value1, value2); \
+}
 
 DEFINE_64BIT_PAIR_HASH(int16, int64);
 DEFINE_64BIT_PAIR_HASH(int16, uint64);
@@ -257,6 +230,32 @@
 DEFINE_64BIT_PAIR_HASH(uint64, uint64);
 
 #undef DEFINE_64BIT_PAIR_HASH
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+// Implement methods for hashing a pair of integers, so they can be used as
+// keys in STL containers.
+
+#if defined(COMPILER_MSVC)
+
+template<typename Type1, typename Type2>
+inline std::size_t hash_value(const std::pair<Type1, Type2>& value) {
+  return base::HashPair(value.first, value.second);
+}
+
+#elif defined(COMPILER_GCC)
+template<typename Type1, typename Type2>
+struct hash<std::pair<Type1, Type2> > {
+  std::size_t operator()(std::pair<Type1, Type2> value) const {
+    return base::HashPair(value.first, value.second);
+  }
+};
+
+#else
+#error define hash<std::pair<Type1, Type2> > for your compiler
+#endif  // COMPILER
+
 }
 
 #undef DEFINE_PAIR_HASH_FUNCTION_START
diff --git a/base/debug/trace_event_android.cc b/base/debug/trace_event_android.cc
index 7a9ad30..78d9de6 100644
--- a/base/debug/trace_event_android.cc
+++ b/base/debug/trace_event_android.cc
@@ -70,7 +70,7 @@
     if (g_atrace_fd == -1) {
       LOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
     } else {
-      EnableIncludedCategoryGroups();
+      UpdateCategoryGroupEnabledFlags();
     }
   }
 }
@@ -80,7 +80,7 @@
   if (g_atrace_fd != -1) {
     close(g_atrace_fd);
     g_atrace_fd = -1;
-    EnableIncludedCategoryGroups();
+    UpdateCategoryGroupEnabledFlags();
   }
 }
 
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index 44d1f71..6e1f08c 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -867,14 +867,20 @@
   return g_category_groups[category_index];
 }
 
-void TraceLog::EnableIncludedCategoryGroup(int category_index) {
-  bool is_enabled = category_filter_.IsCategoryGroupEnabled(
+void TraceLog::UpdateCategoryGroupEnabledFlag(int category_index) {
+  bool is_enabled = enable_count_ && category_filter_.IsCategoryGroupEnabled(
       g_category_groups[category_index]);
   SetCategoryGroupEnabled(category_index, is_enabled);
 }
 
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+  for (int i = 0; i < g_category_index; i++)
+    UpdateCategoryGroupEnabledFlag(i);
+}
+
 void TraceLog::SetCategoryGroupEnabled(int category_index, bool is_enabled) {
-  g_category_group_enabled[category_index] = is_enabled ? CATEGORY_ENABLED : 0;
+  g_category_group_enabled[category_index] =
+      is_enabled ? CATEGORY_GROUP_ENABLED : 0;
 
 #if defined(OS_ANDROID)
   ApplyATraceEnabledFlag(&g_category_group_enabled[category_index]);
@@ -885,12 +891,7 @@
     const unsigned char* category_group_enabled) {
   // On Android, ATrace and normal trace can be enabled independently.
   // This function checks if the normal trace is enabled.
-  return *category_group_enabled & CATEGORY_ENABLED;
-}
-
-void TraceLog::EnableIncludedCategoryGroups() {
-  for (int i = 0; i < g_category_index; i++)
-    EnableIncludedCategoryGroup(i);
+  return *category_group_enabled & CATEGORY_GROUP_ENABLED;
 }
 
 const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
@@ -921,14 +922,10 @@
       ANNOTATE_LEAKING_OBJECT_PTR(new_group);
       g_category_groups[new_index] = new_group;
       DCHECK(!g_category_group_enabled[new_index]);
-      if (enable_count_) {
-        // Note that if both included and excluded patterns in the
-        // CategoryFilter are empty, we exclude nothing,
-        // thereby enabling this category group.
-        EnableIncludedCategoryGroup(new_index);
-      } else {
-        SetCategoryGroupEnabled(new_index, false);
-      }
+      // Note that if both included and excluded patterns in the
+      // CategoryFilter are empty, we exclude nothing,
+      // thereby enabling this category group.
+      UpdateCategoryGroupEnabledFlag(new_index);
       category_group_enabled = &g_category_group_enabled[new_index];
     } else {
       category_group_enabled =
@@ -958,7 +955,7 @@
       }
 
       category_filter_.Merge(category_filter);
-      EnableIncludedCategoryGroups();
+      UpdateCategoryGroupEnabledFlags();
       return;
     }
 
@@ -976,7 +973,7 @@
     num_traces_recorded_++;
 
     category_filter_ = CategoryFilter(category_filter);
-    EnableIncludedCategoryGroups();
+    UpdateCategoryGroupEnabledFlags();
 
     if (options & ENABLE_SAMPLING) {
       sampling_thread_.reset(new TraceSamplingThread);
@@ -1044,8 +1041,7 @@
     category_filter_.Clear();
     watch_category_ = NULL;
     watch_event_name_ = "";
-    for (int i = 0; i < g_category_index; i++)
-      SetCategoryGroupEnabled(i, false);
+    UpdateCategoryGroupEnabledFlags();
     AddMetadataEvents();
 
     dispatching_to_observer_list_ = true;
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 0f30c1e..c3ceec6 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -479,11 +479,13 @@
   // by the Singleton class.
   friend struct DefaultSingletonTraits<TraceLog>;
 
-  // Enable/disable each category group based on the current category_filter_.
-  // If the category group contains a category that matches an included category
+  // Enable/disable each category group based on the current enable_count_
+  // and category_filter_. Disable the category group if enabled_count_ is 0, or
+  // if the category group contains a category that matches an included category
   // pattern, that category group will be enabled.
-  void EnableIncludedCategoryGroups();
-  void EnableIncludedCategoryGroup(int category_index);
+  // On Android, ATRACE_ENABLED flag will be applied if atrace is started.
+  void UpdateCategoryGroupEnabledFlags();
+  void UpdateCategoryGroupEnabledFlag(int category_index);
 
   static void SetCategoryGroupEnabled(int category_index, bool enabled);
   static bool IsCategoryGroupEnabled(
@@ -492,9 +494,9 @@
   // The pointer returned from GetCategoryGroupEnabledInternal() points to a
   // value with zero or more of the following bits. Used in this class only.
   // The TRACE_EVENT macros should only use the value as a bool.
-  enum CategoryEnabledFlags {
-    // Normal enabled flag for categories enabled with Enable().
-    CATEGORY_ENABLED = 1 << 0,
+  enum CategoryGroupEnabledFlags {
+    // Normal enabled flag for category groups enabled with Enable().
+    CATEGORY_GROUP_ENABLED = 1 << 0,
     // On Android if ATrace is enabled, all categories will have this bit.
     // Not used on other platforms.
     ATRACE_ENABLED = 1 << 1
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index d2eafbd..826c757 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -92,7 +92,7 @@
 // time for every task that is added to the MessageLoop incoming queue.
 bool AlwaysNotifyPump(MessageLoop::Type type) {
 #if defined(OS_ANDROID)
-  return type == MessageLoop::TYPE_UI;
+  return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
 #else
   return false;
 #endif
@@ -184,6 +184,10 @@
       pump_.reset(MESSAGE_PUMP_UI);
   } else if (type_ == TYPE_IO) {
     pump_.reset(MESSAGE_PUMP_IO);
+#if defined(OS_ANDROID)
+  } else if (type_ == TYPE_JAVA) {
+    pump_.reset(MESSAGE_PUMP_UI);
+#endif
   } else {
     DCHECK_EQ(TYPE_DEFAULT, type_);
     pump_.reset(new MessagePumpDefault());
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 6f71a85..f22c904 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -109,10 +109,19 @@
   //   This type of ML also supports asynchronous IO.  See also
   //   MessageLoopForIO.
   //
+  // TYPE_JAVA
+  //   This type of ML is backed by a Java message handler which is responsible
+  //   for running the tasks added to the ML. This is only for use on Android.
+  //   TYPE_JAVA behaves in essence like TYPE_UI, except during construction
+  //   where it does not use the main thread specific pump factory.
+  //
   enum Type {
     TYPE_DEFAULT,
     TYPE_UI,
-    TYPE_IO
+    TYPE_IO,
+#if defined(OS_ANDROID)
+    TYPE_JAVA,
+#endif // defined(OS_ANDROID)
   };
 
   // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index 6490b04..595b970 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -73,6 +73,10 @@
 
 namespace base {
 
+namespace android {
+class JavaHandlerThread;
+}
+
 class SequencedWorkerPool;
 class SimpleThread;
 class Thread;
@@ -185,6 +189,7 @@
   friend class Thread;
   friend class ThreadTestHelper;
   friend class PlatformThread;
+  friend class android::JavaHandlerThread;
 
   // END ALLOWED USAGE.
   // BEGIN USAGE THAT NEEDS TO BE FIXED.
diff --git a/build/android/bb_run_sharded_steps.py b/build/android/bb_run_sharded_steps.py
index 9b768a9..086a3a1 100755
--- a/build/android/bb_run_sharded_steps.py
+++ b/build/android/bb_run_sharded_steps.py
@@ -54,6 +54,7 @@
 import signal
 import shutil
 import sys
+import time
 
 from pylib import android_commands
 from pylib import cmd_helper
@@ -174,6 +175,18 @@
           os.kill(int(pid), signal.SIGQUIT)
         except Exception as e:
           logging.warning('Failed killing %s %s %s', server, pid, e)
+  # Restart the adb server with full trace, and redirect stderr to stdout
+  # so the extra tracing won't confuse higher up layers.
+  os.environ['ADB_TRACE'] = 'all'
+  cmd_helper.RunCmd(['adb', 'kill-server'])
+  cmd_helper.RunCmd(['adb', 'start-server'])
+  cmd_helper.RunCmd(['adb', 'root'])
+  i = 1
+  while not android_commands.GetAttachedDevices():
+    time.sleep(i)
+    i *= 2
+    if i > 10:
+      break
 
 
 def main(argv):
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 1df95a3..ae0bb4a 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -11,6 +11,7 @@
 import smtplib
 import sys
 import re
+import urllib
 
 import bb_annotations
 
@@ -148,9 +149,19 @@
 
     # TODO(navabi): Debug by printing both output from GetCmdOutput and
     # GetAttachedDevices to compare results.
+    crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary='
+                  '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' %
+                  (urllib.quote('Device Offline'),
+                   urllib.quote('Buildbot: %s %s\n'
+                                'Build: %s\n'
+                                '(please don\'t change any labels)' %
+                                (os.environ.get('BUILDBOT_BUILDERNAME'),
+                                 os.environ.get('BUILDBOT_SLAVENAME'),
+                                 os.environ.get('BUILDBOT_BUILDNUMBER')))))
     return ['Current online devices: %s' % adb_online_devs,
             '%s are no longer visible. Were they removed?\n' % missing_devs,
-            'SHERIFF: See go/chrome_device_monitor',
+            'SHERIFF:\n',
+            '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link,
             'Cache file: %s\n\n' % last_devices_path,
             'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
             'adb devices(GetAttachedDevices): %s' %
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
index 4cf070d..cb72fff 100644
--- a/build/android/pylib/android_commands.py
+++ b/build/android/pylib/android_commands.py
@@ -184,14 +184,15 @@
   return files
 
 
-def _ComputeFileListHash(md5sum_output):
+def _ParseMd5SumOutput(md5sum_output):
   """Returns a list of tuples from the provided md5sum output.
 
   Args:
     md5sum_output: output directly from md5sum binary.
 
   Returns:
-    List of namedtuples (hash, path).
+    List of namedtuples with attributes |hash| and |path|, where |path| is the
+    absolute path to the file with an Md5Sum of |hash|.
   """
   HashAndPath = collections.namedtuple('HashAndPath', ['hash', 'path'])
   split_lines = [line.split('  ') for line in md5sum_output]
@@ -418,7 +419,8 @@
     # Check if package is already installed and up to date.
     if package_name:
       installed_apk_path = self.GetApplicationPath(package_name)
-      if installed_apk_path and self.CheckMd5Sum(apk_path, installed_apk_path):
+      if (installed_apk_path and
+          not self.GetFilesChanged(apk_path, installed_apk_path)):
         logging.info('Skipped install: identical %s APK already installed' %
             package_name)
         return
@@ -738,15 +740,16 @@
     """
     self.RunShellCommand('input keyevent %d' % keycode)
 
-  def CheckMd5Sum(self, local_path, device_path):
-    """Compares the md5sum of a local path against a device path.
+  def _RunMd5Sum(self, host_path, device_path):
+    """Gets the md5sum of a host path and device path.
 
     Args:
-      local_path: Path (file or directory) on the host.
+      host_path: Path (file or directory) on the host.
       device_path: Path on the device.
 
     Returns:
-      True if the md5sums match.
+      A tuple containing lists of the host and device md5sum results as
+      created by _ParseMd5SumOutput().
     """
     if not self._md5sum_build_dir:
       default_build_type = os.environ.get('BUILD_TYPE', 'Debug')
@@ -763,73 +766,112 @@
 
     cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' +
            MD5SUM_DEVICE_PATH + ' ' + device_path)
-    device_hash_tuples = _ComputeFileListHash(
+    device_hash_tuples = _ParseMd5SumOutput(
         self.RunShellCommand(cmd, timeout_time=2 * 60))
-    assert os.path.exists(local_path), 'Local path not found %s' % local_path
+    assert os.path.exists(host_path), 'Local path not found %s' % host_path
     md5sum_output = cmd_helper.GetCmdOutput(
-        ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path])
-    host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines())
+        ['%s/md5sum_bin_host' % self._md5sum_build_dir, host_path])
+    host_hash_tuples = _ParseMd5SumOutput(md5sum_output.splitlines())
+    return (host_hash_tuples, device_hash_tuples)
+
+  def GetFilesChanged(self, host_path, device_path):
+    """Compares the md5sum of a host path against a device path.
+
+    Note: Ignores extra files on the device.
+
+    Args:
+      host_path: Path (file or directory) on the host.
+      device_path: Path on the device.
+
+    Returns:
+      A list of tuples of the form (host_path, device_path) for files whose
+      md5sums do not match.
+    """
+    host_hash_tuples, device_hash_tuples = self._RunMd5Sum(
+        host_path, device_path)
 
     # Ignore extra files on the device.
     if len(device_hash_tuples) > len(host_hash_tuples):
       host_files = [os.path.relpath(os.path.normpath(p.path),
-                    os.path.normpath(local_path)) for p in host_hash_tuples]
+                    os.path.normpath(host_path)) for p in host_hash_tuples]
 
-      def _host_has(fname):
+      def HostHas(fname):
         return any(path in fname for path in host_files)
 
-      hashes_on_device = [h.hash for h in device_hash_tuples if
-                         _host_has(h.path)]
-    else:
-      hashes_on_device = [h.hash for h in device_hash_tuples]
+      device_hash_tuples = [h for h in device_hash_tuples if HostHas(h.path)]
 
-    # Compare md5sums between host and device files.
-    hashes_on_host = [h.hash for h in host_hash_tuples]
-    hashes_on_device.sort()
-    hashes_on_host.sort()
-    return hashes_on_device == hashes_on_host
+    # Constructs the target device path from a given host path. Don't use when
+    # only a single file is given as the base name given in device_path may
+    # differ from that in host_path.
+    def HostToDevicePath(host_file_path):
+      return os.path.join(os.path.dirname(device_path), os.path.relpath(
+          host_file_path, os.path.dirname(os.path.normpath(host_path))))
 
-  def PushIfNeeded(self, local_path, device_path):
-    """Pushes |local_path| to |device_path|.
+    device_hashes = [h.hash for h in device_hash_tuples]
+    return [(t.path, HostToDevicePath(t.path) if os.path.isdir(host_path) else
+             device_path)
+            for t in host_hash_tuples if t.hash not in device_hashes]
+
+  def PushIfNeeded(self, host_path, device_path):
+    """Pushes |host_path| to |device_path|.
 
     Works for files and directories. This method skips copying any paths in
     |test_data_paths| that already exist on the device with the same hash.
 
     All pushed files can be removed by calling RemovePushedFiles().
     """
-    assert os.path.exists(local_path), 'Local path not found %s' % local_path
-    size = int(cmd_helper.GetCmdOutput(['du', '-sb', local_path]).split()[0])
+    MAX_INDIVIDUAL_PUSHES = 50
+    assert os.path.exists(host_path), 'Local path not found %s' % host_path
+
+    def GetHostSize(path):
+      return int(cmd_helper.GetCmdOutput(['du', '-sb', path]).split()[0])
+
+    size = GetHostSize(host_path)
     self._pushed_files.append(device_path)
     self._potential_push_size += size
 
-    if self.CheckMd5Sum(local_path, device_path):
+    changed_files = self.GetFilesChanged(host_path, device_path)
+    if not changed_files:
       return
 
-    self._actual_push_size += size
-    # They don't match, so remove everything first and then create it.
-    if os.path.isdir(local_path):
-      self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60)
-      self.RunShellCommand('mkdir -p %s' % device_path)
+    def Push(host, device):
+      # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout
+      # of 60 seconds which isn't sufficient for a lot of users of this method.
+      push_command = 'push %s %s' % (host, device)
+      self._LogShell(push_command)
 
-    # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of
-    # 60 seconds which isn't sufficient for a lot of users of this method.
-    push_command = 'push %s %s' % (local_path, device_path)
-    self._LogShell(push_command)
+      # Retry push with increasing backoff if the device is busy.
+      retry = 0
+      while True:
+        output = self._adb.SendCommand(push_command, timeout_time=30 * 60)
+        if _HasAdbPushSucceeded(output):
+          return
+        if retry < 3:
+          retry += 1
+          wait_time = 5 * retry
+          logging.error('Push failed, retrying in %d seconds: %s' %
+                        (wait_time, output))
+          time.sleep(wait_time)
+        else:
+          raise Exception('Push failed: %s' % output)
 
-    # Retry push with increasing backoff if the device is busy.
-    retry = 0
-    while True:
-      output = self._adb.SendCommand(push_command, timeout_time=30 * 60)
-      if _HasAdbPushSucceeded(output):
-        return
-      if 'resource busy' in output and retry < 3:
-        retry += 1
-        wait_time = 5 * retry
-        logging.error('Push failed, retrying in %d seconds: %s' %
-                      (wait_time, output))
-        time.sleep(wait_time)
-      else:
-        raise Exception('Push failed: %s' % output)
+    diff_size = 0
+    if len(changed_files) <= MAX_INDIVIDUAL_PUSHES:
+      diff_size = sum(GetHostSize(f[0]) for f in changed_files)
+
+    # TODO(craigdh): Replace this educated guess with a heuristic that
+    # approximates the push time for each method.
+    if len(changed_files) > MAX_INDIVIDUAL_PUSHES or diff_size > 0.5 * size:
+      # We're pushing everything, remove everything first and then create it.
+      self._actual_push_size += size
+      if os.path.isdir(host_path):
+        self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60)
+        self.RunShellCommand('mkdir -p %s' % device_path)
+      Push(host_path, device_path)
+    else:
+      for f in changed_files:
+        Push(f[0], f[1])
+      self._actual_push_size += diff_size
 
   def GetPushSizeInfo(self):
     """Get total size of pushes to the device done via PushIfNeeded()
diff --git a/build/android/pylib/instrumentation/test_options.py b/build/android/pylib/instrumentation/test_options.py
index fec3d9c..0c9ac00 100644
--- a/build/android/pylib/instrumentation/test_options.py
+++ b/build/android/pylib/instrumentation/test_options.py
@@ -17,7 +17,6 @@
     'test_data',
     'save_perf_json',
     'screenshot_failures',
-    'disable_assertions',
     'wait_for_debugger',
     'test_apk',
     'test_apk_path',
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 4464d72..5e2b67e 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -126,8 +126,7 @@
       logging.warning('Unable to enable java asserts for %s, non rooted device',
                       self.device)
     else:
-      if self.adb.SetJavaAssertsEnabled(
-          enable=not self.options.disable_assertions):
+      if self.adb.SetJavaAssertsEnabled(True):
         self.adb.Reboot(full_reboot=False)
 
     # We give different default value to launch HTTP server based on shard index
diff --git a/build/android/pylib/monkey/__init__.py b/build/android/pylib/monkey/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/build/android/pylib/monkey/__init__.py
diff --git a/build/android/pylib/monkey/setup.py b/build/android/pylib/monkey/setup.py
new file mode 100644
index 0000000..5735d2e
--- /dev/null
+++ b/build/android/pylib/monkey/setup.py
@@ -0,0 +1,27 @@
+# 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.
+
+"""Generates test runner factory and tests for monkey tests."""
+
+import test_runner
+
+
+def Setup(test_options):
+  """Create and return the test runner factory and tests.
+
+  Args:
+    test_options: A MonkeyOptions object.
+
+  Returns:
+    A tuple of (TestRunnerFactory, tests).
+  """
+  # Token to replicate across devices as the "test". The TestRunner does all of
+  # the work to run the test.
+  tests = ['MonkeyTest']
+
+  def TestRunnerFactory(device, shard_index):
+    return test_runner.TestRunner(
+        test_options, device, shard_index)
+
+  return (TestRunnerFactory, tests)
diff --git a/build/android/pylib/monkey/test_options.py b/build/android/pylib/monkey/test_options.py
new file mode 100644
index 0000000..6b095f3
--- /dev/null
+++ b/build/android/pylib/monkey/test_options.py
@@ -0,0 +1,18 @@
+# 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.
+
+"""Defines the MonkeyOptions named tuple."""
+
+import collections
+
+MonkeyOptions = collections.namedtuple('MonkeyOptions', [
+    'build_type',
+    'verbose_count',
+    'package_name',
+    'activity_name',
+    'event_count',
+    'category',
+    'throttle',
+    'seed',
+    'extra_args'])
diff --git a/build/android/pylib/monkey/test_runner.py b/build/android/pylib/monkey/test_runner.py
new file mode 100644
index 0000000..99bc2e6
--- /dev/null
+++ b/build/android/pylib/monkey/test_runner.py
@@ -0,0 +1,77 @@
+# 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.
+
+"""Runs a monkey test on a single device."""
+
+import random
+
+from pylib.base import base_test_result
+from pylib.base import base_test_runner
+
+
+class TestRunner(base_test_runner.BaseTestRunner):
+  """A TestRunner instance runs a monkey test on a single device."""
+
+  def __init__(self, test_options, device, shard_index):
+    super(TestRunner, self).__init__(device, None, test_options.build_type)
+    self.options = test_options
+
+  def _LaunchMonkeyTest(self):
+    """Runs monkey test for a given package.
+
+    Returns:
+      Output from the monkey command on the device.
+    """
+
+    timeout_ms = self.options.event_count * self.options.throttle * 1.5
+
+    cmd = ['monkey',
+           '-p %s' % self.options.package_name,
+           ' '.join(['-c %s' % c for c in self.options.category]),
+           '--throttle %d' % self.options.throttle,
+           '-s %d' % (self.options.seed or random.randint(1, 100)),
+           '-v ' * self.options.verbose_count,
+           '--monitor-native-crashes',
+           '--kill-process-after-error',
+           self.options.extra_args,
+           '%d' % self.options.event_count]
+    return self.adb.RunShellCommand(' '.join(cmd), timeout_time=timeout_ms)
+
+  def RunTest(self, test_name):
+    """Run a Monkey test on the device.
+
+    Args:
+      test_name: String to use for logging the test result.
+
+    Returns:
+      A tuple of (TestRunResults, retry).
+    """
+    self.adb.StartActivity(self.options.package_name,
+                           self.options.activity_name,
+                           wait_for_completion=True,
+                           action='android.intent.action.MAIN',
+                           force_stop=True)
+
+    # Chrome crashes are not always caught by Monkey test runner.
+    # Verify Chrome has the same PID before and after the test.
+    before_pids = self.adb.ExtractPid(self.options.package_name)
+
+    # Run the test.
+    output = ''
+    if before_pids:
+      output = '\n'.join(self._LaunchMonkeyTest())
+      after_pids = self.adb.ExtractPid(self.options.package_name)
+
+    crashed = (not before_pids or not after_pids
+               or after_pids[0] != before_pids[0])
+
+    results = base_test_result.TestRunResults()
+    if 'Monkey finished' in output and not crashed:
+      result = base_test_result.BaseTestResult(
+          test_name, base_test_result.ResultType.PASS, log=output)
+    else:
+      result = base_test_result.BaseTestResult(
+          test_name, base_test_result.ResultType.FAIL, log=output)
+    results.AddResult(result)
+    return results, False
diff --git a/build/android/pylib/uiautomator/test_options.py b/build/android/pylib/uiautomator/test_options.py
index ddc2ae0..2ce5eb0 100644
--- a/build/android/pylib/uiautomator/test_options.py
+++ b/build/android/pylib/uiautomator/test_options.py
@@ -17,7 +17,6 @@
     'test_data',
     'save_perf_json',
     'screenshot_failures',
-    'disable_assertions',
     'uiautomator_jar',
     'uiautomator_info_jar',
     'package_name'])
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index 74e887d..58cdd45 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -35,7 +35,6 @@
         test_options.test_data,
         test_options.save_perf_json,
         test_options.screenshot_failures,
-        test_options.disable_assertions,
         wait_for_debugger=False,
         test_apk=None,
         test_apk_path=None,
diff --git a/build/android/run_monkey_test.py b/build/android/run_monkey_test.py
deleted file mode 100755
index 4957ac6..0000000
--- a/build/android/run_monkey_test.py
+++ /dev/null
@@ -1,170 +0,0 @@
-#!/usr/bin/env python
-# 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.
-
-"""Runs the Monkey tests on one or more devices."""
-import logging
-import optparse
-import random
-import sys
-
-from pylib.base import base_test_result
-from pylib.base import test_dispatcher
-from pylib.host_driven import test_case
-from pylib.host_driven import test_runner
-from pylib.utils import report_results
-from pylib.utils import test_options_parser
-
-
-class MonkeyTest(test_case.HostDrivenTestCase):
-  def __init__(self, test_name, package_name, activity_name, category, seed,
-               throttle, event_count, verbosity, extra_args):
-    """Create a MonkeyTest object.
-
-    Args:
-      test_name: Name of the method to run for this test object.
-      package_name: Allowed package.
-      activity_name: Name of the activity to start.
-      category: A list of allowed categories.
-      seed: Seed value for pseduo-random generator. Same seed value
-          generates the same sequence of events. Seed is randomized by default.
-      throttle: Delay between events (ms).
-      event_count: Number of events to generate.
-      verbosity: Verbosity level [0-3].
-      extra_args: A string of other args to pass to the command verbatim.
-    """
-    super(MonkeyTest, self).__init__(test_name)
-    self.package_name = package_name
-    self.activity_name = activity_name
-    self.category = category
-    self.seed = seed or random.randint(1, 100)
-    self.throttle = throttle
-    self.event_count = event_count
-    self.verbosity = verbosity
-    self.extra_args = extra_args
-
-  def testMonkey(self):
-    # Launch and wait for Chrome to launch.
-    self.adb.StartActivity(self.package_name,
-                           self.activity_name,
-                           wait_for_completion=True,
-                           action='android.intent.action.MAIN',
-                           force_stop=True)
-
-    # Chrome crashes are not always caught by Monkey test runner.
-    # Verify Chrome has the same PID before and after the test.
-    before_pids = self.adb.ExtractPid(self.package_name)
-
-    # Run the test.
-    output = ''
-    if before_pids:
-      output = '\n'.join(self._LaunchMonkeyTest())
-      after_pids = self.adb.ExtractPid(self.package_name)
-
-    crashed = (not before_pids or not after_pids
-               or after_pids[0] != before_pids[0])
-
-    results = base_test_result.TestRunResults()
-    if 'Monkey finished' in output and not crashed:
-      result = base_test_result.BaseTestResult(
-          self.tagged_name, base_test_result.ResultType.PASS, log=output)
-    else:
-      result = base_test_result.BaseTestResult(
-          self.tagged_name, base_test_result.ResultType.FAIL, log=output)
-    results.AddResult(result)
-    return results
-
-  def _LaunchMonkeyTest(self):
-    """Runs monkey test for a given package.
-
-    Returns:
-      Output from the monkey command on the device.
-    """
-
-    timeout_ms = self.event_count * self.throttle * 1.5
-
-    cmd = ['monkey',
-           '-p %s' % self.package_name,
-           ' '.join(['-c %s' % c for c in self.category]),
-           '--throttle %d' % self.throttle,
-           '-s %d' % self.seed,
-           '-v ' * self.verbosity,
-           '--monitor-native-crashes',
-           '--kill-process-after-error',
-           self.extra_args,
-           '%d' % self.event_count]
-    return self.adb.RunShellCommand(' '.join(cmd), timeout_time=timeout_ms)
-
-
-def RunMonkeyTests(options):
-  """Runs the Monkey tests, replicating it if there multiple devices."""
-  logger = logging.getLogger()
-  logger.setLevel(logging.DEBUG)
-
-  # Actually run the tests.
-  logging.debug('Running monkey tests.')
-  available_tests = [
-      MonkeyTest('testMonkey', options.package_name, options.activity_name,
-                 category=options.category, seed=options.seed,
-                 throttle=options.throttle, event_count=options.event_count,
-                 verbosity=options.verbosity, extra_args=options.extra_args)]
-
-  def TestRunnerFactory(device, shard_index):
-    return test_runner.HostDrivenTestRunner(
-        device, shard_index, '', options.build_type, False, False)
-
-  results, exit_code = test_dispatcher.RunTests(
-      available_tests, TestRunnerFactory, False, None, shard=False,
-      build_type=options.build_type, num_retries=0)
-
-  report_results.LogFull(
-      results=results,
-      test_type='Monkey',
-      test_package='Monkey',
-      build_type=options.build_type)
-
-  return exit_code
-
-
-def main():
-  desc = 'Run the Monkey tests on 1 or more devices.'
-  parser = optparse.OptionParser(description=desc)
-  test_options_parser.AddBuildTypeOption(parser)
-  parser.add_option('--package-name', help='Allowed package.')
-  parser.add_option('--activity-name',
-                    default='com.google.android.apps.chrome.Main',
-                    help='Name of the activity to start [default: %default].')
-  parser.add_option('--category', default='',
-                    help='A list of allowed categories [default: %default].')
-  parser.add_option('--throttle', default=100, type='int',
-                    help='Delay between events (ms) [default: %default]. ')
-  parser.add_option('--seed', type='int',
-                    help=('Seed value for pseudo-random generator. Same seed '
-                          'value generates the same sequence of events. Seed '
-                          'is randomized by default.'))
-  parser.add_option('--event-count', default=10000, type='int',
-                    help='Number of events to generate [default: %default].')
-  parser.add_option('--verbosity', default=1, type='int',
-                    help='Verbosity level [0-3] [default: %default].')
-  parser.add_option('--extra-args', default='',
-                    help=('String of other args to pass to the command verbatim'
-                          ' [default: "%default"].'))
-  (options, args) = parser.parse_args()
-
-  if args:
-    parser.print_help(sys.stderr)
-    parser.error('Unknown arguments: %s' % args)
-
-  if not options.package_name:
-    parser.print_help(sys.stderr)
-    parser.error('Missing package name')
-
-  if options.category:
-    options.category = options.category.split(',')
-
-  RunMonkeyTests(options)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 4113158..8655720 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -26,6 +26,8 @@
 from pylib.host_driven import setup as host_driven_setup
 from pylib.instrumentation import setup as instrumentation_setup
 from pylib.instrumentation import test_options as instrumentation_test_options
+from pylib.monkey import setup as monkey_setup
+from pylib.monkey import test_options as monkey_test_options
 from pylib.uiautomator import setup as uiautomator_setup
 from pylib.uiautomator import test_options as uiautomator_test_options
 from pylib.utils import report_results
@@ -68,13 +70,6 @@
                            default=0,
                            action='count',
                            help='Verbose level (multiple times for more)')
-  profilers = ['devicestatsmonitor', 'chrometrace', 'dumpheap', 'smaps',
-               'traceview']
-  option_parser.add_option('--profiler', dest='profilers', action='append',
-                           choices=profilers,
-                           help=('Profiling tool to run during test. Pass '
-                                 'multiple times to run multiple profilers. '
-                                 'Available profilers: %s' % profilers))
   option_parser.add_option('--tool',
                            dest='tool',
                            help=('Run the test under a tool '
@@ -172,10 +167,6 @@
                                  'kept. When this is run via a sharder '
                                  'the test server ports should be kept and '
                                  'should not be reset.'))
-  # TODO(gkanwar): This option is deprecated. Remove it in the future.
-  option_parser.add_option('--disable_assertions', action='store_true',
-                           help=('(DEPRECATED) Run with java assertions '
-                                 'disabled.'))
   option_parser.add_option('--test_data', action='append', default=[],
                            help=('Each instance defines a directory of test '
                                  'data that should be copied to the target(s) '
@@ -228,9 +219,6 @@
   option_parser.add_option('-w', '--wait_debugger', dest='wait_for_debugger',
                            action='store_true',
                            help='Wait for debugger.')
-  #TODO(craigdh): Remove option once -I is no longer passed downstream.
-  option_parser.add_option('-I', dest='install_apk', action='store_true',
-                           help='(DEPRECATED) Install the test apk.')
   option_parser.add_option(
       '--test-apk', dest='test_apk',
       help=('The name of the apk containing the tests '
@@ -293,7 +281,6 @@
       options.test_data,
       options.save_perf_json,
       options.screenshot_failures,
-      options.disable_assertions,
       options.wait_for_debugger,
       options.test_apk,
       options.test_apk_path,
@@ -330,7 +317,7 @@
 
   Returns:
     A UIAutomatorOptions named tuple which contains all options relevant to
-    instrumentation tests.
+    uiautomator tests.
   """
 
   ProcessJavaTestOptions(options, error_func)
@@ -363,12 +350,68 @@
       options.test_data,
       options.save_perf_json,
       options.screenshot_failures,
-      options.disable_assertions,
       options.uiautomator_jar,
       options.uiautomator_info_jar,
       options.package_name)
 
 
+def AddMonkeyTestOptions(option_parser):
+  """Adds monkey test options to |option_parser|."""
+  option_parser.add_option('--package-name', help='Allowed package.')
+  option_parser.add_option(
+      '--activity-name', default='com.google.android.apps.chrome.Main',
+      help='Name of the activity to start [default: %default].')
+  option_parser.add_option(
+      '--event-count', default=10000, type='int',
+      help='Number of events to generate [default: %default].')
+  option_parser.add_option(
+      '--category', default='',
+      help='A list of allowed categories [default: %default].')
+  option_parser.add_option(
+      '--throttle', default=100, type='int',
+      help='Delay between events (ms) [default: %default]. ')
+  option_parser.add_option(
+      '--seed', type='int',
+      help=('Seed value for pseudo-random generator. Same seed value generates '
+            'the same sequence of events. Seed is randomized by default.'))
+  option_parser.add_option(
+      '--extra-args', default='',
+      help=('String of other args to pass to the command verbatim '
+            '[default: "%default"].'))
+
+  AddCommonOptions(option_parser)
+
+
+def ProcessMonkeyTestOptions(options, error_func):
+  """Processes all monkey test options.
+
+  Args:
+    options: optparse.Options object.
+    error_func: Function to call with the error message in case of an error.
+
+  Returns:
+    A MonkeyOptions named tuple which contains all options relevant to
+    monkey tests.
+  """
+  if not options.package_name:
+    error_func('Package name is required.')
+
+  category = options.category
+  if category:
+    category = options.category.split(',')
+
+  return monkey_test_options.MonkeyOptions(
+      options.build_type,
+      options.verbose_count,
+      options.package_name,
+      options.activity_name,
+      options.event_count,
+      category,
+      options.throttle,
+      options.seed,
+      options.extra_args)
+
+
 def _RunGTests(options, error_func):
   """Subcommand of RunTestsCommands which runs gtests."""
   ProcessGTestOptions(options)
@@ -466,9 +509,6 @@
   """Subcommand of RunTestsCommands which runs uiautomator tests."""
   uiautomator_options = ProcessUIAutomatorOptions(options, error_func)
 
-  results = base_test_result.TestRunResults()
-  exit_code = 0
-
   runner_factory, tests = uiautomator_setup.Setup(uiautomator_options)
 
   results, exit_code = test_dispatcher.RunTests(
@@ -489,6 +529,25 @@
   return exit_code
 
 
+def _RunMonkeyTests(options, error_func):
+  """Subcommand of RunTestsCommands which runs monkey tests."""
+  monkey_options = ProcessMonkeyTestOptions(options, error_func)
+
+  runner_factory, tests = monkey_setup.Setup(monkey_options)
+
+  results, exit_code = test_dispatcher.RunTests(
+      tests, runner_factory, False, None, shard=False)
+
+  report_results.LogFull(
+      results=results,
+      test_type='Monkey',
+      test_package='Monkey',
+      build_type=options.build_type)
+
+  return exit_code
+
+
+
 def RunTestsCommand(command, options, args, option_parser):
   """Checks test type and dispatches to the appropriate function.
 
@@ -520,6 +579,8 @@
     return _RunInstrumentationTests(options, option_parser.error)
   elif command == 'uiautomator':
     return _RunUIAutomatorTests(options, option_parser.error)
+  elif command == 'monkey':
+    return _RunMonkeyTests(options, option_parser.error)
   else:
     raise Exception('Unknown test type.')
 
@@ -576,6 +637,8 @@
         AddInstrumentationTestOptions, RunTestsCommand),
     'uiautomator': CommandFunctionTuple(
         AddUIAutomatorTestOptions, RunTestsCommand),
+    'monkey': CommandFunctionTuple(
+        AddMonkeyTestOptions, RunTestsCommand),
     'help': CommandFunctionTuple(lambda option_parser: None, HelpCommand)
     }
 
diff --git a/build/common.gypi b/build/common.gypi
index 29f1278..72e9ecb7 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -27,6 +27,9 @@
             # Whether or not we are building the Ash shell.
             'use_ash%': 0,
 
+            # Whether or not we are using CRAS, the ChromeOS Audio Server.
+            'use_cras%': 0,
+
             # Use a raw surface abstraction.
             'use_ozone%': 0,
           },
@@ -34,6 +37,7 @@
           'chromeos%': '<(chromeos)',
           'use_aura%': '<(use_aura)',
           'use_ash%': '<(use_ash)',
+          'use_cras%': '<(use_cras)',
           'use_ozone%': '<(use_ozone)',
 
           # Whether we are using Views Toolkit
@@ -98,6 +102,7 @@
         'chromeos%': '<(chromeos)',
         'use_aura%': '<(use_aura)',
         'use_ash%': '<(use_ash)',
+        'use_cras%': '<(use_cras)',
         'use_ozone%': '<(use_ozone)',
         'use_openssl%': '<(use_openssl)',
         'enable_viewport%': '<(enable_viewport)',
@@ -179,6 +184,7 @@
       'toolkit_uses_gtk%': '<(toolkit_uses_gtk)',
       'use_aura%': '<(use_aura)',
       'use_ash%': '<(use_ash)',
+      'use_cras%': '<(use_cras)',
       'use_ozone%': '<(use_ozone)',
       'use_openssl%': '<(use_openssl)',
       'enable_viewport%': '<(enable_viewport)',
@@ -693,7 +699,16 @@
         }],
         ['OS=="win" or OS=="linux"', {
             'enable_mdns%' : 1,
-        }]
+        }],
+
+        # Turns on compiler optimizations in V8 in Debug build, except
+        # on android_clang, where we're hitting a weird linker error.
+        # TODO(dpranke): http://crbug.com/266155 .
+        ['OS=="android"', {
+          'v8_optimized_debug': 1,
+        }, {
+          'v8_optimized_debug': 2,
+        }],
       ],
 
       # Set this to 1 to enable use of concatenated impulse responses
@@ -755,6 +770,7 @@
     'ui_compositor_image_transport%': '<(ui_compositor_image_transport)',
     'use_aura%': '<(use_aura)',
     'use_ash%': '<(use_ash)',
+    'use_cras%': '<(use_cras)',
     'use_openssl%': '<(use_openssl)',
     'use_nss%': '<(use_nss)',
     'os_bsd%': '<(os_bsd)',
@@ -847,6 +863,7 @@
     'spdy_proxy_auth_property%': '<(spdy_proxy_auth_property)',
     'spdy_proxy_auth_value%': '<(spdy_proxy_auth_value)',
     'enable_mdns%' : '<(enable_mdns)',
+    'v8_optimized_debug': '<(v8_optimized_debug)',
 
     # Use system nspr instead of the bundled one.
     'use_system_nspr%': 0,
@@ -1104,9 +1121,6 @@
     # rlz codes for searches but do not use the library.
     'enable_rlz%': 0,
 
-    # Turns on compiler optimizations in V8 in Debug build.
-    'v8_optimized_debug': 1,
-
     # Turns on the i18n support in V8.
     'v8_enable_i18n_support': 1,
 
@@ -1928,6 +1942,9 @@
       ['use_ash==1', {
         'defines': ['USE_ASH=1'],
       }],
+      ['use_cras==1', {
+        'defines': ['USE_CRAS=1'],
+      }],
       ['use_ozone==1', {
         'defines': ['USE_OZONE=1'],
       }],
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index 16f4b00..aae8668 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=216133
+LASTCHANGE=216370
diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink
index 3a4250b..03e4ec2 100644
--- a/build/util/LASTCHANGE.blink
+++ b/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=155634
+LASTCHANGE=155688
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index e894ecf..4d8ced4 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -44,7 +44,7 @@
 CHAPTER 3:
 Mr. Usagi felt that something wasn't right. Shortly after the Domo-Kun left he
 began feeling sick. He thought out loud to himself, "No, he wouldn't have done
-that to me." He considered that perhaps he shouldn't have pushed him so far.
+that to me." He considered that perhaps he shouldn't have pushed so hard.
 Perhaps he shouldn't have been so cold and sarcastic, after the unimaginable
 horror that had occurred just the week before.
 
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 315e10a..78060a4 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -292,6 +292,8 @@
         'resources/prioritized_resource.h',
         'resources/prioritized_resource_manager.cc',
         'resources/prioritized_resource_manager.h',
+        'resources/prioritized_tile_set.cc',
+        'resources/prioritized_tile_set.h',
         'resources/priority_calculator.cc',
         'resources/priority_calculator.h',
         'resources/raster_mode.cc',
diff --git a/cc/cc.target.darwin-arm.mk b/cc/cc.target.darwin-arm.mk
index 1c496a4..7029dcc 100644
--- a/cc/cc.target.darwin-arm.mk
+++ b/cc/cc.target.darwin-arm.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc.target.darwin-mips.mk b/cc/cc.target.darwin-mips.mk
index d9dd101..d0f7ee7 100644
--- a/cc/cc.target.darwin-mips.mk
+++ b/cc/cc.target.darwin-mips.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc.target.darwin-x86.mk b/cc/cc.target.darwin-x86.mk
index 36b45db..3f83839 100644
--- a/cc/cc.target.darwin-x86.mk
+++ b/cc/cc.target.darwin-x86.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc.target.linux-arm.mk b/cc/cc.target.linux-arm.mk
index 1c496a4..7029dcc 100644
--- a/cc/cc.target.linux-arm.mk
+++ b/cc/cc.target.linux-arm.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc.target.linux-mips.mk b/cc/cc.target.linux-mips.mk
index d9dd101..d0f7ee7 100644
--- a/cc/cc.target.linux-mips.mk
+++ b/cc/cc.target.linux-mips.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc.target.linux-x86.mk b/cc/cc.target.linux-x86.mk
index 36b45db..3f83839 100644
--- a/cc/cc.target.linux-x86.mk
+++ b/cc/cc.target.linux-x86.mk
@@ -149,6 +149,7 @@
 	cc/resources/pixel_buffer_raster_worker_pool.cc \
 	cc/resources/prioritized_resource.cc \
 	cc/resources/prioritized_resource_manager.cc \
+	cc/resources/prioritized_tile_set.cc \
 	cc/resources/priority_calculator.cc \
 	cc/resources/raster_mode.cc \
 	cc/resources/raster_worker_pool.cc \
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index f633ce4..7e2ff87 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -54,6 +54,7 @@
       'resources/picture_pile_unittest.cc',
       'resources/picture_unittest.cc',
       'resources/prioritized_resource_unittest.cc',
+      'resources/prioritized_tile_set_unittest.cc',
       'resources/raster_worker_pool_unittest.cc',
       'resources/resource_provider_unittest.cc',
       'resources/resource_update_controller_unittest.cc',
@@ -171,6 +172,8 @@
       'test/solid_color_content_layer_client.cc',
       'test/skia_common.cc',
       'test/skia_common.h',
+      'test/test_tile_priorities.cc',
+      'test/test_tile_priorities.h',
       'test/test_web_graphics_context_3d.cc',
       'test/test_web_graphics_context_3d.h',
       'test/tiled_layer_test_common.cc',
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 08a5817..889e2fb 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -36,14 +36,25 @@
 
 void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
   Layer::PushPropertiesTo(base_layer);
+
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
+  // This should be first so others can use it.
+  layer_impl->UpdateTwinLayer();
 
   layer_impl->SetIsMask(is_mask_);
+  layer_impl->CreateTilingSetIfNeeded();
   // Unlike other properties, invalidation must always be set on layer_impl.
   // See PictureLayerImpl::PushPropertiesTo for more details.
   layer_impl->invalidation_.Clear();
   layer_impl->invalidation_.Swap(&pile_invalidation_);
   layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get());
+  layer_impl->SyncFromActiveLayer();
+
+  // PictureLayer must push properties every frame.
+  // TODO(danakj): If we can avoid requiring to do CreateTilingSetIfNeeded() and
+  // SyncFromActiveLayer() on every commit then this could go away, maybe
+  // conditionally. crbug.com/259402
+  needs_push_properties_ = true;
 }
 
 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
@@ -103,14 +114,11 @@
                            pile_invalidation_,
                            visible_layer_rect,
                            rendering_stats_instrumentation());
-  if (updated) {
-    SetNeedsPushProperties();
-  } else {
+  if (!updated) {
     // If this invalidation did not affect the pile, then it can be cleared as
     // an optimization.
     pile_invalidation_.Clear();
   }
-
   return updated;
 }
 
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index a5c69cc..2f1878b 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -45,8 +45,8 @@
       raster_contents_scale_(0.f),
       low_res_raster_contents_scale_(0.f),
       raster_source_scale_was_animating_(false),
-      is_using_lcd_text_(tree_impl->settings().can_use_lcd_text),
-      needs_post_commit_initialization_(true) {}
+      is_using_lcd_text_(tree_impl->settings().can_use_lcd_text) {
+}
 
 PictureLayerImpl::~PictureLayerImpl() {
 }
@@ -60,11 +60,13 @@
   return PictureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
 }
 
-void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
-  // It's possible this layer was never drawn or updated (e.g. because it was
-  // a descendant of an opacity 0 layer).
-  DoPostCommitInitializationIfNeeded();
+void PictureLayerImpl::CreateTilingSetIfNeeded() {
+  DCHECK(layer_tree_impl()->IsPendingTree());
+  if (!tilings_)
+    tilings_.reset(new PictureLayerTilingSet(this, bounds()));
+}
 
+void PictureLayerImpl::PushPropertiesTo(LayerImpl* base_layer) {
   LayerImpl::PushPropertiesTo(base_layer);
 
   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
@@ -76,9 +78,8 @@
 
   layer_impl->SetIsMask(is_mask_);
   layer_impl->pile_ = pile_;
+  pile_ = NULL;
 
-  // Tilings would be expensive to push, so we swap.  This optimization requires
-  // an extra invalidation in SyncFromActiveLayer.
   layer_impl->tilings_.swap(tilings_);
   layer_impl->tilings_->SetClient(layer_impl);
   if (tilings_)
@@ -91,19 +92,19 @@
   layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
 
   layer_impl->UpdateLCDTextStatus(is_using_lcd_text_);
-  layer_impl->needs_post_commit_initialization_ = false;
 
-  // The invalidation on this soon-to-be-recycled layer must be cleared to
-  // mirror clearing the invalidation in PictureLayer's version of this function
-  // in case push properties is skipped.
+  // As an optimization, don't make a copy of this potentially complex region,
+  // and swap it directly from the pending to the active layer.  In general, any
+  // property pushed to a LayerImpl continues to live on that LayerImpl.
+  // However, invalidation is the difference between two main thread frames, so
+  // it no longer makes sense once the pending tree gets recycled.  It will
+  // always get pushed during PictureLayer::PushPropertiesTo.
   layer_impl->invalidation_.Swap(&invalidation_);
   invalidation_.Clear();
-  needs_post_commit_initialization_ = true;
 }
 
 void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
                                    AppendQuadsData* append_quads_data) {
-  DCHECK(!needs_post_commit_initialization_);
   gfx::Rect rect(visible_content_rect());
   gfx::Rect content_rect(content_bounds());
 
@@ -295,7 +296,6 @@
 }
 
 void PictureLayerImpl::UpdateTilePriorities() {
-  DCHECK(!needs_post_commit_initialization_);
   if (!tilings_->num_tilings())
     return;
 
@@ -380,7 +380,6 @@
     float* contents_scale_x,
     float* contents_scale_y,
     gfx::Size* content_bounds) {
-  DoPostCommitInitializationIfNeeded();
   if (!CanHaveTilings()) {
     ideal_page_scale_ = page_scale_factor;
     ideal_device_scale_ = device_scale_factor;
@@ -526,10 +525,14 @@
   return default_tile_size;
 }
 
-void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
-  DCHECK(!other->needs_post_commit_initialization_);
-  DCHECK(other->tilings_);
+void PictureLayerImpl::SyncFromActiveLayer() {
+  DCHECK(layer_tree_impl()->IsPendingTree());
 
+  if (twin_layer_)
+    SyncFromActiveLayer(twin_layer_);
+}
+
+void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
   UpdateLCDTextStatus(other->is_using_lcd_text_);
 
   if (!DrawsContent()) {
@@ -594,6 +597,15 @@
     UpdateTilePriorities();
 }
 
+void PictureLayerImpl::UpdateTwinLayer() {
+  DCHECK(layer_tree_impl()->IsPendingTree());
+
+  twin_layer_ = static_cast<PictureLayerImpl*>(
+      layer_tree_impl()->FindActiveTreeLayerById(id()));
+  if (twin_layer_)
+    twin_layer_->twin_layer_ = this;
+}
+
 void PictureLayerImpl::SetIsMask(bool is_mask) {
   if (is_mask_ == is_mask)
     return;
@@ -712,28 +724,6 @@
   }
 }
 
-void PictureLayerImpl::DoPostCommitInitialization() {
-  DCHECK(needs_post_commit_initialization_);
-  DCHECK(layer_tree_impl()->IsPendingTree());
-
-  if (!tilings_)
-    tilings_.reset(new PictureLayerTilingSet(this, bounds()));
-
-  DCHECK(!twin_layer_);
-  twin_layer_ = static_cast<PictureLayerImpl*>(
-      layer_tree_impl()->FindActiveTreeLayerById(id()));
-  if (twin_layer_) {
-    DCHECK(!twin_layer_->twin_layer_);
-    twin_layer_->twin_layer_ = this;
-    // If the twin has never been pushed to, do not sync from it.
-    // This can happen if this function is called during activation.
-    if (!twin_layer_->needs_post_commit_initialization_)
-      SyncFromActiveLayer(twin_layer_);
-  }
-
-  needs_post_commit_initialization_ = false;
-}
-
 PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) {
   DCHECK(CanHaveTilingWithScale(contents_scale)) <<
       "contents_scale: " << contents_scale;
@@ -785,7 +775,6 @@
   DCHECK(ideal_device_scale_);
   DCHECK(ideal_source_scale_);
   DCHECK(CanHaveTilings());
-  DCHECK(!needs_post_commit_initialization_);
 
   bool change_target_tiling =
       raster_page_scale_ == 0.f ||
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 42efa72..25cc5d0 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -62,7 +62,11 @@
       const PictureLayerTiling* tiling) OVERRIDE;
 
   // PushPropertiesTo active tree => pending tree.
+  void SyncFromActiveLayer();
   void SyncTiling(const PictureLayerTiling* tiling);
+  void UpdateTwinLayer();
+
+  void CreateTilingSetIfNeeded();
 
   // Mask-related functions
   void SetIsMask(bool is_mask);
@@ -88,11 +92,6 @@
   void UpdateLCDTextStatus(bool new_status);
   void ResetRasterScale();
   void MarkVisibleResourcesAsRequired() const;
-  void DoPostCommitInitializationIfNeeded() {
-    if (needs_post_commit_initialization_)
-      DoPostCommitInitialization();
-  }
-  void DoPostCommitInitialization();
 
   bool CanHaveTilings() const;
   bool CanHaveTilingWithScale(float contents_scale) const;
@@ -125,7 +124,6 @@
 
   bool raster_source_scale_was_animating_;
   bool is_using_lcd_text_;
-  bool needs_post_commit_initialization_;
 
   friend class PictureLayer;
   DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 3272712..047a529 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -69,6 +69,7 @@
         host_impl_.active_tree()->LayerById(id_));
 
     SetupPendingTree(pending_pile);
+    pending_layer_->UpdateTwinLayer();
   }
 
   void AddDefaultTilingsWithInvalidation(const Region& invalidation) {
@@ -78,6 +79,7 @@
     for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
       active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
     pending_layer_->set_invalidation(invalidation);
+    pending_layer_->SyncFromActiveLayer();
     for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
       pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
   }
@@ -96,7 +98,6 @@
 
     pending_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.pending_tree()->LayerById(id_));
-    pending_layer_->DoPostCommitInitializationIfNeeded();
   }
 
   static void VerifyAllTilesExistAndHavePile(
@@ -1006,40 +1007,5 @@
   EXPECT_GT(num_offscreen, 0);
 }
 
-TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
-  gfx::Size tile_size(100, 100);
-  gfx::Size layer_bounds(400, 400);
-  scoped_refptr<FakePicturePileImpl> pending_pile =
-      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
-
-  host_impl_.CreatePendingTree();
-  LayerTreeImpl* pending_tree = host_impl_.pending_tree();
-
-  scoped_ptr<FakePictureLayerImpl> pending_layer =
-      FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
-  pending_layer->SetDrawsContent(true);
-  pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());
-
-  pending_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.pending_tree()->LayerById(id_));
-
-  // Set some state on the pending layer, make sure it is not clobbered
-  // by a sync from the active layer.  This could happen because if the
-  // pending layer has not been post-commit initialized it will attempt
-  // to sync from the active layer.
-  bool default_lcd_text_setting = pending_layer_->is_using_lcd_text();
-  pending_layer_->force_set_lcd_text(!default_lcd_text_setting);
-  EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
-
-  host_impl_.ActivatePendingTree();
-
-  active_layer_ = static_cast<FakePictureLayerImpl*>(
-      host_impl_.active_tree()->LayerById(id_));
-
-  EXPECT_EQ(0u, active_layer_->num_tilings());
-  EXPECT_EQ(!default_lcd_text_setting, active_layer_->is_using_lcd_text());
-  EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
-}
-
 }  // namespace
 }  // namespace cc
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index da1bc9a..3d5a37c 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -117,17 +117,14 @@
 
 namespace BASE_HASH_NAMESPACE {
 #if defined(COMPILER_MSVC)
-template<>
-inline size_t hash_value<cc::RenderPass::Id>(const cc::RenderPass::Id& key) {
-  return hash_value<std::pair<int, int> >(
-      std::pair<int, int>(key.layer_id, key.index));
+inline size_t hash_value(const cc::RenderPass::Id& key) {
+  return base::HashPair(key.layer_id, key.index);
 }
 #elif defined(COMPILER_GCC)
 template<>
 struct hash<cc::RenderPass::Id> {
   size_t operator()(cc::RenderPass::Id key) const {
-    return hash<std::pair<int, int> >()(
-        std::pair<int, int>(key.layer_id, key.index));
+    return base::HashPair(key.layer_id, key.index);
   }
 };
 #else
diff --git a/cc/resources/managed_tile_state.cc b/cc/resources/managed_tile_state.cc
index f5607ea..6f85331 100644
--- a/cc/resources/managed_tile_state.cc
+++ b/cc/resources/managed_tile_state.cc
@@ -12,15 +12,24 @@
 
 scoped_ptr<base::Value> ManagedTileBinAsValue(ManagedTileBin bin) {
   switch (bin) {
+  case NOW_AND_READY_TO_DRAW_BIN:
+      return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+          "NOW_AND_READY_TO_DRAW_BIN"));
   case NOW_BIN:
       return scoped_ptr<base::Value>(base::Value::CreateStringValue(
           "NOW_BIN"));
   case SOON_BIN:
       return scoped_ptr<base::Value>(base::Value::CreateStringValue(
           "SOON_BIN"));
+  case EVENTUALLY_AND_ACTIVE_BIN:
+      return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+          "EVENTUALLY_AND_ACTIVE_BIN"));
   case EVENTUALLY_BIN:
       return scoped_ptr<base::Value>(base::Value::CreateStringValue(
           "EVENTUALLY_BIN"));
+  case NEVER_AND_ACTIVE_BIN:
+      return scoped_ptr<base::Value>(base::Value::CreateStringValue(
+          "NEVER_AND_ACTIVE_BIN"));
   case NEVER_BIN:
       return scoped_ptr<base::Value>(base::Value::CreateStringValue(
           "NEVER_BIN"));
diff --git a/cc/resources/managed_tile_state.h b/cc/resources/managed_tile_state.h
index 2f61b39..c6065f9 100644
--- a/cc/resources/managed_tile_state.h
+++ b/cc/resources/managed_tile_state.h
@@ -17,11 +17,14 @@
 
 // Tile manager classifying tiles into a few basic bins:
 enum ManagedTileBin {
-  NOW_BIN = 0,         // Needed ASAP.
-  SOON_BIN = 1,        // Impl-side version of prepainting.
-  EVENTUALLY_BIN = 2,  // Nice to have, if we've got memory and time.
-  NEVER_BIN = 3,       // Dont bother.
-  NUM_BINS = 4
+  NOW_AND_READY_TO_DRAW_BIN = 0,  // Ready to draw and within viewport.
+  NOW_BIN = 1,                    // Needed ASAP.
+  SOON_BIN = 2,                   // Impl-side version of prepainting.
+  EVENTUALLY_AND_ACTIVE_BIN = 3,  // Nice to have, and has a task or resource.
+  EVENTUALLY_BIN = 4,             // Nice to have, if we've got memory and time.
+  NEVER_AND_ACTIVE_BIN = 5,       // Dont bother, but has a task or resource.
+  NEVER_BIN = 6,                  // Dont bother.
+  NUM_BINS = 7
   // NOTE: Be sure to update ManagedTileBinAsValue and kBinPolicyMap when adding
   // or reordering fields.
 };
@@ -98,6 +101,7 @@
 
     private:
       friend class TileManager;
+      friend class PrioritizedTileSet;
       friend class Tile;
       friend class ManagedTileState;
 
@@ -136,12 +140,10 @@
 
   // Ephemeral state, valid only during TileManager::ManageTiles.
   bool is_in_never_bin_on_both_trees() const {
-    return bin[HIGH_PRIORITY_BIN] == NEVER_BIN &&
-           bin[LOW_PRIORITY_BIN] == NEVER_BIN;
-  }
-  bool is_in_now_bin_on_either_tree() const {
-    return bin[HIGH_PRIORITY_BIN] == NOW_BIN ||
-           bin[LOW_PRIORITY_BIN] == NOW_BIN;
+    return (bin[HIGH_PRIORITY_BIN] == NEVER_BIN ||
+            bin[HIGH_PRIORITY_BIN] == NEVER_AND_ACTIVE_BIN) &&
+           (bin[LOW_PRIORITY_BIN] == NEVER_BIN ||
+            bin[LOW_PRIORITY_BIN] == NEVER_AND_ACTIVE_BIN);
   }
 
   ManagedTileBin bin[NUM_BIN_PRIORITIES];
diff --git a/cc/resources/prioritized_tile_set.cc b/cc/resources/prioritized_tile_set.cc
new file mode 100644
index 0000000..5b40945
--- /dev/null
+++ b/cc/resources/prioritized_tile_set.cc
@@ -0,0 +1,126 @@
+// 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 "cc/resources/prioritized_tile_set.h"
+
+#include <algorithm>
+
+#include "cc/resources/managed_tile_state.h"
+#include "cc/resources/tile.h"
+
+namespace cc {
+
+class BinComparator {
+ public:
+  bool operator()(const scoped_refptr<Tile>& a,
+                  const scoped_refptr<Tile>& b) const {
+    const ManagedTileState& ams = a->managed_state();
+    const ManagedTileState& bms = b->managed_state();
+
+    if (ams.bin[LOW_PRIORITY_BIN] != bms.bin[LOW_PRIORITY_BIN])
+      return ams.bin[LOW_PRIORITY_BIN] < bms.bin[LOW_PRIORITY_BIN];
+
+    if (ams.required_for_activation != bms.required_for_activation)
+      return ams.required_for_activation;
+
+    if (ams.resolution != bms.resolution)
+      return ams.resolution < bms.resolution;
+
+    if (ams.time_to_needed_in_seconds !=  bms.time_to_needed_in_seconds)
+      return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
+
+    if (ams.distance_to_visible_in_pixels !=
+        bms.distance_to_visible_in_pixels) {
+      return ams.distance_to_visible_in_pixels <
+             bms.distance_to_visible_in_pixels;
+    }
+
+    gfx::Rect a_rect = a->content_rect();
+    gfx::Rect b_rect = b->content_rect();
+    if (a_rect.y() != b_rect.y())
+      return a_rect.y() < b_rect.y();
+    return a_rect.x() < b_rect.x();
+  }
+};
+
+namespace {
+
+typedef std::vector<scoped_refptr<Tile> > TileVector;
+
+void SortBinTiles(ManagedTileBin bin, TileVector* tiles) {
+  switch (bin) {
+    case NOW_AND_READY_TO_DRAW_BIN:
+      break;
+    case NOW_BIN:
+    case SOON_BIN:
+    case EVENTUALLY_AND_ACTIVE_BIN:
+    case EVENTUALLY_BIN:
+    case NEVER_AND_ACTIVE_BIN:
+    case NEVER_BIN:
+      std::sort(tiles->begin(), tiles->end(), BinComparator());
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace
+
+PrioritizedTileSet::PrioritizedTileSet() {}
+
+PrioritizedTileSet::~PrioritizedTileSet() {}
+
+void PrioritizedTileSet::InsertTile(Tile* tile, ManagedTileBin bin) {
+  tiles_[bin].push_back(make_scoped_refptr(tile));
+}
+
+void PrioritizedTileSet::Clear() {
+  for (int bin = 0; bin < NUM_BINS; ++bin)
+    tiles_[bin].clear();
+}
+
+void PrioritizedTileSet::Sort() {
+  for (int bin = 0; bin < NUM_BINS; ++bin)
+    SortBinTiles(static_cast<ManagedTileBin>(bin), &tiles_[bin]);
+}
+
+PrioritizedTileSet::PriorityIterator::PriorityIterator(
+    PrioritizedTileSet* tile_set)
+    : tile_set_(tile_set),
+      current_bin_(NOW_AND_READY_TO_DRAW_BIN),
+      iterator_(tile_set->tiles_[current_bin_].begin()) {
+  if (iterator_ == tile_set_->tiles_[current_bin_].end())
+    AdvanceList();
+}
+
+PrioritizedTileSet::PriorityIterator::~PriorityIterator() {}
+
+PrioritizedTileSet::PriorityIterator&
+PrioritizedTileSet::PriorityIterator::operator++() {
+  // We can't increment past the end of the tiles.
+  DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end());
+
+  ++iterator_;
+  if (iterator_ == tile_set_->tiles_[current_bin_].end())
+    AdvanceList();
+  return *this;
+}
+
+Tile* PrioritizedTileSet::PriorityIterator::operator*() {
+  DCHECK(iterator_ != tile_set_->tiles_[current_bin_].end());
+  return iterator_->get();
+}
+
+void PrioritizedTileSet::PriorityIterator::AdvanceList() {
+  DCHECK(iterator_ == tile_set_->tiles_[current_bin_].end());
+
+  while (current_bin_ != NEVER_BIN) {
+    current_bin_ = static_cast<ManagedTileBin>(current_bin_ + 1);
+    iterator_ = tile_set_->tiles_[current_bin_].begin();
+    if (iterator_ != tile_set_->tiles_[current_bin_].end())
+      break;
+  }
+}
+
+}  // namespace cc
diff --git a/cc/resources/prioritized_tile_set.h b/cc/resources/prioritized_tile_set.h
new file mode 100644
index 0000000..fe1b2a0
--- /dev/null
+++ b/cc/resources/prioritized_tile_set.h
@@ -0,0 +1,56 @@
+// 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 CC_RESOURCES_PRIORITIZED_TILE_SET_H_
+#define CC_RESOURCES_PRIORITIZED_TILE_SET_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+#include "cc/resources/managed_tile_state.h"
+
+namespace cc {
+class Tile;
+
+class CC_EXPORT PrioritizedTileSet {
+ public:
+  PrioritizedTileSet();
+  ~PrioritizedTileSet();
+
+  void InsertTile(Tile* tile, ManagedTileBin bin);
+  void Clear();
+  void Sort();
+
+  class CC_EXPORT PriorityIterator {
+   public:
+    explicit PriorityIterator(PrioritizedTileSet* set);
+    ~PriorityIterator();
+
+    PriorityIterator& operator++();
+    Tile* operator->() { return *(*this); }
+    Tile* operator*();
+    operator bool() const {
+      return iterator_ != tile_set_->tiles_[current_bin_].end();
+    }
+
+   private:
+    void AdvanceList();
+
+    PrioritizedTileSet* tile_set_;
+    ManagedTileBin current_bin_;
+    std::vector<scoped_refptr<Tile> >::iterator iterator_;
+  };
+
+ private:
+  friend class PriorityIterator;
+
+  typedef scoped_refptr<Tile> TileRef;
+  std::vector<TileRef> tiles_[NUM_BINS];
+};
+
+}  // namespace cc
+
+#endif  // CC_RESOURCES_PRIORITIZED_TILE_SET_H_
diff --git a/cc/resources/prioritized_tile_set_unittest.cc b/cc/resources/prioritized_tile_set_unittest.cc
new file mode 100644
index 0000000..645fa04
--- /dev/null
+++ b/cc/resources/prioritized_tile_set_unittest.cc
@@ -0,0 +1,470 @@
+// 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 <algorithm>
+#include <vector>
+
+#include "cc/resources/managed_tile_state.h"
+#include "cc/resources/prioritized_tile_set.h"
+#include "cc/resources/tile.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_picture_pile_impl.h"
+#include "cc/test/fake_tile_manager.h"
+#include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/test_tile_priorities.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+
+class BinComparator {
+ public:
+  bool operator()(const scoped_refptr<Tile>& a,
+                  const scoped_refptr<Tile>& b) const {
+    const ManagedTileState& ams = a->managed_state();
+    const ManagedTileState& bms = b->managed_state();
+
+    if (ams.bin[LOW_PRIORITY_BIN] != bms.bin[LOW_PRIORITY_BIN])
+      return ams.bin[LOW_PRIORITY_BIN] < bms.bin[LOW_PRIORITY_BIN];
+
+    if (ams.required_for_activation != bms.required_for_activation)
+      return ams.required_for_activation;
+
+    if (ams.resolution != bms.resolution)
+      return ams.resolution < bms.resolution;
+
+    if (ams.time_to_needed_in_seconds !=  bms.time_to_needed_in_seconds)
+      return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
+
+    if (ams.distance_to_visible_in_pixels !=
+        bms.distance_to_visible_in_pixels) {
+      return ams.distance_to_visible_in_pixels <
+             bms.distance_to_visible_in_pixels;
+    }
+
+    gfx::Rect a_rect = a->content_rect();
+    gfx::Rect b_rect = b->content_rect();
+    if (a_rect.y() != b_rect.y())
+      return a_rect.y() < b_rect.y();
+    return a_rect.x() < b_rect.x();
+  }
+};
+
+namespace {
+
+class PrioritizedTileSetTest : public testing::Test {
+ public:
+  PrioritizedTileSetTest()
+      : output_surface_(FakeOutputSurface::Create3d()),
+        resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)),
+        tile_manager_(new FakeTileManager(&tile_manager_client_,
+                                          resource_provider_.get())),
+        picture_pile_(FakePicturePileImpl::CreatePile()) {}
+
+  scoped_refptr<Tile> CreateTile() {
+    return make_scoped_refptr(new Tile(tile_manager_.get(),
+                                       picture_pile_.get(),
+                                       settings_.default_tile_size,
+                                       gfx::Rect(),
+                                       gfx::Rect(),
+                                       1.0,
+                                       0,
+                                       0,
+                                       true));
+  }
+
+ private:
+  FakeTileManagerClient tile_manager_client_;
+  LayerTreeSettings settings_;
+  scoped_ptr<FakeOutputSurface> output_surface_;
+  scoped_ptr<ResourceProvider> resource_provider_;
+  scoped_ptr<FakeTileManager> tile_manager_;
+  scoped_refptr<FakePicturePileImpl> picture_pile_;
+};
+
+TEST_F(PrioritizedTileSetTest, EmptyIterator) {
+  PrioritizedTileSet set;
+  set.Sort();
+
+  PrioritizedTileSet::PriorityIterator it(&set);
+  EXPECT_FALSE(it);
+}
+
+TEST_F(PrioritizedTileSetTest, NonEmptyIterator) {
+  PrioritizedTileSet set;
+  scoped_refptr<Tile> tile = CreateTile();
+  set.InsertTile(tile, NOW_BIN);
+  set.Sort();
+
+  PrioritizedTileSet::PriorityIterator it(&set);
+  EXPECT_TRUE(it);
+  EXPECT_TRUE(*it == tile.get());
+  ++it;
+  EXPECT_FALSE(it);
+}
+
+TEST_F(PrioritizedTileSetTest, NowAndReadyToDrawBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in the same order as inserted.
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, NowBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, NOW_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, SoonBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, SOON_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, EventuallyAndActiveBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, EventuallyBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, EVENTUALLY_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, NeverAndActiveBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, NEVER_AND_ACTIVE_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, NeverBin) {
+  PrioritizedTileSet set;
+  TilePriority priorities[4] = {
+      TilePriorityForEventualBin(),
+      TilePriorityForNowBin(),
+      TilePriority(),
+      TilePriorityForSoonBin()};
+
+  std::vector<scoped_refptr<Tile> > tiles;
+  for (int priority = 0; priority < 4; ++priority) {
+    for (int i = 0; i < 5; ++i) {
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
+      tiles.push_back(tile);
+      set.InsertTile(tile, NEVER_BIN);
+    }
+  }
+
+  set.Sort();
+
+  // Tiles should appear in BinComparator order.
+  std::sort(tiles.begin(), tiles.end(), BinComparator());
+
+  int i = 0;
+  for (PrioritizedTileSet::PriorityIterator it(&set);
+       it;
+       ++it) {
+    EXPECT_TRUE(*it == tiles[i].get());
+    ++i;
+  }
+  EXPECT_EQ(20, i);
+}
+
+TEST_F(PrioritizedTileSetTest, TilesForEachBin) {
+  scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
+  scoped_refptr<Tile> now_bin = CreateTile();
+  scoped_refptr<Tile> soon_bin = CreateTile();
+  scoped_refptr<Tile> eventually_and_active_bin = CreateTile();
+  scoped_refptr<Tile> eventually_bin = CreateTile();
+  scoped_refptr<Tile> never_bin = CreateTile();
+  scoped_refptr<Tile> never_and_active_bin = CreateTile();
+
+  PrioritizedTileSet set;
+  set.InsertTile(soon_bin, SOON_BIN);
+  set.InsertTile(never_and_active_bin, NEVER_AND_ACTIVE_BIN);
+  set.InsertTile(eventually_bin, EVENTUALLY_BIN);
+  set.InsertTile(now_bin, NOW_BIN);
+  set.InsertTile(eventually_and_active_bin, EVENTUALLY_AND_ACTIVE_BIN);
+  set.InsertTile(never_bin, NEVER_BIN);
+  set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
+
+  set.Sort();
+
+  // Tiles should appear in order.
+  PrioritizedTileSet::PriorityIterator it(&set);
+  EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == now_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == soon_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == eventually_and_active_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == eventually_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == never_and_active_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == never_bin.get());
+  ++it;
+  EXPECT_FALSE(it);
+}
+
+TEST_F(PrioritizedTileSetTest, TilesForFirstAndLastBins) {
+  scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
+  scoped_refptr<Tile> never_bin = CreateTile();
+
+  PrioritizedTileSet set;
+  set.InsertTile(never_bin, NEVER_BIN);
+  set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
+
+  set.Sort();
+
+  // Only two tiles should appear and they should appear in order.
+  PrioritizedTileSet::PriorityIterator it(&set);
+  EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == never_bin.get());
+  ++it;
+  EXPECT_FALSE(it);
+}
+
+TEST_F(PrioritizedTileSetTest, MultipleIterators) {
+  scoped_refptr<Tile> now_and_ready_to_draw_bin = CreateTile();
+  scoped_refptr<Tile> now_bin = CreateTile();
+  scoped_refptr<Tile> soon_bin = CreateTile();
+  scoped_refptr<Tile> eventually_bin = CreateTile();
+  scoped_refptr<Tile> never_bin = CreateTile();
+
+  PrioritizedTileSet set;
+  set.InsertTile(soon_bin, SOON_BIN);
+  set.InsertTile(eventually_bin, EVENTUALLY_BIN);
+  set.InsertTile(now_bin, NOW_BIN);
+  set.InsertTile(never_bin, NEVER_BIN);
+  set.InsertTile(now_and_ready_to_draw_bin, NOW_AND_READY_TO_DRAW_BIN);
+
+  set.Sort();
+
+  // Tiles should appear in order.
+  PrioritizedTileSet::PriorityIterator it(&set);
+  EXPECT_TRUE(*it == now_and_ready_to_draw_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == now_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == soon_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == eventually_bin.get());
+  ++it;
+  EXPECT_TRUE(*it == never_bin.get());
+  ++it;
+  EXPECT_FALSE(it);
+
+  // Creating multiple iterators shouldn't affect old iterators.
+  PrioritizedTileSet::PriorityIterator second_it(&set);
+  EXPECT_TRUE(second_it);
+  EXPECT_FALSE(it);
+
+  ++second_it;
+  EXPECT_TRUE(second_it);
+  ++second_it;
+  EXPECT_TRUE(second_it);
+  EXPECT_FALSE(it);
+
+  PrioritizedTileSet::PriorityIterator third_it(&set);
+  EXPECT_TRUE(third_it);
+  ++second_it;
+  ++second_it;
+  EXPECT_TRUE(second_it);
+  EXPECT_TRUE(third_it);
+  EXPECT_FALSE(it);
+
+  ++third_it;
+  ++third_it;
+  EXPECT_TRUE(third_it);
+  EXPECT_TRUE(*third_it == soon_bin.get());
+  EXPECT_TRUE(second_it);
+  EXPECT_TRUE(*second_it == never_bin.get());
+  EXPECT_FALSE(it);
+
+  ++second_it;
+  EXPECT_TRUE(third_it);
+  EXPECT_FALSE(second_it);
+  EXPECT_FALSE(it);
+
+  set.Clear();
+
+  PrioritizedTileSet::PriorityIterator empty_it(&set);
+  EXPECT_FALSE(empty_it);
+}
+
+}  // namespace
+}  // namespace cc
+
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 408d4b1..be9b19a 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -120,6 +120,7 @@
  private:
   // Methods called by by tile manager.
   friend class TileManager;
+  friend class PrioritizedTileSet;
   friend class FakeTileManager;
   friend class BinComparator;
   ManagedTileState& managed_state() { return managed_state_; }
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 41e2631..aa6c1ad 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -27,32 +27,46 @@
 // Memory limit policy works by mapping some bin states to the NEVER bin.
 const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = {
   {  // [ALLOW_NOTHING]
-    NEVER_BIN,      // [NOW_BIN]
-    NEVER_BIN,      // [SOON_BIN]
-    NEVER_BIN,      // [EVENTUALLY_BIN]
-    NEVER_BIN       // [NEVER_BIN]
+    NEVER_BIN,                  // [NOW_AND_READY_TO_DRAW_BIN]
+    NEVER_BIN,                  // [NOW_BIN]
+    NEVER_BIN,                  // [SOON_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_BIN]
+    NEVER_BIN,                  // [NEVER_AND_ACTIVE_BIN]
+    NEVER_BIN                   // [NEVER_BIN]
   }, {  // [ALLOW_ABSOLUTE_MINIMUM]
-    NOW_BIN,        // [NOW_BIN]
-    NEVER_BIN,      // [SOON_BIN]
-    NEVER_BIN,      // [EVENTUALLY_BIN]
-    NEVER_BIN       // [NEVER_BIN]
+    NOW_AND_READY_TO_DRAW_BIN,  // [NOW_AND_READY_TO_DRAW_BIN]
+    NOW_BIN,                    // [NOW_BIN]
+    NEVER_BIN,                  // [SOON_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_BIN]
+    NEVER_BIN,                  // [NEVER_AND_ACTIVE_BIN]
+    NEVER_BIN                   // [NEVER_BIN]
   }, {  // [ALLOW_PREPAINT_ONLY]
-    NOW_BIN,         // [NOW_BIN]
-    SOON_BIN,        // [SOON_BIN]
-    NEVER_BIN,       // [EVENTUALLY_BIN]
-    NEVER_BIN        // [NEVER_BIN]
+    NOW_AND_READY_TO_DRAW_BIN,  // [NOW_AND_READY_TO_DRAW_BIN]
+    NOW_BIN,                    // [NOW_BIN]
+    SOON_BIN,                   // [SOON_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
+    NEVER_BIN,                  // [EVENTUALLY_BIN]
+    NEVER_BIN,                  // [NEVER_AND_ACTIVE_BIN]
+    NEVER_BIN                   // [NEVER_BIN]
   }, {  // [ALLOW_ANYTHING]
-    NOW_BIN,         // [NOW_BIN]
-    SOON_BIN,        // [SOON_BIN]
-    EVENTUALLY_BIN,  // [EVENTUALLY_BIN]
-    NEVER_BIN        // [NEVER_BIN]
+    NOW_AND_READY_TO_DRAW_BIN,  // [NOW_AND_READY_TO_DRAW_BIN]
+    NOW_BIN,                    // [NOW_BIN]
+    SOON_BIN,                   // [SOON_BIN]
+    EVENTUALLY_AND_ACTIVE_BIN,  // [EVENTUALLY_AND_ACTIVE_BIN]
+    EVENTUALLY_BIN,             // [EVENTUALLY_BIN]
+    NEVER_AND_ACTIVE_BIN,       // [NEVER_AND_ACTIVE_BIN]
+    NEVER_BIN                   // [NEVER_BIN]
   }
 };
 
 // Determine bin based on three categories of tiles: things we need now,
 // things we need soon, and eventually.
 inline ManagedTileBin BinFromTilePriority(const TilePriority& prio,
-                                          TreePriority tree_priority) {
+                                          TreePriority tree_priority,
+                                          bool is_ready_to_draw,
+                                          bool is_active) {
   // The amount of time for which we want to have prepainting coverage.
   const float kPrepaintingWindowTimeSeconds = 1.0f;
   const float kBackflingGuardDistancePixels = 314.0f;
@@ -64,19 +78,19 @@
 
   if (prio.distance_to_visible_in_pixels ==
       std::numeric_limits<float>::infinity())
-    return NEVER_BIN;
+    return is_active ? NEVER_AND_ACTIVE_BIN : NEVER_BIN;
 
   if (can_be_in_now_bin && prio.time_to_visible_in_seconds == 0)
-    return NOW_BIN;
+    return is_ready_to_draw ? NOW_AND_READY_TO_DRAW_BIN : NOW_BIN;
 
   if (prio.resolution == NON_IDEAL_RESOLUTION)
-    return EVENTUALLY_BIN;
+    return is_active ? EVENTUALLY_AND_ACTIVE_BIN : EVENTUALLY_BIN;
 
   if (prio.distance_to_visible_in_pixels < kBackflingGuardDistancePixels ||
       prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds)
     return SOON_BIN;
 
-  return EVENTUALLY_BIN;
+  return is_active ? EVENTUALLY_AND_ACTIVE_BIN : EVENTUALLY_BIN;
 }
 
 // Limit to the number of raster tasks that can be scheduled.
@@ -145,8 +159,8 @@
   // our memory usage to drop to zero.
   global_state_ = GlobalStateThatImpactsTilePriority();
 
-  // Clear |sorted_tiles_| so that tiles kept alive by it can be freed.
-  sorted_tiles_.clear();
+  // Clear |prioritized_tiles_| so that tiles kept alive by it can be freed.
+  prioritized_tiles_.Clear();
   DCHECK_EQ(0u, tiles_.size());
 
   TileVector empty;
@@ -196,7 +210,8 @@
   raster_worker_pool_->CheckForCompletedTasks();
 
   TileVector tiles_that_need_to_be_rasterized;
-  AssignGpuMemoryToTiles(sorted_tiles_, &tiles_that_need_to_be_rasterized);
+  AssignGpuMemoryToTiles(&prioritized_tiles_,
+                         &tiles_that_need_to_be_rasterized);
 
   // |tiles_that_need_to_be_rasterized| will be empty when we reach a
   // steady memory state. Keep scheduling tasks until we reach this state.
@@ -233,51 +248,9 @@
   client_->NotifyReadyToActivate();
 }
 
-class BinComparator {
- public:
-  bool operator()(const scoped_refptr<Tile>& a,
-                  const scoped_refptr<Tile>& b) const {
-    const ManagedTileState& ams = a->managed_state();
-    const ManagedTileState& bms = b->managed_state();
-
-    if (ams.visible_and_ready_to_draw != bms.visible_and_ready_to_draw)
-      return ams.visible_and_ready_to_draw;
-
-    if (ams.bin[HIGH_PRIORITY_BIN] != bms.bin[HIGH_PRIORITY_BIN])
-      return ams.bin[HIGH_PRIORITY_BIN] < bms.bin[HIGH_PRIORITY_BIN];
-
-    if (ams.bin[LOW_PRIORITY_BIN] != bms.bin[LOW_PRIORITY_BIN])
-      return ams.bin[LOW_PRIORITY_BIN] < bms.bin[LOW_PRIORITY_BIN];
-
-    if (ams.required_for_activation != bms.required_for_activation)
-      return ams.required_for_activation;
-
-    if (ams.resolution != bms.resolution)
-      return ams.resolution < bms.resolution;
-
-    if (ams.time_to_needed_in_seconds !=  bms.time_to_needed_in_seconds)
-      return ams.time_to_needed_in_seconds < bms.time_to_needed_in_seconds;
-
-    if (ams.distance_to_visible_in_pixels !=
-        bms.distance_to_visible_in_pixels) {
-      return ams.distance_to_visible_in_pixels <
-             bms.distance_to_visible_in_pixels;
-    }
-
-    gfx::Rect a_rect = a->content_rect();
-    gfx::Rect b_rect = b->content_rect();
-    if (a_rect.y() != b_rect.y())
-      return a_rect.y() < b_rect.y();
-    return a_rect.x() < b_rect.x();
-  }
-};
-
-void TileManager::GetTilesWithAssignedBins(TileRefVector* tiles) {
+void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
   TRACE_EVENT0("cc", "TileManager::GetTilesWithAssignedBins");
 
-  DCHECK_EQ(0u, tiles->size());
-  tiles->reserve(tiles_.size());
-
   const TileMemoryLimitPolicy memory_policy = global_state_.memory_limit_policy;
   const TreePriority tree_priority = global_state_.tree_priority;
 
@@ -302,6 +275,11 @@
         break;
     }
 
+    bool tile_is_ready_to_draw = tile->IsReadyToDraw();
+    bool tile_is_active =
+        tile_is_ready_to_draw ||
+        !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
+
     mts.resolution = prio[HIGH_PRIORITY_BIN].resolution;
     mts.time_to_needed_in_seconds =
         prio[HIGH_PRIORITY_BIN].time_to_visible_in_seconds;
@@ -309,56 +287,80 @@
         prio[HIGH_PRIORITY_BIN].distance_to_visible_in_pixels;
     mts.required_for_activation =
         prio[HIGH_PRIORITY_BIN].required_for_activation;
-    mts.bin[HIGH_PRIORITY_BIN] =
-        BinFromTilePriority(prio[HIGH_PRIORITY_BIN], tree_priority);
-    mts.bin[LOW_PRIORITY_BIN] =
-        BinFromTilePriority(prio[LOW_PRIORITY_BIN], tree_priority);
-    mts.gpu_memmgr_stats_bin =
-        BinFromTilePriority(tile->combined_priority(), tree_priority);
 
-    mts.tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][
-        BinFromTilePriority(tile->priority(ACTIVE_TREE), tree_priority)];
-    mts.tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][
-        BinFromTilePriority(tile->priority(PENDING_TREE), tree_priority)];
+    mts.bin[HIGH_PRIORITY_BIN] =
+        BinFromTilePriority(prio[HIGH_PRIORITY_BIN],
+                            tree_priority,
+                            tile_is_ready_to_draw,
+                            tile_is_active);
+    mts.bin[LOW_PRIORITY_BIN] =
+        BinFromTilePriority(prio[LOW_PRIORITY_BIN],
+                            tree_priority,
+                            tile_is_ready_to_draw,
+                            tile_is_active);
+    mts.gpu_memmgr_stats_bin =
+        BinFromTilePriority(tile->combined_priority(),
+                            tree_priority,
+                            tile_is_ready_to_draw,
+                            tile_is_active);
+
+    ManagedTileBin active_bin =
+        BinFromTilePriority(tile->priority(ACTIVE_TREE),
+                            tree_priority,
+                            tile_is_ready_to_draw,
+                            tile_is_active);
+    mts.tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
+
+    ManagedTileBin pending_bin =
+        BinFromTilePriority(tile->priority(PENDING_TREE),
+                            tree_priority,
+                            tile_is_ready_to_draw,
+                            tile_is_active);
+    mts.tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
 
     for (int i = 0; i < NUM_BIN_PRIORITIES; ++i)
       mts.bin[i] = kBinPolicyMap[memory_policy][mts.bin[i]];
 
     mts.visible_and_ready_to_draw =
-        mts.tree_bin[ACTIVE_TREE] == NOW_BIN && tile->IsReadyToDraw();
+        mts.tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
 
-    // Skip and free resources for tiles in the NEVER_BIN on both trees.
-    if (mts.is_in_never_bin_on_both_trees())
+    if (mts.is_in_never_bin_on_both_trees()) {
       FreeResourcesForTile(tile);
-    else
-      tiles->push_back(make_scoped_refptr(tile));
+      continue;
+    }
+
+    // Note that if the tile is visible_and_ready_to_draw, then we always want
+    // the priority to be NOW_AND_READY_TO_DRAW_BIN, even if HIGH_PRIORITY_BIN
+    // is something different. The reason for this is that if we're prioritizing
+    // the pending tree, we still want visible tiles to take the highest
+    // priority.
+    ManagedTileBin priority_bin = mts.visible_and_ready_to_draw
+                                  ? NOW_AND_READY_TO_DRAW_BIN
+                                  : mts.bin[HIGH_PRIORITY_BIN];
+
+    // Insert the tile into a priority set.
+    tiles->InsertTile(tile, priority_bin);
   }
 }
 
-void TileManager::SortTiles(TileRefVector* tiles) {
-  TRACE_EVENT0("cc", "TileManager::SortTiles");
-
-  // Sort by bin, resolution and time until needed.
-  std::sort(tiles->begin(), tiles->end(), BinComparator());
-}
-
-void TileManager::GetSortedTilesWithAssignedBins(TileRefVector* tiles) {
-  TRACE_EVENT0("cc", "TileManager::GetSortedTilesWithAssignedBins");
+void TileManager::GetPrioritizedTileSet(PrioritizedTileSet* tiles) {
+  TRACE_EVENT0("cc", "TileManager::GetPrioritizedTileSet");
 
   GetTilesWithAssignedBins(tiles);
-  SortTiles(tiles);
+  tiles->Sort();
 }
 
 void TileManager::ManageTiles() {
   TRACE_EVENT0("cc", "TileManager::ManageTiles");
 
-  // Clear |sorted_tiles_| so that tiles kept alive by it can be freed.
-  sorted_tiles_.clear();
+  // Clear |prioritized_tiles_| so that tiles kept alive by it can be freed.
+  prioritized_tiles_.Clear();
 
-  GetSortedTilesWithAssignedBins(&sorted_tiles_);
+  GetPrioritizedTileSet(&prioritized_tiles_);
 
   TileVector tiles_that_need_to_be_rasterized;
-  AssignGpuMemoryToTiles(sorted_tiles_, &tiles_that_need_to_be_rasterized);
+  AssignGpuMemoryToTiles(&prioritized_tiles_,
+                         &tiles_that_need_to_be_rasterized);
   CleanUpUnusedImageDecodeTasks();
 
   TRACE_EVENT_INSTANT1(
@@ -406,7 +408,8 @@
       continue;
 
     size_t tile_bytes = tile->bytes_consumed_if_allocated();
-    if (mts.gpu_memmgr_stats_bin == NOW_BIN)
+    if ((mts.gpu_memmgr_stats_bin == NOW_BIN) ||
+        (mts.gpu_memmgr_stats_bin == NOW_AND_READY_TO_DRAW_BIN))
       *memory_required_bytes += tile_bytes;
     if (mts.gpu_memmgr_stats_bin != NEVER_BIN)
       *memory_nice_to_have_bytes += tile_bytes;
@@ -468,7 +471,7 @@
 }
 
 void TileManager::AssignGpuMemoryToTiles(
-    const TileRefVector& sorted_tiles,
+    PrioritizedTileSet* tiles,
     TileVector* tiles_that_need_to_be_rasterized) {
   TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles");
 
@@ -476,10 +479,10 @@
   // the needs-to-be-rasterized queue.
   size_t bytes_releasable = 0;
   size_t resources_releasable = 0;
-  for (TileRefVector::const_iterator it = sorted_tiles.begin();
-       it != sorted_tiles.end();
+  for (PrioritizedTileSet::PriorityIterator it(tiles);
+       it;
        ++it) {
-    const Tile* tile = it->get();
+    const Tile* tile = *it;
     const ManagedTileState& mts = tile->managed_state();
     for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
       if (mts.tile_versions[mode].resource_) {
@@ -512,10 +515,10 @@
   bool oomed = false;
 
   unsigned schedule_priority = 1u;
-  for (TileRefVector::const_iterator it = sorted_tiles.begin();
-       it != sorted_tiles.end();
+  for (PrioritizedTileSet::PriorityIterator it(tiles);
+       it;
        ++it) {
-    Tile* tile = it->get();
+    Tile* tile = *it;
     ManagedTileState& mts = tile->managed_state();
 
     mts.scheduled_priority = schedule_priority++;
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index f6f5785..2e226c9 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -16,6 +16,7 @@
 #include "cc/resources/managed_tile_state.h"
 #include "cc/resources/memory_history.h"
 #include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/prioritized_tile_set.h"
 #include "cc/resources/raster_worker_pool.h"
 #include "cc/resources/resource_pool.h"
 #include "cc/resources/tile.h"
@@ -98,7 +99,6 @@
   virtual void DidFinishRunningTasksRequiredForActivation() OVERRIDE;
 
   typedef std::vector<Tile*> TileVector;
-  typedef std::vector<scoped_refptr<Tile> > TileRefVector;
   typedef std::set<Tile*> TileSet;
 
   // Virtual for test
@@ -106,11 +106,10 @@
       const TileVector& tiles_that_need_to_be_rasterized);
 
   void AssignGpuMemoryToTiles(
-      const TileRefVector& sorted_tiles,
+      PrioritizedTileSet* tiles,
       TileVector* tiles_that_need_to_be_rasterized);
-  void GetTilesWithAssignedBins(TileRefVector* tiles);
-  void SortTiles(TileRefVector* tiles);
-  void GetSortedTilesWithAssignedBins(TileRefVector* tiles);
+  void GetTilesWithAssignedBins(PrioritizedTileSet* tiles);
+  void GetPrioritizedTileSet(PrioritizedTileSet* tiles);
 
  private:
   void OnImageDecodeTaskCompleted(
@@ -142,7 +141,7 @@
   typedef base::hash_map<Tile::Id, Tile*> TileMap;
   TileMap tiles_;
 
-  TileRefVector sorted_tiles_;
+  PrioritizedTileSet prioritized_tiles_;
 
   bool all_tiles_that_need_to_be_rasterized_have_memory_;
   bool all_tiles_required_for_activation_have_memory_;
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 677dffc..ca6f997 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -6,8 +6,10 @@
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/test_tile_priorities.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -19,53 +21,6 @@
 static const int kWarmupRuns = 5;
 static const int kTimeCheckInterval = 10;
 
-class FakePicturePileImpl : public PicturePileImpl {
- public:
-  FakePicturePileImpl() {
-    gfx::Size size(std::numeric_limits<int>::max(),
-                   std::numeric_limits<int>::max());
-    Resize(size);
-    recorded_region_ = Region(gfx::Rect(size));
-  }
-
- protected:
-  virtual ~FakePicturePileImpl() {}
-};
-
-class TilePriorityForSoonBin : public TilePriority {
- public:
-  TilePriorityForSoonBin() : TilePriority(
-            HIGH_RESOLUTION,
-            0.5,
-            300.0) {}
-};
-
-class TilePriorityForEventualBin : public TilePriority {
- public:
-    TilePriorityForEventualBin() : TilePriority(
-            NON_IDEAL_RESOLUTION,
-            1.0,
-            315.0) {}
-};
-
-class TilePriorityForNowBin : public TilePriority {
- public:
-    TilePriorityForNowBin() : TilePriority(
-            HIGH_RESOLUTION,
-            0,
-            0) {}
-};
-
-class TilePriorityRequiredForActivation : public TilePriority {
- public:
-    TilePriorityRequiredForActivation() : TilePriority(
-            HIGH_RESOLUTION,
-            0,
-            0) {
-      required_for_activation = true;
-    }
-};
-
 class TileManagerPerfTest : public testing::Test {
  public:
   typedef std::vector<scoped_refptr<Tile> > TileVector;
@@ -87,7 +42,7 @@
     state.tree_priority = SMOOTHNESS_TAKES_PRIORITY;
 
     tile_manager_->SetGlobalState(state);
-    picture_pile_ = make_scoped_refptr(new FakePicturePileImpl());
+    picture_pile_ = FakePicturePileImpl::CreatePile();
   }
 
   virtual void TearDown() OVERRIDE {
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index f55f1e4..6fb0690 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -5,60 +5,15 @@
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
 #include "cc/test/fake_output_surface.h"
+#include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
+#include "cc/test/test_tile_priorities.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
 namespace {
 
-class FakePicturePileImpl : public PicturePileImpl {
- public:
-  FakePicturePileImpl() {
-    gfx::Size size(std::numeric_limits<int>::max(),
-                   std::numeric_limits<int>::max());
-    Resize(size);
-    recorded_region_ = Region(gfx::Rect(size));
-  }
-
- protected:
-  virtual ~FakePicturePileImpl() {}
-};
-
-class TilePriorityForSoonBin : public TilePriority {
- public:
-  TilePriorityForSoonBin() : TilePriority(
-            HIGH_RESOLUTION,
-            0.5,
-            300.0) {}
-};
-
-class TilePriorityForEventualBin : public TilePriority {
- public:
-    TilePriorityForEventualBin() : TilePriority(
-            NON_IDEAL_RESOLUTION,
-            1.0,
-            315.0) {}
-};
-
-class TilePriorityForNowBin : public TilePriority {
- public:
-    TilePriorityForNowBin() : TilePriority(
-            HIGH_RESOLUTION,
-            0,
-            0) {}
-};
-
-class TilePriorityRequiredForActivation : public TilePriority {
- public:
-    TilePriorityRequiredForActivation() : TilePriority(
-            HIGH_RESOLUTION,
-            0,
-            0) {
-      required_for_activation = true;
-    }
-};
-
 class TileManagerTest : public testing::TestWithParam<bool> {
  public:
   typedef std::vector<scoped_refptr<Tile> > TileVector;
@@ -90,7 +45,7 @@
     state.tree_priority = tree_priority;
 
     tile_manager_->SetGlobalState(state);
-    picture_pile_ = make_scoped_refptr(new FakePicturePileImpl());
+    picture_pile_ = FakePicturePileImpl::CreatePile();
   }
 
   void SetTreePriority(TreePriority tree_priority) {
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index bdf40a5..dd383a6 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -14,6 +14,7 @@
       append_quads_count_(0) {
   pile_ = pile;
   SetBounds(pile_->size());
+  CreateTilingSetIfNeeded();
 }
 
 FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id)
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 2eeaeef..a0c7829 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -32,14 +32,6 @@
   using PictureLayerImpl::CleanUpTilingsOnActiveLayer;
   using PictureLayerImpl::CanHaveTilings;
   using PictureLayerImpl::MarkVisibleResourcesAsRequired;
-  using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
-
-  bool needs_post_commit_initialization() const {
-    return needs_post_commit_initialization_;
-  }
-
-  bool is_using_lcd_text() const { return is_using_lcd_text_; }
-  void force_set_lcd_text(bool enabled) { is_using_lcd_text_ = enabled; }
 
   PictureLayerTiling* HighResTiling() const;
   PictureLayerTiling* LowResTiling() const;
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 80df818..c79d0ae 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -4,6 +4,7 @@
 
 #include "cc/test/fake_picture_pile_impl.h"
 
+#include <limits>
 #include <utility>
 
 #include "cc/test/fake_rendering_stats_instrumentation.h"
@@ -42,6 +43,15 @@
   return pile;
 }
 
+scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreatePile() {
+  scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
+  gfx::Size size(std::numeric_limits<int>::max(),
+                 std::numeric_limits<int>::max());
+  pile->Resize(size);
+  pile->recorded_region_ = Region(gfx::Rect(size));
+  return pile;
+}
+
 void FakePicturePileImpl::AddRecordingAt(int x, int y) {
   EXPECT_GE(x, 0);
   EXPECT_GE(y, 0);
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index a606934..1b35ecf 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -21,6 +21,8 @@
       gfx::Size tile_size,
       gfx::Size layer_bounds);
 
+  static scoped_refptr<FakePicturePileImpl> CreatePile();
+
   TilingData& tiling() { return tiling_; }
 
   void AddRecordingAt(int x, int y);
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index e302a23..c132254 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -42,10 +42,10 @@
 
 void FakeTileManager::AssignMemoryToTiles() {
   tiles_for_raster.clear();
-  all_tiles.clear();
+  all_tiles.Clear();
 
-  GetSortedTilesWithAssignedBins(&all_tiles);
-  AssignGpuMemoryToTiles(all_tiles, &tiles_for_raster);
+  GetPrioritizedTileSet(&all_tiles);
+  AssignGpuMemoryToTiles(&all_tiles, &tiles_for_raster);
 }
 
 bool FakeTileManager::HasBeenAssignedMemory(Tile* tile) {
diff --git a/cc/test/fake_tile_manager.h b/cc/test/fake_tile_manager.h
index 77dbb78..f49c0ee 100644
--- a/cc/test/fake_tile_manager.h
+++ b/cc/test/fake_tile_manager.h
@@ -24,7 +24,7 @@
   virtual ~FakeTileManager();
 
   std::vector<Tile*> tiles_for_raster;
-  std::vector<scoped_refptr<Tile> > all_tiles;
+  PrioritizedTileSet all_tiles;
 };
 
 }  // namespace cc
diff --git a/cc/test/test_tile_priorities.cc b/cc/test/test_tile_priorities.cc
new file mode 100644
index 0000000..f83f9b9
--- /dev/null
+++ b/cc/test/test_tile_priorities.cc
@@ -0,0 +1,23 @@
+// 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 "cc/test/test_tile_priorities.h"
+
+namespace cc {
+
+TilePriorityForSoonBin::TilePriorityForSoonBin()
+    : TilePriority(HIGH_RESOLUTION, 0.5, 300.0) {}
+
+TilePriorityForEventualBin::TilePriorityForEventualBin()
+    : TilePriority(NON_IDEAL_RESOLUTION, 1.0, 315.0) {}
+
+TilePriorityForNowBin::TilePriorityForNowBin()
+    : TilePriority(HIGH_RESOLUTION, 0, 0) {}
+
+TilePriorityRequiredForActivation::TilePriorityRequiredForActivation()
+    : TilePriority(HIGH_RESOLUTION, 0, 0) {
+  required_for_activation = true;
+}
+
+}  // namespace cc
diff --git a/cc/test/test_tile_priorities.h b/cc/test/test_tile_priorities.h
new file mode 100644
index 0000000..cc54105
--- /dev/null
+++ b/cc/test/test_tile_priorities.h
@@ -0,0 +1,34 @@
+// 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 CC_TEST_TEST_TILE_PRIORITIES_H_
+#define CC_TEST_TEST_TILE_PRIORITIES_H_
+
+#include "cc/resources/tile_priority.h"
+
+namespace cc {
+
+class TilePriorityForSoonBin : public TilePriority {
+ public:
+  TilePriorityForSoonBin();
+};
+
+class TilePriorityForEventualBin : public TilePriority {
+ public:
+  TilePriorityForEventualBin();
+};
+
+class TilePriorityForNowBin : public TilePriority {
+ public:
+  TilePriorityForNowBin();
+};
+
+class TilePriorityRequiredForActivation : public TilePriority {
+ public:
+  TilePriorityRequiredForActivation();
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_TEST_TILE_PRIORITIES_H_
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 67411aa..b18a88a 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -3313,13 +3313,19 @@
     child_ = PushPropertiesCountingLayer::Create();
     child2_ = PushPropertiesCountingLayer::Create();
     grandchild_ = PushPropertiesCountingLayer::Create();
-    leaf_scrollbar_layer_ =
-        FakeScrollbarLayer::Create(false, false, root_->id());
+
+    if (layer_tree_host()->settings().impl_side_painting)
+      leaf_picture_layer_ = FakePictureLayer::Create(&client_);
+    else
+      leaf_content_layer_ = FakeContentLayer::Create(&client_);
 
     root_->AddChild(child_);
     root_->AddChild(child2_);
     child_->AddChild(grandchild_);
-    child2_->AddChild(leaf_scrollbar_layer_);
+    if (leaf_picture_layer_)
+      child2_->AddChild(leaf_picture_layer_);
+    if (leaf_content_layer_)
+      child2_->AddChild(leaf_content_layer_);
 
     other_root_ = PushPropertiesCountingLayer::Create();
 
@@ -3338,10 +3344,16 @@
               child2_->push_properties_count());
     EXPECT_EQ(expected_push_properties_other_root_,
               other_root_->push_properties_count());
-    EXPECT_EQ(expected_push_properties_leaf_layer_,
-              leaf_scrollbar_layer_->push_properties_count());
+    if (leaf_content_layer_) {
+      EXPECT_EQ(expected_push_properties_leaf_layer_,
+                leaf_content_layer_->push_properties_count());
+    }
+    if (leaf_picture_layer_) {
+      EXPECT_EQ(expected_push_properties_leaf_layer_,
+                leaf_picture_layer_->push_properties_count());
+    }
 
-    // The scrollbar layer always needs to be pushed.
+    // The content/picture layer always needs to be pushed.
     if (root_->layer_tree_host()) {
       EXPECT_TRUE(root_->descendant_needs_push_properties());
       EXPECT_FALSE(root_->needs_push_properties());
@@ -3350,9 +3362,13 @@
       EXPECT_TRUE(child2_->descendant_needs_push_properties());
       EXPECT_FALSE(child2_->needs_push_properties());
     }
-    if (leaf_scrollbar_layer_->layer_tree_host()) {
-      EXPECT_FALSE(leaf_scrollbar_layer_->descendant_needs_push_properties());
-      EXPECT_TRUE(leaf_scrollbar_layer_->needs_push_properties());
+    if (leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) {
+      EXPECT_FALSE(leaf_content_layer_->descendant_needs_push_properties());
+      EXPECT_TRUE(leaf_content_layer_->needs_push_properties());
+    }
+    if (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host()) {
+      EXPECT_FALSE(leaf_picture_layer_->descendant_needs_push_properties());
+      EXPECT_TRUE(leaf_picture_layer_->needs_push_properties());
     }
 
     // child_ and grandchild_ don't persist their need to push properties.
@@ -3463,7 +3479,8 @@
 
     // Content/Picture layers require PushProperties every commit that they are
     // in the tree.
-    if (leaf_scrollbar_layer_->layer_tree_host())
+    if ((leaf_content_layer_.get() && leaf_content_layer_->layer_tree_host()) ||
+        (leaf_picture_layer_.get() && leaf_picture_layer_->layer_tree_host()))
       ++expected_push_properties_leaf_layer_;
   }
 
@@ -3476,7 +3493,8 @@
   scoped_refptr<PushPropertiesCountingLayer> child2_;
   scoped_refptr<PushPropertiesCountingLayer> grandchild_;
   scoped_refptr<PushPropertiesCountingLayer> other_root_;
-  scoped_refptr<FakeScrollbarLayer> leaf_scrollbar_layer_;
+  scoped_refptr<FakeContentLayer> leaf_content_layer_;
+  scoped_refptr<FakePictureLayer> leaf_picture_layer_;
   size_t expected_push_properties_root_;
   size_t expected_push_properties_child_;
   size_t expected_push_properties_child2_;
diff --git a/chrome/VERSION b/chrome/VERSION
index 3036542..8bdd7b3 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=30
 MINOR=0
-BUILD=1590
+BUILD=1591
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
index 972af11..278a9cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/TabBase.java
@@ -20,6 +20,8 @@
  * parent classes.
  */
 public abstract class TabBase {
+    public static final int INVALID_TAB_ID = -1;
+
     private final WindowAndroid mWindowAndroid;
     private int mNativeTabAndroid;
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 485ed5d..ce595e8 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -1000,7 +1000,7 @@
           &amp;Search <ph name="SEARCH_ENGINE">$1<ex>Google</ex></ph> for '<ph name="SEARCH_TERMS">$2<ex>flowers</ex></ph>'
         </message>
         <message name="IDS_CONTENT_CONTEXT_SEARCHWEBFORIMAGE" desc="In Title Case: The name of the Search For Image command in the content area context menu">
-          &amp;Search <ph name="SEARCH_ENGINE">$1<ex>Google</ex></ph> for this image
+          &amp;Search <ph name="SEARCH_ENGINE">$1<ex>Google</ex></ph> for this Image
         </message>
         <message name="IDS_CONTENT_CONTEXT_GOTOURL" desc="In Title Case: The name of the Go to url for 'string' command in the content area context menu">
           &amp;Go to <ph name="URL">$1<ex>http://www.google.com/</ex></ph>
@@ -1611,1070 +1611,6 @@
         <ph name="ENGINE_NAME">$1<ex>Google</ex></ph> (Default)
       </message>
 
-      <message name="IDS_TIME_SECS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_SEC_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_SEC_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_SECS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_SECS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_SECS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_SECS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_SECS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_SECS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_SECS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_SECS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_MINS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_MIN_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_MIN_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_MINS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_MINS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_MINS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_MINS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_MINS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_MINS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_MINS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_MINS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_HOURS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_HOUR_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_HOUR_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_HOURS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_HOURS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_HOURS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_HOURS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_HOURS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_HOURS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_HOURS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_HOURS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_DAYS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_DAY_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_DAY_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_DAYS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_DAYS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_DAYS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DAYS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_DAYS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DAYS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_DAYS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_DAYS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_REMAINING_SECS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs left
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_REMAINING_SEC_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec left
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_REMAINING_SEC_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_REMAINING_SECS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs left
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_REMAINING_SECS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_SECS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs left
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_SECS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_SECS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs left
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_SECS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_REMAINING_SECS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs left
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_REMAINING_SECS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_REMAINING_MINS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins left
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_REMAINING_MIN_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min left
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_REMAINING_MIN_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_REMAINING_MINS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins left
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_REMAINING_MINS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_MINS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins left
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_MINS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_MINS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins left
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_MINS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_REMAINING_MINS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins left
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_REMAINING_MINS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_REMAINING_LONG_MINS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes left
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute left
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes left
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_LONG_MINS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes left
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_LONG_MINS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes left
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_REMAINING_LONG_MINS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes left
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_REMAINING_HOURS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours left
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_REMAINING_HOUR_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour left
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_REMAINING_HOUR_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_REMAINING_HOURS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours left
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_HOURS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours left
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_HOURS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours left
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_REMAINING_HOURS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours left
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_REMAINING_DAYS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days left
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_REMAINING_DAY_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day left
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_REMAINING_DAY_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_REMAINING_DAYS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days left
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_DAYS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days left
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_REMAINING_DAYS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days left
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_REMAINING_DAYS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days left
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_DURATION_LONG_SECS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_DURATION_LONG_SECS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_DURATION_LONG_SECS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_DURATION_LONG_SECS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_DURATION_LONG_SECS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_DURATION_LONG_MINS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_DURATION_LONG_MINS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_DURATION_LONG_MINS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_DURATION_LONG_MINS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_DURATION_LONG_MINS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_TIME_ELAPSED_SECS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs ago
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_ELAPSED_SEC_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec ago
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_SEC_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_ELAPSED_SECS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs ago
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_SECS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs ago
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_SECS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs ago
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_ELAPSED_SECS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs ago
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_ELAPSED_MINS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins ago
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_ELAPSED_MIN_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min ago
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_MIN_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_ELAPSED_MINS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins ago
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_MINS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins ago
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_MINS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins ago
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_ELAPSED_MINS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins ago
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_ELAPSED_HOURS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours ago
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour ago
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_ELAPSED_HOURS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours ago
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_HOURS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours ago
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_HOURS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours ago
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_ELAPSED_HOURS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours ago
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-
-      <message name="IDS_TIME_ELAPSED_DAYS_DEFAULT"
-               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
-        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days ago
-      </message>
-
-      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message name="IDS_TIME_ELAPSED_DAY_SINGULAR"
-               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
-        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day ago
-      </message>
-      </if>
-      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_DAY_SINGULAR"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ar', 'ro', 'lv']">
-      <message name="IDS_TIME_ELAPSED_DAYS_ZERO"
-               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
-        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days ago
-      </message>
-      </if>
-      <if expr="lang not in ['ar', 'ro', 'lv']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_ZERO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang in ['ga', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_DAYS_TWO"
-               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
-        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days ago
-      </message>
-      </if>
-      <if expr="lang not in ['ga', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_TWO"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message name="IDS_TIME_ELAPSED_DAYS_FEW"
-               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
-        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days ago
-      </message>
-      </if>
-      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
-      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_FEW"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <if expr="lang == 'ar'">
-      <message name="IDS_TIME_ELAPSED_DAYS_MANY"
-               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
-        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days ago
-      </message>
-      </if>
-      <if expr="lang != 'ar'">
-      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_MANY"
-               desc="">
-        NA
-      </message>
-      </if>
-
-      <message name="IDS_PAST_TIME_TODAY" desc="Relative day today">
-        Today
-      </message>
-      <message name="IDS_PAST_TIME_YESTERDAY" desc="Relative day yesterday">
-        Yesterday
-      </message>
       <!-- Download Shelf-->
       <if expr="is_macosx">
         <message name="IDS_SHOW_ALL"
@@ -7495,14 +6431,6 @@
       <message name="IDS_FLAGS_ENABLE_DEVICE_MOTION_DESCRIPTION" desc="Description for the flag to enable device motion.">
         Enables device motion DOM events in JavaScript.
       </message>
-      <if expr="is_android">
-        <message name="IDS_FLAGS_ENABLE_CAST_NAME" desc="Name of the flag to enable Google Cast support.">
-          Enable Google Cast support
-        </message>
-        <message name="IDS_FLAGS_ENABLE_CAST_DESCRIPTION" desc="Description for the flag to enable playing videos remotely on Google Cast receivers.">
-          Enable playing videos remotely on Google Cast receivers.
-        </message>
-      </if>
 
       <!-- Crashes -->
       <message name="IDS_CRASHES_TITLE" desc="Title for the chrome://crashes page.">
@@ -8520,7 +7448,7 @@
 
       <!-- Managed User Avatar Menu -->
       <message name="IDS_MANAGED_USER_INFO" desc="Text which explains that a supervised user is managed by a custodian.">
-        This user is supervised by <ph name="CUSTODIAN_NAME">$1<ex>Jane Doe</ex></ph>. Usage and history from this user may be viewed by the manager.
+        This user is supervised by <ph name="CUSTODIAN_EMAIL">$1<ex>Jane.Doe@gmail.com</ex></ph>. Usage and history from this user can be reviewed by the manager on chrome.com.
       </message>
       <message name="IDS_MANAGED_USER_AVATAR_LABEL" desc="A label for the supervised user which is used in the avatar menu and as a label in the titlebar.">
         Supervised user
diff --git a/chrome/app/policy/policy_templates.json b/chrome/app/policy/policy_templates.json
index 1cc9245..10ad804 100644
--- a/chrome/app/policy/policy_templates.json
+++ b/chrome/app/policy/policy_templates.json
@@ -117,7 +117,7 @@
 #   persistent IDs for all fields (but not for groups!) are needed. These are
 #   specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
 #   because doing so would break the deployed wire format!
-#   For your editing convenience: highest ID currently used: 235
+#   For your editing convenience: highest ID currently used: 236
 #
 # Placeholders:
 #   The following placeholder strings are automatically substituted:
@@ -4065,6 +4065,20 @@
       The format of the value follows the names of timezones in the "IANA Time Zone Database" (see "http://en.wikipedia.org/wiki/List_of_tz_database_time"). In particular, most timezones can be referred to by "continent/large_city" or "ocean/large_city".''',
     },
     {
+      'name': 'SystemUse24HourClock',
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:30-'],
+      'device_only': True,
+      'features': {
+        'dynamic_refresh': True,
+      },
+      'example_value': True,
+      'id': 236,
+      'caption': '''Use 24 hour clock by default''',
+      'desc': '''Specifies the clock format be used for the device. Users can override clock format for the current session. However, on logout it is set back to the specified value. If an empty string is provided, device owner preference is used.''',
+    },
+    {
       'name': 'ShowLogoutButtonInTray',
       'type': 'main',
       'schema': { 'type': 'boolean' },
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e23918a..cffd974 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1606,22 +1606,6 @@
     SINGLE_VALUE_TYPE(switches::kDisableAppList)
   },
 #endif
-  {
-    "enable-device-motion",
-    IDS_FLAGS_ENABLE_DEVICE_MOTION_NAME,
-    IDS_FLAGS_ENABLE_DEVICE_MOTION_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableDeviceMotion)
-  },
-#if defined(OS_ANDROID)
-  {
-    "enable-cast",
-    IDS_FLAGS_ENABLE_CAST_NAME,
-    IDS_FLAGS_ENABLE_CAST_DESCRIPTION,
-    kOsAndroid,
-    SINGLE_VALUE_TYPE(switches::kEnableCast)
-  },
-#endif
 };
 
 const Experiment* experiments = kExperiments;
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc
index 8944515..563f46a 100644
--- a/chrome/browser/android/provider/chrome_browser_provider.cc
+++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -1040,7 +1040,7 @@
     RemoveSearchTermsFromAPITask(AndroidHistoryProviderService* service,
                                  CancelableRequestConsumer* cancelable_consumer,
                                  Profile* profile)
-        : SearchTermTask(service, cancelable_consumer, profile) {}
+        : SearchTermTask(service, cancelable_consumer, profile), result_() {}
 
   int Run(const std::string& selection,
           const std::vector<string16>& selection_args) {
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.cc b/chrome/browser/autocomplete/zero_suggest_provider.cc
index bd850a6..2369385 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.cc
+++ b/chrome/browser/autocomplete/zero_suggest_provider.cc
@@ -19,6 +19,7 @@
 #include "chrome/browser/autocomplete/history_url_provider.h"
 #include "chrome/browser/autocomplete/search_provider.h"
 #include "chrome/browser/autocomplete/url_prefix.h"
+#include "chrome/browser/google/google_util.h"
 #include "chrome/browser/metrics/variations/variations_http_header_provider.h"
 #include "chrome/browser/omnibox/omnibox_field_trial.h"
 #include "chrome/browser/profiles/profile.h"
@@ -186,12 +187,7 @@
 }
 
 bool ZeroSuggestProvider::ShouldRunZeroSuggest(const GURL& url) const {
-  if (!url.is_valid())
-    return false;
-
-  // Do not query non-http URLs. There will be no useful suggestions for https
-  // or chrome URLs.
-  if (url.scheme() != chrome::kHttpScheme)
+  if (!ShouldSendURL(url))
     return false;
 
   // Don't run if there's no profile or in incognito mode.
@@ -217,6 +213,18 @@
   return true;
 }
 
+bool ZeroSuggestProvider::ShouldSendURL(const GURL& url) const {
+  if (!url.is_valid())
+    return false;
+
+  // Only allow HTTP URLs or Google HTTPS URLs (including Google search
+  // result pages).  For the latter case, Google was already sent the HTTPS
+  // URLs when requesting the page, so the information is just re-sent.
+  return (url.scheme() == chrome::kHttpScheme) ||
+      google_util::IsGoogleDomainUrl(url, google_util::ALLOW_SUBDOMAIN,
+                                     google_util::ALLOW_NON_STANDARD_PORTS);
+}
+
 void ZeroSuggestProvider::FillResults(
     const Value& root_val,
     int* verbatim_relevance,
diff --git a/chrome/browser/autocomplete/zero_suggest_provider.h b/chrome/browser/autocomplete/zero_suggest_provider.h
index c53c9ee..f6fafa5 100644
--- a/chrome/browser/autocomplete/zero_suggest_provider.h
+++ b/chrome/browser/autocomplete/zero_suggest_provider.h
@@ -86,6 +86,10 @@
 
   bool ShouldRunZeroSuggest(const GURL& url) const;
 
+  // Whether the URL can get Zero Suggest.  For example, don't send the URL of
+  // non-Google HTTPS requests because it may contain sensitive information.
+  bool ShouldSendURL(const GURL& url) const;
+
   // The 4 functions below (that take classes defined in SearchProvider as
   // arguments) were copied and trimmed from SearchProvider.
   // TODO(hfung): Refactor them into a new base class common to both
diff --git a/chrome/browser/autofill/form_structure_browsertest.cc b/chrome/browser/autofill/form_structure_browsertest.cc
index aa8f085..c497275 100644
--- a/chrome/browser/autofill/form_structure_browsertest.cc
+++ b/chrome/browser/autofill/form_structure_browsertest.cc
@@ -90,8 +90,7 @@
             (*iter)->begin();
          field_iter != (*iter)->end();
          ++field_iter) {
-      forms_string +=
-          AutofillType::FieldTypeToString((*field_iter)->Type().server_type());
+      forms_string += (*field_iter)->Type().ToString();
       forms_string += " | " + UTF16ToUTF8((*field_iter)->name);
       forms_string += " | " + UTF16ToUTF8((*field_iter)->label);
       forms_string += " | " + UTF16ToUTF8((*field_iter)->value);
diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc
index 4471269..83e9fbe 100644
--- a/chrome/browser/browser_about_handler.cc
+++ b/chrome/browser/browser_about_handler.cc
@@ -86,8 +86,6 @@
 }
 
 bool HandleNonNavigationAboutURL(const GURL& url) {
-  std::string host(url.host());
-
   // chrome://ipc/ is currently buggy, so we disable it for official builds.
 #if !defined(OFFICIAL_BUILD)
 
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 51ca592..ee1bbc5 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -405,8 +405,9 @@
 
 #if defined(OS_WIN) || defined(OS_LINUX)
 
-#if defined(OS_LINUX)
-// http://crbug.com/129235
+#if defined(OS_LINUX) || (defined(OS_WIN) && defined(USE_AURA))
+// Linux: http://crbug.com/129235
+// Win Aura: crbug.com/269564
 #define MAYBE_CtrlKeyEvents DISABLED_CtrlKeyEvents
 #else
 #define MAYBE_CtrlKeyEvents CtrlKeyEvents
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
index ea9d7f7..b906a79 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper.cc
@@ -9,8 +9,8 @@
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/local_storage_usage_info.h"
 #include "content/public/browser/storage_partition.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 using content::BrowserContext;
 using content::BrowserThread;
@@ -53,12 +53,12 @@
 }
 
 void BrowsingDataLocalStorageHelper::GetUsageInfoCallback(
-    const std::vector<dom_storage::LocalStorageUsageInfo>& infos) {
+    const std::vector<content::LocalStorageUsageInfo>& infos) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   for (size_t i = 0; i < infos.size(); ++i) {
     // Non-websafe state is not considered browsing data.
-    const dom_storage::LocalStorageUsageInfo& info = infos[i];
+    const content::LocalStorageUsageInfo& info = infos[i];
     if (BrowsingDataHelper::HasWebScheme(info.origin)) {
       local_storage_info_.push_back(
           LocalStorageInfo(info.origin, info.data_size, info.last_modified));
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper.h b/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
index 80c55fd..ba67f59 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper.h
@@ -62,7 +62,7 @@
 
  private:
   void GetUsageInfoCallback(
-      const std::vector<dom_storage::LocalStorageUsageInfo>& infos);
+      const std::vector<content::LocalStorageUsageInfo>& infos);
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataLocalStorageHelper);
 };
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index fb6403c..008d5cf 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -50,8 +50,10 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/download_manager.h"
+#include "content/public/browser/local_storage_usage_info.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/plugin_data_remover.h"
+#include "content/public/browser/session_storage_usage_info.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/user_metrics.h"
 #include "net/base/net_errors.h"
@@ -65,7 +67,6 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "webkit/browser/quota/quota_manager.h"
 #include "webkit/browser/quota/special_storage_policy.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/common/quota/quota_types.h"
 
 using content::BrowserContext;
@@ -896,7 +897,7 @@
 }
 
 void BrowsingDataRemover::OnGotLocalStorageUsageInfo(
-    const std::vector<dom_storage::LocalStorageUsageInfo>& infos) {
+    const std::vector<content::LocalStorageUsageInfo>& infos) {
   DCHECK(waiting_for_clear_local_storage_);
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -924,7 +925,7 @@
 }
 
 void BrowsingDataRemover::OnGotSessionStorageUsageInfo(
-    const std::vector<dom_storage::SessionStorageUsageInfo>& infos) {
+    const std::vector<content::SessionStorageUsageInfo>& infos) {
   DCHECK(waiting_for_clear_session_storage_);
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h
index 502247f..af1b441 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.h
+++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -16,7 +16,6 @@
 #include "base/time/time.h"
 #include "chrome/browser/pepper_flash_settings_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
-#include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "url/gurl.h"
@@ -42,7 +41,8 @@
 class QuotaManager;
 }
 
-namespace dom_storage {
+namespace content {
+class DOMStorageContext;
 struct LocalStorageUsageInfo;
 struct SessionStorageUsageInfo;
 }
@@ -295,14 +295,14 @@
 
   // Callback to deal with the list gathered in ClearLocalStorageOnUIThread.
   void OnGotLocalStorageUsageInfo(
-      const std::vector<dom_storage::LocalStorageUsageInfo>& infos);
+      const std::vector<content::LocalStorageUsageInfo>& infos);
 
   // Invoked on the UI thread to delete session storage.
   void ClearSessionStorageOnUIThread();
 
   // Callback to deal with the list gathered in ClearSessionStorageOnUIThread.
   void OnGotSessionStorageUsageInfo(
-      const std::vector<dom_storage::SessionStorageUsageInfo>& infos);
+      const std::vector<content::SessionStorageUsageInfo>& infos);
 
   // Invoked on the IO thread to delete all storage types managed by the quota
   // system: AppCache, Databases, FileSystems.
diff --git a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
index 174a2b5..3de958d 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_unittest.cc
@@ -32,6 +32,7 @@
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "content/public/browser/dom_storage_context.h"
+#include "content/public/browser/local_storage_usage_info.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/test/test_browser_thread.h"
@@ -45,7 +46,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "webkit/browser/quota/mock_quota_manager.h"
 #include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/common/quota/quota_types.h"
 
 using content::BrowserThread;
@@ -284,8 +284,10 @@
                                    base::Time creation_time,
                                    base::Time expiration_time) {
     GetCertStore()->SetServerBoundCert(server_identifier,
-                                       net::CLIENT_CERT_RSA_SIGN, creation_time,
-                                       expiration_time, "a", "b");
+                                       creation_time,
+                                       expiration_time,
+                                       "a",
+                                       "b");
   }
 
   // Add a server bound cert for |server|, with the current time as the
@@ -520,7 +522,7 @@
                    base::Unretained(this)));
   }
   void OnGotLocalStorageUsage(
-      const std::vector<dom_storage::LocalStorageUsageInfo>& infos) {
+      const std::vector<content::LocalStorageUsageInfo>& infos) {
     infos_ = infos;
     await_completion_.Notify();
   }
@@ -529,7 +531,7 @@
   TestingProfile* profile_;
   content::DOMStorageContext* dom_storage_context_;
 
-  std::vector<dom_storage::LocalStorageUsageInfo> infos_;
+  std::vector<content::LocalStorageUsageInfo> infos_;
 
   AwaitCompletionHelper await_completion_;
 
diff --git a/chrome/browser/browsing_data/browsing_data_server_bound_cert_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_server_bound_cert_helper_unittest.cc
index 4a12c5a..a95405e 100644
--- a/chrome/browser/browsing_data/browsing_data_server_bound_cert_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_server_bound_cert_helper_unittest.cc
@@ -39,11 +39,9 @@
     net::ServerBoundCertStore* cert_store =
         context->server_bound_cert_service()->GetCertStore();
     cert_store->SetServerBoundCert("https://www.google.com:443",
-                                   net::CLIENT_CERT_RSA_SIGN,
                                    base::Time(), base::Time(),
                                    "key", "cert");
     cert_store->SetServerBoundCert("https://www.youtube.com:443",
-                                   net::CLIENT_CERT_RSA_SIGN,
                                    base::Time(), base::Time(),
                                    "key", "cert");
   }
@@ -131,34 +129,6 @@
   ASSERT_EQ(0UL, server_bound_cert_list_.size());
 }
 
-TEST_F(BrowsingDataServerBoundCertHelperTest, CannedUnique) {
-  std::string origin = "https://www.google.com:443";
-
-  scoped_refptr<CannedBrowsingDataServerBoundCertHelper> helper(
-      new CannedBrowsingDataServerBoundCertHelper());
-
-  ASSERT_TRUE(helper->empty());
-  helper->AddServerBoundCert(net::ServerBoundCertStore::ServerBoundCert(
-      origin, net::CLIENT_CERT_RSA_SIGN, base::Time(), base::Time(), "key",
-      "cert"));
-  helper->AddServerBoundCert(net::ServerBoundCertStore::ServerBoundCert(
-      origin, net::CLIENT_CERT_ECDSA_SIGN, base::Time(), base::Time(), "key",
-      "cert"));
-
-  helper->StartFetching(
-      base::Bind(&BrowsingDataServerBoundCertHelperTest::FetchCallback,
-                 base::Unretained(this)));
-  base::RunLoop().RunUntilIdle();
-
-  ASSERT_EQ(1UL, server_bound_cert_list_.size());
-  net::ServerBoundCertStore::ServerBoundCert& cert =
-      server_bound_cert_list_.front();
-
-  EXPECT_EQ("https://www.google.com:443", cert.server_identifier());
-  EXPECT_EQ(net::CLIENT_CERT_ECDSA_SIGN, cert.type());
-  EXPECT_EQ(0, ssl_config_changed_count_);
-}
-
 TEST_F(BrowsingDataServerBoundCertHelperTest, CannedEmpty) {
   std::string origin = "https://www.google.com";
 
@@ -167,8 +137,7 @@
 
   ASSERT_TRUE(helper->empty());
   helper->AddServerBoundCert(net::ServerBoundCertStore::ServerBoundCert(
-      origin, net::CLIENT_CERT_RSA_SIGN, base::Time(), base::Time(), "key",
-      "cert"));
+      origin, base::Time(), base::Time(), "key", "cert"));
   ASSERT_FALSE(helper->empty());
   helper->Reset();
   ASSERT_TRUE(helper->empty());
diff --git a/chrome/browser/browsing_data/mock_browsing_data_server_bound_cert_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_server_bound_cert_helper.cc
index 6cb78ed..85a02b9 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_server_bound_cert_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_server_bound_cert_helper.cc
@@ -28,8 +28,7 @@
   DCHECK(server_bound_certs_.find(server_id) == server_bound_certs_.end());
   server_bound_cert_list_.push_back(
       net::ServerBoundCertStore::ServerBoundCert(
-          server_id, net::CLIENT_CERT_ECDSA_SIGN,
-          base::Time(), base::Time(), "key", "cert"));
+          server_id, base::Time(), base::Time(), "key", "cert"));
   server_bound_certs_[server_id] = true;
 }
 
diff --git a/chrome/browser/chrome_browser_field_trials_mobile.cc b/chrome/browser/chrome_browser_field_trials_mobile.cc
index 8d9140c..df95a80 100644
--- a/chrome/browser/chrome_browser_field_trials_mobile.cc
+++ b/chrome/browser/chrome_browser_field_trials_mobile.cc
@@ -16,16 +16,15 @@
 
 namespace {
 
-// Governs the rollout of the compression proxy for Chrome on mobile platforms.
-// Always enabled in DEV and BETA versions.
-// Stable percentage will be controlled from server.
-void DataCompressionProxyFieldTrial() {
-  const char kDataCompressionProxyFieldTrialName[] =
-      "DataCompressionProxyRollout";
-  const base::FieldTrial::Probability kDataCompressionProxyDivisor = 1000;
-
-  // 10/1000 = 1% for starters.
-  const base::FieldTrial::Probability kDataCompressionProxyStable = 10;
+// Base function used by all data reduction proxy field trials. A trial is
+// only conducted for installs that are in the "Enabled" group. They are always
+// enabled on DEV and BETA channels, and for STABLE, a percentage will be
+// controlled from the server. Until the percentage is learned from the server,
+// a client-side configuration is used.
+void DataCompressionProxyBaseFieldTrial(
+    const char* trial_name,
+    const base::FieldTrial::Probability enabled_group_probability,
+    const base::FieldTrial::Probability total_probability) {
   const char kEnabled[] = "Enabled";
   const char kDisabled[] = "Disabled";
 
@@ -36,20 +35,41 @@
   // Experiment enabled until Jan 1, 2015. By default, disabled.
   scoped_refptr<base::FieldTrial> trial(
       base::FieldTrialList::FactoryGetFieldTrial(
-          kDataCompressionProxyFieldTrialName, kDataCompressionProxyDivisor,
+          trial_name,
+          total_probability,
           kDisabled, 2015, 1, 1, base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
 
   // Non-stable channels will run with probability 1.
   const int kEnabledGroup = trial->AppendGroup(
       kEnabled,
-      kIsStableChannel ?
-          kDataCompressionProxyStable : kDataCompressionProxyDivisor);
+      kIsStableChannel ? enabled_group_probability : total_probability);
 
   const int v = trial->group();
-  VLOG(1) << "DataCompression proxy enabled group id: " << kEnabledGroup
+  VLOG(1) << trial_name <<  " enabled group id: " << kEnabledGroup
           << ". Selected group id: " << v;
 }
 
+void DataCompressionProxyFieldTrials() {
+  // Governs the rollout of the compression proxy for Chrome on mobile
+  // platforms. Always enabled in DEV and BETA channels. For STABLE, the
+  // percentage will be controlled from the server, and is configured to be
+  // 10% = 100 / 1000 until overridden by the server.
+  DataCompressionProxyBaseFieldTrial(
+      "DataCompressionProxyRollout", 100, 1000);
+
+  if (base::FieldTrialList::FindFullName(
+      "DataCompressionProxyRollout") == "Enabled") {
+
+    // Governs the rollout of the _promo_ for the compression proxy
+    // independently from the rollout of compression proxy. The enabled
+    // percentage is configured to be 100% = 1000 / 1000 until overridden by the
+    // server. When this trial is "Enabled," users get a promo, whereas
+    // otherwise, compression is enabled without a promo.
+    DataCompressionProxyBaseFieldTrial(
+        "DataCompressionProxyPromoVisibility", 1000, 1000);
+  }
+}
+
 void NewTabButtonInToolbarFieldTrial(const CommandLine& parsed_command_line) {
   // Do not enable this field trials for tablet devices.
   if (parsed_command_line.HasSwitch(switches::kTabletUI))
@@ -92,7 +112,7 @@
 void SetupMobileFieldTrials(const CommandLine& parsed_command_line,
                             const base::Time& install_time,
                             PrefService* local_state) {
-  DataCompressionProxyFieldTrial();
+  DataCompressionProxyFieldTrials();
 
 #if defined(OS_ANDROID)
   NewTabButtonInToolbarFieldTrial(parsed_command_line);
diff --git a/chrome/browser/chrome_notification_types.h b/chrome/browser/chrome_notification_types.h
index 326ba22..a4b5adc 100644
--- a/chrome/browser/chrome_notification_types.h
+++ b/chrome/browser/chrome_notification_types.h
@@ -66,12 +66,6 @@
   // (std::pair<std::string, std::string>).
   NOTIFICATION_PAGE_TRANSLATED,
 
-  // Sent after the renderer returns a snapshot of tab contents.
-  // The source (Source<content::WebContents>) is the RenderViewHost for which
-  // the snapshot was generated and the details (Details<const SkBitmap>) is
-  // the actual snapshot.
-  NOTIFICATION_TAB_SNAPSHOT_TAKEN,
-
   // The user has changed the browser theme. The source is a
   // Source<ThemeService>. There are no details.
   NOTIFICATION_BROWSER_THEME_CHANGED,
@@ -510,11 +504,6 @@
   // details about why the install failed.
   NOTIFICATION_EXTENSION_INSTALL_ERROR,
 
-  // Sent when an extension install is not allowed, as indicated by
-  // PendingExtensionInfo::ShouldAllowInstall. The details are an Extension,
-  // and the source is a Profile.
-  NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED,
-
   // Sent when an extension has been uninstalled. The details are an Extension,
   // and the source is a Profile.
   NOTIFICATION_EXTENSION_UNINSTALLED,
@@ -564,13 +553,6 @@
   // Sent when a background page is ready so other components can load.
   NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
 
-  // Sent when a pop-up extension view is ready, so that notification may
-  // be sent to pending callbacks.  Note that this notification is sent
-  // after all onload callbacks have been invoked in the main frame.
-  // The details is the ExtensionHost* hosted within the popup, and the source
-  // is a Profile*.
-  NOTIFICATION_EXTENSION_POPUP_VIEW_READY,
-
   // Sent when a browser action's state has changed. The source is the
   // ExtensionAction* that changed.  The details are the Profile* that the
   // browser action belongs to.
@@ -798,10 +780,6 @@
   // details.
   NOTIFICATION_SYNC_CONFIGURE_DONE,
 
-  // The sync service has started the datatype configuration process. The source
-  // is the ProfileSyncService object of the Profile. There are no details.
-  NOTIFICATION_SYNC_CONFIGURE_START,
-
   // A service is requesting a sync datatype refresh for the current profile.
   // The details value is a const syncer::ModelTypeSet.
   // If the payload map is empty, it should be treated as an invalidation for
@@ -857,11 +835,6 @@
   // TokenRequestFailedDetails object.
   NOTIFICATION_TOKEN_REQUEST_FAILED,
 
-  // When a service has a new token they got from a frontend that the
-  // TokenService should know about, fire this notification. The source is the
-  // Profile. The details are a TokenAvailableDetails object.
-  NOTIFICATION_TOKEN_UPDATED,
-
   // Fired when the TokenService has had all of its tokens removed (such as due
   // to the user signing out). The source is the TokenService. There are no
   // details.
@@ -1024,12 +997,6 @@
   // Sent when the user list has changed.
   NOTIFICATION_USER_LIST_CHANGED,
 
-  // Sent when a panel state changed.
-  NOTIFICATION_PANEL_STATE_CHANGED,
-
-  // Sent when the window manager's layout mode has changed.
-  NOTIFICATION_LAYOUT_MODE_CHANGED,
-
   // Sent when the screen lock state has changed. The source is
   // ScreenLocker and the details is a bool specifing that the
   // screen is locked. When details is a false, the source object
diff --git a/chrome/browser/chromeos/drive/file_system.h b/chrome/browser/chromeos/drive/file_system.h
index ebead43..5bb1ca8 100644
--- a/chrome/browser/chromeos/drive/file_system.h
+++ b/chrome/browser/chromeos/drive/file_system.h
@@ -20,14 +20,13 @@
 class PrefService;
 
 namespace base {
-struct PlatformFileInfo;
 class SequencedTaskRunner;
-}
+}  // namespace base
 
 namespace google_apis {
 class AboutResource;
 class ResourceEntry;
-}
+}  // namespace google_apis
 
 namespace drive {
 
@@ -166,12 +165,10 @@
   virtual void OnLoadFromServerComplete() OVERRIDE;
   virtual void OnInitialLoadComplete() OVERRIDE;
 
-  // Used in tests to update the file system using the change list loader.
-  internal::ChangeListLoader* change_list_loader() {
+  // Used by tests.
+  internal::ChangeListLoader* change_list_loader_for_testing() {
     return change_list_loader_.get();
   }
-
-  // Used by tests.
   internal::SyncClient* sync_client_for_testing() { return sync_client_.get(); }
 
  private:
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
index 7743c06..25d6348 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.cc
@@ -22,19 +22,6 @@
 
 namespace drive {
 namespace file_system {
-namespace {
-
-FileError UpdateFileLocalState(internal::FileCache* cache,
-                               const std::string& resource_id,
-                               base::FilePath* local_file_path) {
-  FileError error = cache->MarkDirty(resource_id);
-  if (error != FILE_ERROR_OK)
-    return error;
-
-  return cache->GetFile(resource_id, local_file_path);
-}
-
-}  // namespace
 
 OpenFileOperation::OpenFileOperation(
     base::SequencedTaskRunner* blocking_task_runner,
@@ -130,27 +117,23 @@
     return;
   }
 
-  // Note: after marking the file dirty, the local file path may be changed.
-  // So, it is necessary to take the path again.
-  base::FilePath* new_local_file_path = new base::FilePath;
   base::PostTaskAndReplyWithResult(
       blocking_task_runner_.get(),
       FROM_HERE,
-      base::Bind(&UpdateFileLocalState,
-                 cache_,
-                 entry->resource_id(),
-                 new_local_file_path),
-      base::Bind(&OpenFileOperation::OpenFileAfterUpdateLocalState,
+      base::Bind(&internal::FileCache::MarkDirty,
+                 base::Unretained(cache_),
+                 entry->resource_id()),
+      base::Bind(&OpenFileOperation::OpenFileAfterMarkDirty,
                  weak_ptr_factory_.GetWeakPtr(),
+                 local_file_path,
                  entry->resource_id(),
-                 callback,
-                 base::Owned(new_local_file_path)));
+                 callback));
 }
 
-void OpenFileOperation::OpenFileAfterUpdateLocalState(
+void OpenFileOperation::OpenFileAfterMarkDirty(
+    const base::FilePath& local_file_path,
     const std::string& resource_id,
     const OpenFileCallback& callback,
-    const base::FilePath* local_file_path,
     FileError error) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK(!callback.is_null());
@@ -161,7 +144,7 @@
   }
 
   ++open_files_[resource_id];
-  callback.Run(error, *local_file_path,
+  callback.Run(error, local_file_path,
                base::Bind(&OpenFileOperation::CloseFile,
                           weak_ptr_factory_.GetWeakPtr(), resource_id));
 }
diff --git a/chrome/browser/chromeos/drive/file_system/open_file_operation.h b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
index f656d2f..7055eea 100644
--- a/chrome/browser/chromeos/drive/file_system/open_file_operation.h
+++ b/chrome/browser/chromeos/drive/file_system/open_file_operation.h
@@ -67,11 +67,11 @@
                                    const base::FilePath& local_file_path,
                                    scoped_ptr<ResourceEntry> entry);
 
-  // Part of OpenFile(). Called after the updating of the local state.
-  void OpenFileAfterUpdateLocalState(const std::string& resource_id,
-                                     const OpenFileCallback& callback,
-                                     const base::FilePath* local_file_path,
-                                     FileError error);
+  // Part of OpenFile(). Called after marking the cache file dirty.
+  void OpenFileAfterMarkDirty(const base::FilePath& local_file_path,
+                              const std::string& resource_id,
+                              const OpenFileCallback& callback,
+                              FileError error);
 
   // Closes the file with |resource_id|.
   void CloseFile(const std::string& resource_id);
diff --git a/chrome/browser/chromeos/drive/file_system_interface.h b/chrome/browser/chromeos/drive/file_system_interface.h
index 5a554c9..1c5865e 100644
--- a/chrome/browser/chromeos/drive/file_system_interface.h
+++ b/chrome/browser/chromeos/drive/file_system_interface.h
@@ -150,7 +150,7 @@
   ContextType type;
 };
 
-// Option enum to control eligible entries for searchMetadata().
+// Option enum to control eligible entries for SearchMetadata().
 // SEARCH_METADATA_ALL is the default to investigate all the entries.
 // SEARCH_METADATA_EXCLUDE_HOSTED_DOCUMENTS excludes the hosted documents.
 // SEARCH_METADATA_EXCLUDE_DIRECTORIES excludes the directories from the result.
diff --git a/chrome/browser/chromeos/drive/file_system_unittest.cc b/chrome/browser/chromeos/drive/file_system_unittest.cc
index 2f3baf3..0f0ca56 100644
--- a/chrome/browser/chromeos/drive/file_system_unittest.cc
+++ b/chrome/browser/chromeos/drive/file_system_unittest.cc
@@ -149,7 +149,7 @@
   // Loads the full resource list via FakeDriveService.
   bool LoadFullResourceList() {
     FileError error = FILE_ERROR_FAILED;
-    file_system_->change_list_loader()->LoadIfNeeded(
+    file_system_->change_list_loader_for_testing()->LoadIfNeeded(
         DirectoryFetchInfo(),
         google_apis::test_util::CreateCopyResultCallback(&error));
     test_util::RunBlockingPoolTask();
diff --git a/chrome/browser/chromeos/drive/job_scheduler.cc b/chrome/browser/chromeos/drive/job_scheduler.cc
index aec04a4..d9c0d61 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.cc
+++ b/chrome/browser/chromeos/drive/job_scheduler.cc
@@ -119,6 +119,7 @@
     DriveServiceInterface* drive_service,
     base::SequencedTaskRunner* blocking_task_runner)
     : throttle_count_(0),
+      wait_until_(base::Time::Now()),
       disable_throttling_(false),
       drive_service_(drive_service),
       uploader_(new DriveUploader(drive_service, blocking_task_runner)),
@@ -718,6 +719,18 @@
     }
   }
 
+  // Wait when throttled.
+  const base::Time now = base::Time::Now();
+  if (now < wait_until_) {
+    base::MessageLoopProxy::current()->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&JobScheduler::DoJobLoop,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   queue_type),
+        wait_until_ - now);
+    return;
+  }
+
   // Run the job with the highest priority in the queue.
   JobID job_id = -1;
   if (!queue_[queue_type]->PopForRun(accepted_priority, &job_id))
@@ -728,11 +741,13 @@
 
   JobInfo* job_info = &entry->job_info;
   job_info->state = STATE_RUNNING;
-  job_info->start_time = base::Time::Now();
+  job_info->start_time = now;
   NotifyJobUpdated(*job_info);
 
   entry->cancel_callback = entry->task.Run();
 
+  UpdateWait();
+
   util::Log(logging::LOG_INFO,
             "Job started: %s - %s",
             job_info->ToString().c_str(),
@@ -764,42 +779,19 @@
   return BACKGROUND;
 }
 
-void JobScheduler::ThrottleAndContinueJobLoop(QueueType queue_type) {
+void JobScheduler::UpdateWait() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  if (throttle_count_ < kMaxThrottleCount)
-    throttle_count_++;
+  if (disable_throttling_ || throttle_count_ == 0)
+    return;
 
-  base::TimeDelta delay;
-  if (disable_throttling_) {
-    delay = base::TimeDelta::FromSeconds(0);
-  } else {
-    // Exponential backoff: https://developers.google.com/drive/handle-errors.
-    delay =
+  // Exponential backoff: https://developers.google.com/drive/handle-errors.
+  base::TimeDelta delay =
       base::TimeDelta::FromSeconds(1 << (throttle_count_ - 1)) +
       base::TimeDelta::FromMilliseconds(base::RandInt(0, 1000));
-  }
   VLOG(1) << "Throttling for " << delay.InMillisecondsF();
 
-  const bool posted = base::MessageLoopProxy::current()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&JobScheduler::DoJobLoop,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 queue_type),
-      delay);
-  DCHECK(posted);
-}
-
-void JobScheduler::ResetThrottleAndContinueJobLoop(QueueType queue_type) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  // Post a task to continue the job loop.  This allows us to finish handling
-  // the current job before starting the next one.
-  throttle_count_ = 0;
-  base::MessageLoopProxy::current()->PostTask(FROM_HERE,
-      base::Bind(&JobScheduler::DoJobLoop,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 queue_type));
+  wait_until_ = std::max(wait_until_, base::Time::Now() + delay);
 }
 
 bool JobScheduler::OnJobDone(JobID job_id, google_apis::GDataErrorCode error) {
@@ -821,9 +813,20 @@
             GetQueueInfo(queue_type).c_str());
 
   // Retry, depending on the error.
-  if ((error == google_apis::HTTP_SERVICE_UNAVAILABLE ||
-      error == google_apis::HTTP_INTERNAL_SERVER_ERROR) &&
-      job_entry->retry_count < kMaxRetryCount) {
+  const bool is_server_error =
+      error == google_apis::HTTP_SERVICE_UNAVAILABLE ||
+      error == google_apis::HTTP_INTERNAL_SERVER_ERROR;
+  if (is_server_error) {
+    if (throttle_count_ < kMaxThrottleCount)
+      ++throttle_count_;
+    UpdateWait();
+  } else {
+    throttle_count_ = 0;
+  }
+
+  const bool should_retry =
+      is_server_error && job_entry->retry_count < kMaxRetryCount;
+  if (should_retry) {
     job_entry->cancel_callback.Reset();
     job_info->state = STATE_RETRY;
     NotifyJobUpdated(*job_info);
@@ -832,18 +835,20 @@
 
     // Requeue the job.
     QueueJob(job_id);
-
-    ThrottleAndContinueJobLoop(queue_type);
-    return false;
   } else {
     NotifyJobDone(*job_info, error);
     // The job has finished, no retry will happen in the scheduler. Now we can
     // remove the job info from the map.
     job_map_.Remove(job_id);
-
-    ResetThrottleAndContinueJobLoop(queue_type);
-    return true;
   }
+
+  // Post a task to continue the job loop.  This allows us to finish handling
+  // the current job before starting the next one.
+  base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+      base::Bind(&JobScheduler::DoJobLoop,
+                 weak_ptr_factory_.GetWeakPtr(),
+                 queue_type));
+  return !should_retry;
 }
 
 void JobScheduler::OnGetResourceListJobDone(
diff --git a/chrome/browser/chromeos/drive/job_scheduler.h b/chrome/browser/chromeos/drive/job_scheduler.h
index 059a5ae..acd51ae 100644
--- a/chrome/browser/chromeos/drive/job_scheduler.h
+++ b/chrome/browser/chromeos/drive/job_scheduler.h
@@ -244,12 +244,8 @@
   // currently allowed to start for the |queue_type|.
   int GetCurrentAcceptedPriority(QueueType queue_type);
 
-  // Increases the throttle delay if it's below the maximum value, and posts a
-  // task to continue the loop after the delay.
-  void ThrottleAndContinueJobLoop(QueueType queue_type);
-
-  // Resets the throttle delay to the initial value, and continues the job loop.
-  void ResetThrottleAndContinueJobLoop(QueueType queue_type);
+  // Updates |wait_until_| to throttle requests.
+  void UpdateWait();
 
   // Retries the job if needed and returns false. Otherwise returns true.
   bool OnJobDone(JobID job_id, google_apis::GDataErrorCode error);
@@ -352,6 +348,9 @@
   // next task.
   int throttle_count_;
 
+  // Jobs should not start running until this time. Used for throttling.
+  base::Time wait_until_;
+
   // Disables throttling for testing.
   bool disable_throttling_;
 
diff --git a/chrome/browser/chromeos/drive/logging.cc b/chrome/browser/chromeos/drive/logging.cc
index 40c205a..b939c46 100644
--- a/chrome/browser/chromeos/drive/logging.cc
+++ b/chrome/browser/chromeos/drive/logging.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/chromeos/drive/logging.h"
 
 #include <stdarg.h>   // va_list
+#include <string>
 
 #include "base/lazy_instance.h"
 #include "base/strings/stringprintf.h"
diff --git a/chrome/browser/chromeos/drive/logging.h b/chrome/browser/chromeos/drive/logging.h
index 1e6964d..473478a 100644
--- a/chrome/browser/chromeos/drive/logging.h
+++ b/chrome/browser/chromeos/drive/logging.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_CHROMEOS_DRIVE_LOGGING_H_
 #define CHROME_BROWSER_CHROMEOS_DRIVE_LOGGING_H_
 
-#include <string>
 #include <vector>
 
 #include "chrome/browser/drive/event_logger.h"
diff --git a/chrome/browser/chromeos/extensions/OWNERS b/chrome/browser/chromeos/extensions/OWNERS
index 6a5847e..6571aa3 100644
--- a/chrome/browser/chromeos/extensions/OWNERS
+++ b/chrome/browser/chromeos/extensions/OWNERS
@@ -5,6 +5,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/chrome/browser/chromeos/extensions/external_cache.cc b/chrome/browser/chromeos/extensions/external_cache.cc
index cee8544..86c0f19 100644
--- a/chrome/browser/chromeos/extensions/external_cache.cc
+++ b/chrome/browser/chromeos/extensions/external_cache.cc
@@ -61,7 +61,7 @@
   for (base::DictionaryValue::Iterator it(*cached_extensions_.get());
        !it.IsAtEnd(); it.Advance()) {
     const base::DictionaryValue* entry = NULL;
-    if (it.value().GetAsDictionary(&entry)) {
+    if (!it.value().GetAsDictionary(&entry)) {
       NOTREACHED() << "ExternalCache found bad entry with type "
                    << it.value().GetType();
       continue;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index b65bda2..58296be 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -171,9 +171,12 @@
   result->SetString("transferState", job_status);
   result->SetString("transferType",
                     IsUploadJob(job_info.job_type) ? "upload" : "download");
-  result->SetInteger("processed",
-                     static_cast<int>(job_info.num_completed_bytes));
-  result->SetInteger("total", static_cast<int>(job_info.num_total_bytes));
+  // JavaScript does not have 64-bit integers. Instead we use double, which
+  // is in IEEE 754 formant and accurate up to 52-bits in JS, and in practice
+  // in C++. Larger values are rounded.
+  result->SetDouble("processed",
+                    static_cast<double>(job_info.num_completed_bytes));
+  result->SetDouble("total", static_cast<double>(job_info.num_total_bytes));
   return result.Pass();
 }
 
@@ -220,10 +223,6 @@
       profile_(profile),
       weak_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  file_watcher_callback_ =
-      base::Bind(&EventRouter::HandleFileWatchNotification,
-                 weak_factory_.GetWeakPtr());
 }
 
 EventRouter::~EventRouter() {
@@ -321,20 +320,31 @@
   DCHECK(!callback.is_null());
 
   base::FilePath watch_path = local_path;
-  bool is_remote_watch = false;
+  bool is_on_drive = drive::util::IsUnderDriveMountPoint(watch_path);
   // Tweak watch path for remote sources - we need to drop leading /special
   // directory from there in order to be able to pair these events with
   // their change notifications.
-  if (drive::util::IsUnderDriveMountPoint(watch_path)) {
+  if (is_on_drive)
     watch_path = drive::util::ExtractDrivePath(watch_path);
-    is_remote_watch = true;
-  }
 
   WatcherMap::iterator iter = file_watchers_.find(watch_path);
   if (iter == file_watchers_.end()) {
-    scoped_ptr<FileWatcher> watcher(
-        new FileWatcher(virtual_path, extension_id, is_remote_watch));
-    watcher->Watch(watch_path, file_watcher_callback_, callback);
+    scoped_ptr<FileWatcher> watcher(new FileWatcher(virtual_path));
+    watcher->AddExtension(extension_id);
+
+    if (is_on_drive) {
+      // For Drive, file watching is done via OnDirectoryChanged().
+      base::MessageLoopProxy::current()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, true));
+    } else {
+      // For local files, start watching using FileWatcher.
+      watcher->WatchLocalFile(
+          watch_path,
+          base::Bind(&EventRouter::HandleFileWatchNotification,
+                     weak_factory_.GetWeakPtr()),
+          callback);
+    }
+
     file_watchers_[watch_path] = watcher.release();
   } else {
     iter->second->AddExtension(extension_id);
@@ -357,9 +367,9 @@
   WatcherMap::iterator iter = file_watchers_.find(watch_path);
   if (iter == file_watchers_.end())
     return;
-  // Remove the renderer process for this watch.
+  // Remove the watcher if |watch_path| is no longer watched by any extensions.
   iter->second->RemoveExtension(extension_id);
-  if (iter->second->ref_count() == 0) {
+  if (iter->second->GetExtensionIds().empty()) {
     delete iter->second;
     file_watchers_.erase(iter);
   }
@@ -637,22 +647,23 @@
     return;
   }
   DispatchDirectoryChangeEvent(iter->second->virtual_path(), got_error,
-                               iter->second->extensions());
+                               iter->second->GetExtensionIds());
 }
 
 void EventRouter::DispatchDirectoryChangeEvent(
     const base::FilePath& virtual_path,
     bool got_error,
-    const FileWatcher::ExtensionUsageRegistry& extensions) {
+    const std::vector<std::string>& extension_ids) {
   if (!profile_) {
     NOTREACHED();
     return;
   }
 
-  for (FileWatcher::ExtensionUsageRegistry::const_iterator iter =
-           extensions.begin(); iter != extensions.end(); ++iter) {
+  for (size_t i = 0; i < extension_ids.size(); ++i) {
+    const std::string& extension_id = extension_ids[i];
+
     GURL target_origin_url(extensions::Extension::GetBaseURLFromExtensionId(
-        iter->first));
+        extension_id));
     GURL base_url = fileapi::GetFileSystemRootURI(
         target_origin_url,
         fileapi::kFileSystemTypeExternal);
@@ -671,7 +682,7 @@
     scoped_ptr<extensions::Event> event(new extensions::Event(
         extensions::event_names::kOnDirectoryChanged, args.Pass()));
     extensions::ExtensionSystem::Get(profile_)->event_router()->
-        DispatchEventToExtension(iter->first, event.Pass());
+        DispatchEventToExtension(extension_id, event.Pass());
   }
 }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index 24b6ca9..e10e30b 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -126,7 +126,7 @@
   void DispatchDirectoryChangeEvent(
       const base::FilePath& path,
       bool error,
-      const FileWatcher::ExtensionUsageRegistry& extensions);
+      const std::vector<std::string>& extension_ids);
 
   void DispatchMountEvent(
       chromeos::disks::DiskMountManager::MountEvent event,
@@ -156,7 +156,6 @@
   std::map<drive::JobID, DriveJobInfoWithStatus> drive_jobs_;
   base::Time last_file_transfer_event_;
 
-  base::FilePathWatcher::Callback file_watcher_callback_;
   WatcherMap file_watchers_;
   scoped_ptr<DesktopNotifications> notifications_;
   scoped_ptr<PrefChangeRegistrar> pref_change_registrar_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
index 1b00fc5..e2b428f 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.cc
@@ -142,7 +142,7 @@
   // Reacts to the user action reported by the dialog and notifies |function_|
   // about file selection result (by calling |OnFilePathSelected()|).
   // The |this| object is self destruct after the function is notified.
-  // |success| indicates whether user has selectd the file.
+  // |success| indicates whether user has selected the file.
   // |selected_path| is path that was selected. It is empty if the file wasn't
   // selected.
   void SendResponse(bool success, const base::FilePath& selected_path);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
index 8608786..7dae077 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api_test.cc
@@ -188,11 +188,11 @@
   // will be needed.
   static ExtensionFunction* TestSelectFileFunctionFactory() {
     EXPECT_TRUE(test_cases_);
-    EXPECT_TRUE(current_test_case_ < test_cases_->size());
+    EXPECT_TRUE(!test_cases_ || current_test_case_ < test_cases_->size());
 
     // If this happens, test failed. But, we still don't want to crash, so
     // return valid extension function.
-    if (!test_cases_ && current_test_case_ >= test_cases_->size())
+    if (!test_cases_ || current_test_case_ >= test_cases_->size())
       return new FileBrowserHandlerInternalSelectFileFunction();
 
     // Create file creator factory for the current test case.
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.cc b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.cc
index af196ba..6a39f9e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_browser_private_api.cc
@@ -45,7 +45,7 @@
   registry->RegisterFunction<SelectFileFunction>();
   registry->RegisterFunction<SelectFilesFunction>();
 
-  // Mount points releated functions.
+  // Mount points related functions.
   registry->RegisterFunction<AddMountFunction>();
   registry->RegisterFunction<RemoveMountFunction>();
   registry->RegisterFunction<GetMountPointsFunction>();
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
index 8db2c2f..e38c55b 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.cc
@@ -270,7 +270,7 @@
   return true;
 }
 
-// Executes handler specifed with |extension_id| and |action_id| for |url|.
+// Executes handler specified with |extension_id| and |action_id| for |url|.
 void ExecuteHandler(Profile* profile,
                     std::string extension_id,
                     std::string action_id,
@@ -314,7 +314,7 @@
     return;
 
   // Some values of |action_id| are not listed in the manifest and are used
-  // to parametrize the behavior when opening the Files app window.
+  // to parameterize the behavior when opening the Files app window.
   ExecuteHandler(profile, kFileBrowserDomain, action_id, url,
                  file_tasks::kTaskFile);
 }
@@ -414,7 +414,7 @@
                      file_tasks::kTaskFile);
       return true;
     }
-    return ExecuteBuiltinHandler(browser, path, action_id);
+    return ExecuteBuiltinHandler(browser, path);
   }
 
   ExecuteHandler(profile, extension_id, action_id, url,
@@ -755,8 +755,7 @@
   OpenFileBrowserImpl(path, "select");
 }
 
-bool ExecuteBuiltinHandler(Browser* browser, const base::FilePath& path,
-    const std::string& internal_task_id) {
+bool ExecuteBuiltinHandler(Browser* browser, const base::FilePath& path) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   Profile* profile = browser->profile();
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
index 579091f..0932ed2 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_util.h
@@ -79,12 +79,9 @@
 // Opens file browser on the folder containing the file, with the file selected.
 void ShowFileInFolder(const base::FilePath& path);
 
-// Executes the built-in File Manager handler or tries to open |file| directly
+// Executes the built-in File Manager handler or tries to open |path| directly
 // in the browser. Returns false if neither is possible.
-bool ExecuteBuiltinHandler(
-    Browser* browser,
-    const base::FilePath& path,
-    const std::string& internal_task_id);
+bool ExecuteBuiltinHandler(Browser* browser, const base::FilePath& path);
 
 // Checks whether a pepper plugin for |file_extension| is enabled.
 bool ShouldBeOpenedWithPlugin(Profile* profile, const char* file_extension);
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
index 64a1214..609cf4c 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_tasks.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
 
+#include "apps/launcher.h"
 #include "base/bind.h"
 #include "base/file_util.h"
 #include "base/i18n/case_conversion.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/lazy_background_task_queue.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -559,7 +559,7 @@
     return true;
   } else if (task_type == kTaskApp) {
     for (size_t i = 0; i != file_urls.size(); ++i) {
-      extensions::LaunchPlatformAppWithFileHandler(
+      apps::LaunchPlatformAppWithFileHandler(
           profile, extension, action_id, file_urls[i].path());
     }
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_watcher.cc b/chrome/browser/chromeos/extensions/file_manager/file_watcher.cc
index 29bfc71..6f72071 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_watcher.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/file_watcher.cc
@@ -31,17 +31,11 @@
 
 }  // namespace
 
-FileWatcher::FileWatcher(const base::FilePath& virtual_path,
-                         const std::string& extension_id,
-                         bool is_remote_file_system)
+FileWatcher::FileWatcher(const base::FilePath& virtual_path)
     : local_file_watcher_(NULL),
       virtual_path_(virtual_path),
-      ref_count_(0),
-      is_remote_file_system_(is_remote_file_system),
       weak_ptr_factory_(this) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-
-  AddExtension(extension_id);
 }
 
 FileWatcher::~FileWatcher() {
@@ -56,28 +50,36 @@
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   extensions_[extension_id]++;
-  ref_count_++;
 }
 
 void FileWatcher::RemoveExtension(const std::string& extension_id) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
-  ExtensionUsageRegistry::iterator it = extensions_.find(extension_id);
+  ExtensionCountMap::iterator it = extensions_.find(extension_id);
   if (it == extensions_.end()) {
     LOG(ERROR) << " Extension [" << extension_id
-               << "] tries to unsubscribe from folder [" << local_path_.value()
+               << "] tries to unsubscribe from folder ["
+               << virtual_path_.value()
                << "] it isn't subscribed";
     return;
   }
 
   // If entry found - decrease it's count and remove if necessary
-  if (it->second-- == 0)
+  --it->second;
+  if (it->second == 0)
     extensions_.erase(it);
-
-  ref_count_--;
 }
 
-void FileWatcher::Watch(
+std::vector<std::string> FileWatcher::GetExtensionIds() const {
+  std::vector<std::string> extension_ids;
+  for (ExtensionCountMap::const_iterator iter = extensions_.begin();
+       iter != extensions_.end(); ++iter) {
+    extension_ids.push_back(iter->first);
+  }
+  return extension_ids;
+}
+
+void FileWatcher::WatchLocalFile(
     const base::FilePath& local_path,
     const base::FilePathWatcher::Callback& file_watcher_callback,
     const BoolCallback& callback) {
@@ -85,14 +87,6 @@
   DCHECK(!callback.is_null());
   DCHECK(!local_file_watcher_);
 
-  local_path_ = local_path;  // For error message in RemoveExtension().
-
-  if (is_remote_file_system_) {
-    base::MessageLoopProxy::current()->PostTask(FROM_HERE,
-                                                base::Bind(callback, true));
-    return;
-  }
-
   BrowserThread::PostTaskAndReplyWithResult(
       BrowserThread::FILE,
       FROM_HERE,
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_watcher.h b/chrome/browser/chromeos/extensions/file_manager/file_watcher.h
index 1106347..2849fb1 100644
--- a/chrome/browser/chromeos/extensions/file_manager/file_watcher.h
+++ b/chrome/browser/chromeos/extensions/file_manager/file_watcher.h
@@ -26,14 +26,10 @@
 // files is handled differently in EventRouter.
 class FileWatcher {
  public:
-  typedef std::map<std::string, int> ExtensionUsageRegistry;
   typedef base::Callback<void(bool success)> BoolCallback;
 
-  // AddExtension() is internally called for |extension_id|.
-  // TODO(satorux): Remove |extension_id| and stop calling AddExtension().
-  FileWatcher(const base::FilePath& virtual_path,
-              const std::string& extension_id,
-              bool is_remote_file_system);
+  // Creates a FileWatcher associated with the virtual path.
+  explicit FileWatcher(const base::FilePath& virtual_path);
 
   ~FileWatcher();
 
@@ -51,31 +47,22 @@
   // comment at AddExtension() for details.
   void RemoveExtension(const std::string& extension_id);
 
-  // Returns IDs of the extensions watching virtual_path.
-  // TODO(satorux): Should just return a list of extension IDs rather than a
-  // map.
-  const ExtensionUsageRegistry& extensions() const { return extensions_; }
+  // Returns IDs of the extensions watching virtual_path. The returned list
+  // is sorted in the alphabetical order and contains no duplicates.
+  std::vector<std::string> GetExtensionIds() const;
 
-  // Returns 0 when no extensions are watching the virtual path.
-  // TODO(satorux): Should be replaced with extensions().empty().
-  int ref_count() const { return ref_count_; }
-
-  // Returns the path being watched.
+  // Returns the virtual path associated with the FileWatcher.
   const base::FilePath& virtual_path() const { return virtual_path_; }
 
-  // Starts watching |local_path|. For a local file, a base::FilePathWatcher
-  // will be created and |file_watcher_callback| will be called when changes
-  // are notified.
-  //
-  // For a remote file, this function actually does nothing but
-  // runs |callback| with true. See also the class comment.
-  // TODO(satorux): This function shouldn't be called for remote files.
+  // Starts watching a local file at |local_path|. |file_watcher_callback|
+  // will be called when changes are notified.
   //
   // |callback| will be called with true, if the file watch is started
   // successfully, or false if failed. |callback| must not be null.
-  void Watch(const base::FilePath& local_path,
-             const base::FilePathWatcher::Callback& file_watcher_callback,
-             const BoolCallback& callback);
+  void WatchLocalFile(
+      const base::FilePath& local_path,
+      const base::FilePathWatcher::Callback& file_watcher_callback,
+      const BoolCallback& callback);
 
  private:
   // Called when a FilePathWatcher is created and started.
@@ -84,11 +71,11 @@
                         base::FilePathWatcher* file_path_watcher);
 
   base::FilePathWatcher* local_file_watcher_;
-  base::FilePath local_path_;
   base::FilePath virtual_path_;
-  ExtensionUsageRegistry extensions_;
-  int ref_count_;
-  bool is_remote_file_system_;
+  // Map of extension-id to counter. See the comment at AddExtension() for
+  // why we need to count.
+  typedef std::map<std::string, int> ExtensionCountMap;
+  ExtensionCountMap extensions_;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate the weak pointers before any other members are destroyed.
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_watcher_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/file_watcher_unittest.cc
new file mode 100644
index 0000000..6e96f66
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/file_manager/file_watcher_unittest.cc
@@ -0,0 +1,157 @@
+// 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/extensions/file_manager/file_watcher.h"
+
+#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chrome/browser/google_apis/test_util.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace file_manager {
+namespace {
+
+using google_apis::test_util::CreateQuitCallback;
+using google_apis::test_util::CreateCopyResultCallback;
+
+class FileManagerFileWatcherTest : public testing::Test {
+ public:
+  // Use IO_MAINLOOP so FilePathWatcher works in the fake FILE thread, which
+  // is actually shared with the main thread.
+  FileManagerFileWatcherTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+};
+
+TEST_F(FileManagerFileWatcherTest, AddAndRemoveOneExtensionId) {
+  const base::FilePath kVirtualPath =
+      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
+  const char kExtensionId[] = "extension-id";
+
+  FileWatcher file_watcher(kVirtualPath);
+  file_watcher.AddExtension(kExtensionId);
+  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
+
+  ASSERT_EQ(1U, extension_ids.size());
+  ASSERT_EQ(kExtensionId, extension_ids[0]);
+
+  file_watcher.RemoveExtension(kExtensionId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(0U, extension_ids.size());
+}
+
+TEST_F(FileManagerFileWatcherTest, AddAndRemoveMultipleExtensionIds) {
+  const base::FilePath kVirtualPath =
+      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
+  const char kExtensionFooId[] = "extension-foo-id";
+  const char kExtensionBarId[] = "extension-bar-id";
+
+  FileWatcher file_watcher(kVirtualPath);
+  file_watcher.AddExtension(kExtensionFooId);
+  file_watcher.AddExtension(kExtensionBarId);
+  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
+
+  // The list should be sorted.
+  ASSERT_EQ(2U, extension_ids.size());
+  ASSERT_EQ(kExtensionBarId, extension_ids[0]);
+  ASSERT_EQ(kExtensionFooId, extension_ids[1]);
+
+  // Remove Foo. Bar should remain.
+  file_watcher.RemoveExtension(kExtensionFooId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(1U, extension_ids.size());
+  ASSERT_EQ(kExtensionBarId, extension_ids[0]);
+
+  // Remove Bar. Nothing should remain.
+  file_watcher.RemoveExtension(kExtensionBarId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(0U, extension_ids.size());
+}
+
+TEST_F(FileManagerFileWatcherTest, AddSameExtensionMultipleTimes) {
+  const base::FilePath kVirtualPath =
+      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
+  const char kExtensionId[] = "extension-id";
+
+  FileWatcher file_watcher(kVirtualPath);
+  // Add three times.
+  file_watcher.AddExtension(kExtensionId);
+  file_watcher.AddExtension(kExtensionId);
+  file_watcher.AddExtension(kExtensionId);
+
+  std::vector<std::string> extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(1U, extension_ids.size());
+  ASSERT_EQ(kExtensionId, extension_ids[0]);
+
+  // Remove 1st time.
+  file_watcher.RemoveExtension(kExtensionId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(1U, extension_ids.size());
+
+  // Remove 2nd time.
+  file_watcher.RemoveExtension(kExtensionId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(1U, extension_ids.size());
+
+  // Remove 3rd time. The extension ID should be gone now.
+  file_watcher.RemoveExtension(kExtensionId);
+  extension_ids = file_watcher.GetExtensionIds();
+  ASSERT_EQ(0U, extension_ids.size());
+}
+
+TEST_F(FileManagerFileWatcherTest, WatchLocalFile) {
+  const base::FilePath kVirtualPath =
+      base::FilePath::FromUTF8Unsafe("foo/bar.txt");
+  const char kExtensionId[] = "extension-id";
+
+  // Create a temporary directory.
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+  // See the comment at the end of this function for why scoped_ptr is used.
+  scoped_ptr<FileWatcher> file_watcher(
+      new FileWatcher(kVirtualPath));
+  file_watcher->AddExtension(kExtensionId);
+
+  // Start watching changes in the temporary directory.
+  base::FilePath changed_path;
+  bool watcher_created = false;
+  bool on_change_error = false;
+  base::RunLoop run_loop;
+  file_watcher->WatchLocalFile(
+      temp_dir.path(),
+      CreateQuitCallback(
+          &run_loop,
+          CreateCopyResultCallback(&changed_path, &on_change_error)),
+      CreateCopyResultCallback(&watcher_created));
+  // Spin the message loop so the base::FilePathWatcher is created.
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(watcher_created);
+
+  // Create a temporary file in the temporary directory. The file watcher
+  // should detect the change in the directory.
+  base::FilePath temp_file_path;
+  ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(),
+                                                  &temp_file_path));
+  // Wait until the directory change is notified.
+  run_loop.Run();
+  ASSERT_FALSE(on_change_error);
+  ASSERT_EQ(temp_dir.path().value(), changed_path.value());
+
+  // This is ugly, but FileWatcher should be deleted explicitly here, and
+  // spin the message loop so the base::FilePathWatcher is deleted.
+  // Otherwise, base::FilePathWatcher may detect a change when the temporary
+  // directory is deleted, which may result in crash.
+  file_watcher.reset();
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace file_manager.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
index cb5380d..e257dce 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_tasks.cc
@@ -621,9 +621,6 @@
   args_->GetList(0, &path_list);
   DCHECK(path_list);
 
-  std::string internal_task_id;
-  args_->GetString(1, &internal_task_id);
-
   std::vector<base::FilePath> files;
   for (size_t i = 0; i < path_list->GetSize(); ++i) {
     std::string url_as_string;
@@ -641,8 +638,7 @@
 
   if (browser) {
     for (size_t i = 0; i < files.size(); ++i) {
-      bool handled = util::ExecuteBuiltinHandler(
-          browser, files[i], internal_task_id);
+      bool handled = util::ExecuteBuiltinHandler(browser, files[i]);
       if (!handled && files.size() == 1)
         success = false;
     }
diff --git a/chrome/browser/chromeos/input_method/keyboard_browsertest.cc b/chrome/browser/chromeos/input_method/keyboard_browsertest.cc
index 21c41b9..fb3579d 100644
--- a/chrome/browser/chromeos/input_method/keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/input_method/keyboard_browsertest.cc
@@ -13,7 +13,9 @@
 
 typedef TextInputTestBase KeyboardEventEndToEndTest;
 
-IN_PROC_BROWSER_TEST_F(KeyboardEventEndToEndTest, AltGrToCtrlAltKeyDown) {
+// Flaky test: 268049
+IN_PROC_BROWSER_TEST_F(KeyboardEventEndToEndTest,
+                       DISABLED_AltGrToCtrlAltKeyDown) {
   TextInputTestHelper helper;
 
   GURL url = ui_test_utils::GetTestUrl(
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index d7fef07..94bd1b5 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -95,7 +95,6 @@
       ::switches::kEnableBrowserInputController,
       ::switches::kEnableCompositingForFixedPosition,
       ::switches::kEnableDelegatedRenderer,
-      ::switches::kEnableEncodedScreenCapture,
       ::switches::kEnableEncryptedMedia,
       ::switches::kEnableGestureTapHighlight,
       ::switches::kDisableGestureTapHighlight,
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.cc b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
index 6e49d1b..197417d 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
@@ -94,11 +94,15 @@
       device_management_service_(service),
       local_state_(local_state) {
   DCHECK_LE(power_initial_, power_limit_);
+  DCHECK(!completion_callback_.is_null());
   if (!serial_number.empty())
     serial_number_hash_ = crypto::SHA256HashString(serial_number);
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
 }
 
-AutoEnrollmentClient::~AutoEnrollmentClient() {}
+AutoEnrollmentClient::~AutoEnrollmentClient() {
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+}
 
 // static
 void AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) {
@@ -165,7 +169,7 @@
   if (GetCachedDecision()) {
     VLOG(1) << "AutoEnrollmentClient: using cached decision: "
             << should_auto_enroll_;
-  } else if (device_management_service_.get()) {
+  } else if (device_management_service_) {
     if (serial_number_hash_.empty()) {
       LOG(ERROR) << "Failed to get the hash of the serial number, "
                  << "will not attempt to auto-enroll.";
@@ -194,6 +198,25 @@
   }
 }
 
+void AutoEnrollmentClient::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  if (GetCachedDecision()) {
+    // A previous request already obtained a definitive response from the
+    // server, so there is no point in retrying; it will get the same decision.
+    return;
+  }
+
+  if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
+      !completion_callback_.is_null() &&
+      !request_job_ &&
+      device_management_service_ &&
+      !serial_number_hash_.empty()) {
+    VLOG(1) << "Retrying auto enrollment check after network changed";
+    time_start_ = base::Time::Now();
+    SendRequest(power_initial_);
+  }
+}
+
 bool AutoEnrollmentClient::GetCachedDecision() {
   const PrefService::Preference* should_enroll_pref =
       local_state_->FindPreference(prefs::kShouldAutoEnroll);
@@ -219,7 +242,7 @@
 void AutoEnrollmentClient::SendRequest(int power) {
   if (power < 0 || power > power_limit_ || serial_number_hash_.empty()) {
     NOTREACHED();
-    OnProtocolDone();
+    OnRequestDone();
     return;
   }
 
@@ -255,7 +278,8 @@
     UMA_HISTOGRAM_SPARSE_SLOWLY(kUMARequestStatus, status);
     if (status == DM_STATUS_REQUEST_FAILED)
       UMA_HISTOGRAM_SPARSE_SLOWLY(kUMANetworkErrorCode, -net_error);
-    OnProtocolDone();
+    // The client will retry if a network change is detected.
+    OnRequestDone();
     return;
   }
 
@@ -285,8 +309,10 @@
                      << power << ") that isn't larger than the first used ("
                      << power_initial_ << "). Retrying anyway.";
       }
+      // Remember this value, so that eventual retries start with the correct
+      // modulus.
+      power_initial_ = power;
       SendRequest(power);
-      // Don't invoke the callback yet.
       return;
     }
   } else {
@@ -327,15 +353,10 @@
   if (!time_start_.is_null()) {
     base::TimeDelta delta = now - time_start_;
     UMA_HISTOGRAM_CUSTOM_TIMES(kUMAProtocolTime, delta, kMin, kMax, kBuckets);
-    time_start_ = base::Time();
   }
   base::TimeDelta delta = kZero;
-  if (!time_extra_start_.is_null()) {
-    // CancelAndDeleteSoon() was invoked before.
+  if (!time_extra_start_.is_null())
     delta = now - time_extra_start_;
-    base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
-    time_extra_start_ = base::Time();
-  }
   // This samples |kZero| when there was no need for extra time, so that we can
   // measure the ratio of users that succeeded without needing a delay to the
   // total users going through OOBE.
@@ -343,6 +364,18 @@
 
   if (!completion_callback_.is_null())
     completion_callback_.Run();
+
+  OnRequestDone();
+}
+
+void AutoEnrollmentClient::OnRequestDone() {
+  request_job_.reset();
+  time_start_ = base::Time();
+
+  if (completion_callback_.is_null()) {
+    // CancelAndDeleteSoon() was invoked before.
+    base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
+  }
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.h b/chrome/browser/chromeos/policy/auto_enrollment_client.h
index 95c22ef..921dc0d 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.h
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.h
@@ -13,6 +13,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/policy/cloud/cloud_policy_constants.h"
+#include "net/base/network_change_notifier.h"
 #include "third_party/protobuf/src/google/protobuf/repeated_field.h"
 
 class PrefRegistrySimple;
@@ -30,7 +31,8 @@
 // Interacts with the device management service and determines whether this
 // machine should automatically enter the Enterprise Enrollment screen during
 // OOBE.
-class AutoEnrollmentClient {
+class AutoEnrollmentClient
+    : public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
   // |completion_callback| will be invoked on completion of the protocol, after
   // Start() is invoked.
@@ -79,6 +81,10 @@
   // It can be reused for subsequent requests to the device management service.
   std::string device_id() const { return device_id_; }
 
+  // Implementation of net::NetworkChangeNotifier::NetworkChangeObserver:
+  virtual void OnNetworkChanged(
+      net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
+
  private:
   // Tries to load the result of a previous execution of the protocol from
   // local state. Returns true if that decision has been made and is valid.
@@ -103,6 +109,10 @@
   // some UMA metrics.
   void OnProtocolDone();
 
+  // Invoked when a request job completes. Resets the internal state, and
+  // deletes the client if necessary.
+  void OnRequestDone();
+
   // Callback to invoke when the protocol completes.
   base::Closure completion_callback_;
 
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
index cfd609e..18554fa 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/prefs/testing_pref_service.h"
 #include "base/values.h"
@@ -14,6 +15,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "crypto/sha2.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -99,6 +101,12 @@
         .WillOnce(service_->SucceedJob(response));
   }
 
+  void ServerWillReplyAsync(MockDeviceManagementJob** job) {
+    EXPECT_CALL(*service_,
+                CreateJob(DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT))
+        .WillOnce(service_->CreateAsyncJob(job));
+  }
+
   bool HasCachedDecision() {
     return local_state_->GetUserPref(prefs::kShouldAutoEnroll);
   }
@@ -118,6 +126,7 @@
     return last_request_.auto_enrollment_request();
   }
 
+  content::TestBrowserThreadBundle browser_threads_;
   ScopedTestingLocalState scoped_testing_local_state_;
   TestingPrefServiceSimple* local_state_;
   MockDeviceManagementService* service_;
@@ -133,7 +142,7 @@
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
   client_->Start();
   EXPECT_FALSE(client_->should_auto_enroll());
-  EXPECT_EQ(1, completion_callback_count_);
+  EXPECT_EQ(0, completion_callback_count_);
   EXPECT_FALSE(HasCachedDecision());
 }
 
@@ -164,7 +173,7 @@
   ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
   client_->Start();
   EXPECT_FALSE(client_->should_auto_enroll());
-  EXPECT_EQ(1, completion_callback_count_);
+  EXPECT_EQ(0, completion_callback_count_);
   EXPECT_FALSE(HasCachedDecision());
 }
 
@@ -236,6 +245,11 @@
   EXPECT_FALSE(client_->should_auto_enroll());
   EXPECT_EQ(1, completion_callback_count_);
   VerifyCachedResult(false, 8);
+
+  // Network changes don't trigger retries after obtaining a response from
+  // the server.
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_EQ(1, completion_callback_count_);
 }
 
 TEST_F(AutoEnrollmentClientTest, EnterpriseDevice) {
@@ -244,6 +258,11 @@
   EXPECT_TRUE(client_->should_auto_enroll());
   EXPECT_EQ(1, completion_callback_count_);
   VerifyCachedResult(true, 8);
+
+  // Network changes don't trigger retries after obtaining a response from
+  // the server.
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_EQ(1, completion_callback_count_);
 }
 
 TEST_F(AutoEnrollmentClientTest, NoSerial) {
@@ -323,6 +342,112 @@
   EXPECT_EQ(1, completion_callback_count_);
 }
 
+TEST_F(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) {
+  ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
+  client_->Start();
+  EXPECT_FALSE(client_->should_auto_enroll());
+  // Don't invoke the callback if there was a network failure.
+  EXPECT_EQ(0, completion_callback_count_);
+  EXPECT_FALSE(HasCachedDecision());
+
+  // The client doesn't retry if no new connection became available.
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
+  EXPECT_FALSE(client_->should_auto_enroll());
+  EXPECT_EQ(0, completion_callback_count_);
+  EXPECT_FALSE(HasCachedDecision());
+
+  // Retry once the network is back.
+  ServerWillReply(-1, true, true);
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_TRUE(client_->should_auto_enroll());
+  EXPECT_EQ(1, completion_callback_count_);
+  EXPECT_TRUE(HasCachedDecision());
+
+  // Subsequent network changes don't trigger retries.
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE);
+  client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_TRUE(client_->should_auto_enroll());
+  EXPECT_EQ(1, completion_callback_count_);
+  EXPECT_TRUE(HasCachedDecision());
+}
+
+TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) {
+  MockDeviceManagementJob* job = NULL;
+  ServerWillReplyAsync(&job);
+  EXPECT_FALSE(job);
+  client_->Start();
+  ASSERT_TRUE(job);
+  EXPECT_EQ(0, completion_callback_count_);
+
+  // Cancel while a request is in flight.
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+  client_.release()->CancelAndDeleteSoon();
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+
+  // The client cleans itself up once a reply is received.
+  job->SendResponse(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                    em::DeviceManagementResponse());
+  // The DeleteSoon task has been posted:
+  EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting());
+  EXPECT_EQ(0, completion_callback_count_);
+}
+
+TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) {
+  MockDeviceManagementJob* job = NULL;
+  ServerWillReplyAsync(&job);
+  EXPECT_FALSE(job);
+  client_->Start();
+  ASSERT_TRUE(job);
+  EXPECT_EQ(0, completion_callback_count_);
+
+  // Cancel while a request is in flight.
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+  AutoEnrollmentClient* client = client_.release();
+  client->CancelAndDeleteSoon();
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+
+  // Network change events are ignored while a request is pending.
+  client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_EQ(0, completion_callback_count_);
+
+  // The client cleans itself up once a reply is received.
+  job->SendResponse(DM_STATUS_TEMPORARY_UNAVAILABLE,
+                    em::DeviceManagementResponse());
+  // The DeleteSoon task has been posted:
+  EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting());
+  EXPECT_EQ(0, completion_callback_count_);
+
+  // Network changes that have been posted before are also ignored:
+  client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET);
+  EXPECT_EQ(0, completion_callback_count_);
+}
+
+TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) {
+  ServerWillReply(-1, true, true);
+  client_->Start();
+  EXPECT_EQ(1, completion_callback_count_);
+  EXPECT_TRUE(client_->should_auto_enroll());
+
+  // The client will delete itself immediately if there are no pending
+  // requests.
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+  client_.release()->CancelAndDeleteSoon();
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+}
+
+TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterNetworkFailure) {
+  ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE);
+  client_->Start();
+  EXPECT_EQ(0, completion_callback_count_);
+  EXPECT_FALSE(client_->should_auto_enroll());
+
+  // The client will delete itself immediately if there are no pending
+  // requests.
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+  client_.release()->CancelAndDeleteSoon();
+  EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting());
+}
+
 }  // namespace
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 237d66a..a0438e0 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -569,6 +569,17 @@
     }
   }
 
+  if (policy.has_use_24hour_clock()) {
+    if (policy.use_24hour_clock().has_use_24hour_clock()) {
+      policies->Set(key::kSystemUse24HourClock,
+                    POLICY_LEVEL_MANDATORY,
+                    POLICY_SCOPE_MACHINE,
+                    Value::CreateBooleanValue(
+                        policy.use_24hour_clock().use_24hour_clock()),
+                    NULL);
+    }
+  }
+
   if (policy.has_allow_redeem_offers()) {
     const em::AllowRedeemChromeOsRegistrationOffersProto& container(
         policy.allow_redeem_offers());
diff --git a/chrome/browser/chromeos/preferences.cc b/chrome/browser/chromeos/preferences.cc
index 279a3ea..bc82310 100644
--- a/chrome/browser/chromeos/preferences.cc
+++ b/chrome/browser/chromeos/preferences.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/chromeos/system/statistics_provider.h"
 #include "chrome/browser/download/download_util.h"
+#include "chrome/browser/feedback/tracing_manager.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/prefs/scoped_user_pref_update.h"
 #include "chrome/common/chrome_switches.h"
@@ -96,6 +97,11 @@
   }
 
   registry->RegisterBooleanPref(
+      prefs::kPerformanceTracingEnabled,
+      false,
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+
+  registry->RegisterBooleanPref(
       prefs::kTapToClickEnabled,
       true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
@@ -356,6 +362,8 @@
   BooleanPrefMember::NamedChangeCallback callback =
       base::Bind(&Preferences::OnPreferenceChanged, base::Unretained(this));
 
+  performance_tracing_enabled_.Init(prefs::kPerformanceTracingEnabled,
+                                    prefs, callback);
   tap_to_click_enabled_.Init(prefs::kTapToClickEnabled, prefs, callback);
   tap_dragging_enabled_.Init(prefs::kTapDraggingEnabled, prefs, callback);
   three_finger_click_enabled_.Init(prefs::kEnableTouchpadThreeFingerClick,
@@ -480,6 +488,13 @@
 }
 
 void Preferences::NotifyPrefChanged(const std::string* pref_name) {
+  if (!pref_name || *pref_name == prefs::kPerformanceTracingEnabled) {
+    const bool enabled = performance_tracing_enabled_.GetValue();
+    if (enabled)
+      tracing_manager_ = TracingManager::Create();
+    else
+      tracing_manager_.reset();
+  }
   if (!pref_name || *pref_name == prefs::kTapToClickEnabled) {
     const bool enabled = tap_to_click_enabled_.GetValue();
     system::touchpad_settings::SetTapToClick(enabled);
diff --git a/chrome/browser/chromeos/preferences.h b/chrome/browser/chromeos/preferences.h
index 9fb6c78..9c98650 100644
--- a/chrome/browser/chromeos/preferences.h
+++ b/chrome/browser/chromeos/preferences.h
@@ -18,6 +18,8 @@
 class PrefService;
 class PrefServiceSyncable;
 
+class TracingManager;
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -114,7 +116,9 @@
   PrefServiceSyncable* prefs_;
 
   input_method::InputMethodManager* input_method_manager_;
+  scoped_ptr<TracingManager> tracing_manager_;
 
+  BooleanPrefMember performance_tracing_enabled_;
   BooleanPrefMember tap_to_click_enabled_;
   BooleanPrefMember tap_dragging_enabled_;
   BooleanPrefMember three_finger_click_enabled_;
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.cc b/chrome/browser/chromeos/settings/cros_settings_names.cc
index cea9665..ac3369d 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.cc
+++ b/chrome/browser/chromeos/settings/cros_settings_names.cc
@@ -53,6 +53,10 @@
 const char kSystemTimezone[] = "cros.system.timezone";
 const char kSystemTimezonePolicy[] = "cros.system.timezone_policy";
 
+// Value of kUse24HourClock user preference of device' owner.
+// ChromeOS device uses this setting on login screen.
+const char kSystemUse24HourClock[] = "cros.system.use_24hour_clock";
+
 const char kDeviceOwner[] = "cros.device.owner";
 
 const char kStatsReportingPref[] = "cros.metrics.reportingEnabled";
diff --git a/chrome/browser/chromeos/settings/cros_settings_names.h b/chrome/browser/chromeos/settings/cros_settings_names.h
index 226e9301..eff6785 100644
--- a/chrome/browser/chromeos/settings/cros_settings_names.h
+++ b/chrome/browser/chromeos/settings/cros_settings_names.h
@@ -31,6 +31,7 @@
 
 extern const char kSystemTimezonePolicy[];
 extern const char kSystemTimezone[];
+extern const char kSystemUse24HourClock[];
 
 extern const char kDeviceOwner[];
 
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index f18d144..7816dc7 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -75,6 +75,7 @@
   kStartUpUrls,
   kStatsReportingPref,
   kSystemTimezonePolicy,
+  kSystemUse24HourClock,
   kUpdateDisabled,
   kVariationsRestrictParameter,
 };
@@ -375,6 +376,16 @@
           flags_proto->add_flags(flag);
       }
     }
+  } else if (prop == kSystemUse24HourClock) {
+    em::SystemUse24HourClockProto* use_24hour_clock_proto =
+        device_settings_.mutable_use_24hour_clock();
+    use_24hour_clock_proto->Clear();
+    bool use_24hour_clock_value;
+    if (value->GetAsBoolean(&use_24hour_clock_value)) {
+      use_24hour_clock_proto->set_use_24hour_clock(use_24hour_clock_value);
+    } else {
+      NOTREACHED();
+    }
   } else {
     // The remaining settings don't support Set(), since they are not
     // intended to be customizable by the user:
@@ -704,6 +715,13 @@
     }
   }
 
+  if (policy.has_use_24hour_clock()) {
+    if (policy.use_24hour_clock().has_use_24hour_clock()) {
+      new_values_cache->SetBoolean(
+          kSystemUse24HourClock, policy.use_24hour_clock().use_24hour_clock());
+    }
+  }
+
   if (policy.has_allow_redeem_offers()) {
     new_values_cache->SetBoolean(
         kAllowRedeemChromeOsRegistrationOffers,
diff --git a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
index 1580e0c..764b81e 100644
--- a/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
+++ b/chrome/browser/chromeos/system/ash_system_tray_delegate.cc
@@ -66,6 +66,7 @@
 #include "chrome/browser/chromeos/options/network_config_view.h"
 #include "chrome/browser/chromeos/options/network_connect.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/sim_dialog_delegate.h"
 #include "chrome/browser/chromeos/status/data_promo_notification.h"
 #include "chrome/browser/chromeos/system/timezone_settings.h"
@@ -85,7 +86,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -112,6 +112,7 @@
 #include "net/base/escape.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 
 using drive::DriveIntegrationService;
 using drive::DriveIntegrationServiceFactory;
@@ -884,7 +885,7 @@
 
   virtual string16 FormatTimeDuration(
       const base::TimeDelta& delta) const OVERRIDE {
-    return TimeFormat::TimeDurationLong(delta);
+    return ui::TimeFormat::TimeDurationLong(delta);
   }
 
   virtual void MaybeSpeak(const std::string& utterance) const OVERRIDE {
@@ -970,13 +971,40 @@
       integration_service->job_list()->RemoveObserver(this);
   }
 
+  bool ShouldUse24HourClock() const {
+    // On login screen and in guest mode owner default is used for
+    // kUse24HourClock preference.
+    // All other modes default to the default locale value.
+    const ash::user::LoginStatus status = GetUserLoginStatus();
+    const CrosSettings* const cros_settings = CrosSettings::Get();
+    bool system_use_24_hour_clock = true;
+    const bool system_value_found = cros_settings->GetBoolean(
+        kSystemUse24HourClock, &system_use_24_hour_clock);
+
+    if (status == ash::user::LOGGED_IN_NONE)
+      return (system_value_found ? system_use_24_hour_clock : true);
+
+    const PrefService::Preference* user_pref =
+        user_pref_registrar_->prefs()->FindPreference(prefs::kUse24HourClock);
+    if (status == ash::user::LOGGED_IN_GUEST && user_pref->IsDefaultValue())
+      return (system_value_found ? system_use_24_hour_clock : true);
+
+    bool use_24_hour_clock = true;
+    user_pref->GetValue()->GetAsBoolean(&use_24_hour_clock);
+    return use_24_hour_clock;
+  }
+
   void UpdateClockType() {
     if (!user_pref_registrar_)
       return;
-    clock_type_ =
-        user_pref_registrar_->prefs()->GetBoolean(prefs::kUse24HourClock) ?
-        base::k24HourClock : base::k12HourClock;
+
+    const bool use_24_hour_clock = ShouldUse24HourClock();
+    clock_type_ = use_24_hour_clock ? base::k24HourClock : base::k12HourClock;
     GetSystemTrayNotifier()->NotifyDateFormatChanged();
+    // This also works for enterprise-managed devices because they never have
+    // local owner.
+    if (chromeos::UserManager::Get()->IsCurrentUserOwner())
+      CrosSettings::Get()->SetBoolean(kSystemUse24HourClock, use_24_hour_clock);
   }
 
   void UpdateShowLogoutButtonInTray() {
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index cdb9f24..769a38b 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -43,17 +43,17 @@
 
 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT)
 
-// CRX hash. The extension id is: pdkaonnflpjcgibpgaanildgengnihcm.
-const uint8 kSha2Hash[] = { 0xf3, 0xa0, 0xed, 0xd5, 0xbf, 0x92, 0x68, 0x1f,
-                            0x60, 0x0d, 0x8b, 0x36, 0x4d, 0x6d, 0x87, 0x2c,
-                            0x86, 0x61, 0x12, 0x20, 0x21, 0xf8, 0x94, 0xdd,
-                            0xe1, 0xb6, 0xb4, 0x55, 0x34, 0x8c, 0x2e, 0x20 };
+// CRX hash. The extension id is: oimompecagnajdejgnnjijobebaeigek.
+const uint8 kSha2Hash[] = { 0xe8, 0xce, 0xcf, 0x42, 0x06, 0xd0, 0x93, 0x49,
+                            0x6d, 0xd9, 0x89, 0xe1, 0x41, 0x04, 0x86, 0x4a,
+                            0x8f, 0xbd, 0x86, 0x12, 0xb9, 0x58, 0x9b, 0xfb,
+                            0x4f, 0xbb, 0x1b, 0xa9, 0xd3, 0x85, 0x37, 0xef };
 
 // File name of the Widevine CDM component manifest on different platforms.
 const char kWidevineCdmManifestName[] = "WidevineCdm";
 
 // Name of the Widevine CDM OS in the component manifest.
-const char kWidevineCdmOperatingSystem[] =
+const char kWidevineCdmPlatform[] =
 #if defined(OS_MACOSX)
     "mac";
 #elif defined(OS_WIN)
@@ -65,7 +65,7 @@
 // Name of the Widevine CDM architecture in the component manifest.
 const char kWidevineCdmArch[] =
 #if defined(ARCH_CPU_X86)
-    "ia32";
+    "x86";
 #elif defined(ARCH_CPU_X86_64)
     "x64";
 #else  // TODO(viettrungluu): Support an ARM check?
@@ -83,6 +83,16 @@
   return result;
 }
 
+// Widevine CDM is packaged as a multi-CRX. Widevine CDM binaries are located in
+// _platform_specific/<platform_arch> folder in the package. This function
+// returns the platform-specific subdirectory that is part of that multi-CRX.
+base::FilePath GetPlatformDirectory(const base::FilePath& base_path) {
+  std::string platform_arch = kWidevineCdmPlatform;
+  platform_arch += '_';
+  platform_arch += kWidevineCdmArch;
+  return base_path.AppendASCII("_platform_specific").AppendASCII(platform_arch);
+}
+
 // Widevine CDM has the version encoded in the path so we need to enumerate the
 // directories to find the full path.
 // On success, |latest_dir| returns something like:
@@ -172,16 +182,6 @@
   if (!version.IsValid())
     return false;
 
-  std::string os;
-  manifest.GetStringASCII("x-widevine-cdm-os", &os);
-  if (os != kWidevineCdmOperatingSystem)
-    return false;
-
-  std::string arch;
-  manifest.GetStringASCII("x-widevine-cdm-arch", &arch);
-  if (arch != kWidevineCdmArch)
-    return false;
-
   *version_out = version;
   return true;
 }
@@ -221,8 +221,10 @@
   if (current_version_.CompareTo(version) > 0)
     return false;
 
-  if (!base::PathExists(unpack_path.AppendASCII(kWidevineCdmFileName)))
+  if (!base::PathExists(
+      GetPlatformDirectory(unpack_path).AppendASCII(kWidevineCdmFileName))) {
     return false;
+  }
 
   base::FilePath adapter_source_path;
   PathService::Get(chrome::FILE_WIDEVINE_CDM_ADAPTER, &adapter_source_path);
@@ -237,8 +239,8 @@
   if (!base::Move(unpack_path, install_path))
     return false;
 
-  base::FilePath adapter_install_path =
-      install_path.AppendASCII(kWidevineCdmAdapterFileName);
+  base::FilePath adapter_install_path = GetPlatformDirectory(install_path)
+      .AppendASCII(kWidevineCdmAdapterFileName);
   if (!base::CopyFile(adapter_source_path, adapter_install_path))
     return false;
 
@@ -249,18 +251,17 @@
   return true;
 }
 
+// Given |file|, a path like "_platform_specific/win_x86/widevinecdm.dll",
+// returns the assumed install path. The path separator in |file| is '/'
+// for all platforms. Caller is responsible for checking that the
+// |installed_file| actually exists.
 bool WidevineCdmComponentInstaller::GetInstalledFile(
     const std::string& file, base::FilePath* installed_file) {
-  // Only the CDM is component-updated.
-  if (file != kWidevineCdmFileName)
-    return false;
-
   if (current_version_.Equals(base::Version(kNullVersion)))
     return false;  // No CDM has been installed yet.
 
-  *installed_file =
-      GetWidevineCdmBaseDirectory().AppendASCII(current_version_.GetString())
-          .AppendASCII(kWidevineCdmFileName);
+  *installed_file = GetWidevineCdmBaseDirectory().AppendASCII(
+      current_version_.GetString()).AppendASCII(file);
   return true;
 }
 
@@ -292,9 +293,11 @@
   std::vector<base::FilePath> older_dirs;
 
   if (GetWidevineCdmDirectory(&latest_dir, &version, &older_dirs)) {
+    base::FilePath latest_platform_dir = GetPlatformDirectory(latest_dir);
     base::FilePath adapter_path =
-        latest_dir.AppendASCII(kWidevineCdmAdapterFileName);
-    base::FilePath cdm_path = latest_dir.AppendASCII(kWidevineCdmFileName);
+        latest_platform_dir.AppendASCII(kWidevineCdmAdapterFileName);
+    base::FilePath cdm_path =
+        latest_platform_dir.AppendASCII(kWidevineCdmFileName);
 
     if (base::PathExists(adapter_path) &&
         base::PathExists(cdm_path)) {
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index b10a7ce..58791d1 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -290,6 +290,9 @@
         return BrowserThread::CurrentlyOn(BrowserThread::UI);
       case base::MessageLoop::TYPE_IO:
         return BrowserThread::CurrentlyOn(BrowserThread::IO);
+#if defined(OS_ANDROID)
+      case base::MessageLoop::TYPE_JAVA: // fall-through
+#endif // defined(OS_ANDROID)
       case base::MessageLoop::TYPE_DEFAULT:
         return !BrowserThread::CurrentlyOn(BrowserThread::UI) &&
                !BrowserThread::CurrentlyOn(BrowserThread::IO);
diff --git a/chrome/browser/devtools/adb_client_socket.cc b/chrome/browser/devtools/adb_client_socket.cc
index f316e77..98e9065 100644
--- a/chrome/browser/devtools/adb_client_socket.cc
+++ b/chrome/browser/devtools/adb_client_socket.cc
@@ -158,6 +158,7 @@
     response_ += std::string(response_buffer->data(), result);
     int expected_length = 0;
     if (bytes_total < 0) {
+      // TODO(kaznacheev): Use net::HttpResponseHeader to parse the header.
       size_t content_pos = response_.find("Content-Length:");
       if (content_pos != std::string::npos) {
         size_t endline_pos = response_.find("\n", content_pos);
@@ -181,7 +182,7 @@
 
     if (bytes_total == static_cast<int>(response_.length())) {
       if (!command_callback_.is_null())
-        command_callback_.Run(body_pos_, response_);
+        command_callback_.Run(net::OK, response_.substr(body_pos_));
       else
         socket_callback_.Run(net::OK, socket_.release());
       delete this;
diff --git a/chrome/browser/devtools/adb_web_socket.cc b/chrome/browser/devtools/adb_web_socket.cc
index 4e207a6..b740497 100644
--- a/chrome/browser/devtools/adb_web_socket.cc
+++ b/chrome/browser/devtools/adb_web_socket.cc
@@ -63,7 +63,7 @@
 AdbWebSocket::~AdbWebSocket() {}
 
 void AdbWebSocket::ConnectOnHandlerThread() {
-  device_->HttpQuery(
+  device_->HttpUpgrade(
       socket_name_,
       base::StringPrintf(kWebSocketUpgradeRequest, url_.c_str()),
       base::Bind(&AdbWebSocket::ConnectedOnHandlerThread, this));
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 3ce82bb..2973fa2 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/devtools/adb/android_rsa.h"
 #include "chrome/browser/devtools/adb_client_socket.h"
 #include "chrome/browser/devtools/adb_web_socket.h"
+#include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/devtools/tethering_adb_filter.h"
 #include "chrome/browser/profiles/profile.h"
@@ -51,10 +52,16 @@
 
 static const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
 static const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n";
+static const char kClosePageRequest[] = "GET /json/close/%s HTTP/1.1\r\n\r\n";
+static const char kNewPageRequest[] = "GET /json/new HTTP/1.1\r\n\r\n";
 const int kAdbPort = 5037;
 const int kBufferSize = 16 * 1024;
 const int kAdbPollingIntervalMs = 1000;
 
+static const char kUrlParam[] = "url";
+static const char kPageReloadCommand[] = "Page.reload";
+static const char kPageNavigateCommand[] = "Page.navigate";
+
 typedef DevToolsAdbBridge::Callback Callback;
 typedef std::vector<scoped_refptr<DevToolsAdbBridge::AndroidDevice> >
     AndroidDevices;
@@ -276,8 +283,7 @@
     }
 
     // Parse version, append to package name if available,
-    std::string body = response.substr(result);
-    scoped_ptr<base::Value> value(base::JSONReader::Read(body));
+    scoped_ptr<base::Value> value(base::JSONReader::Read(response));
     base::DictionaryValue* dict;
     if (value && value->GetAsDictionary(&dict)) {
       std::string browser;
@@ -303,8 +309,7 @@
       return;
     }
 
-    std::string body = response.substr(result);
-    scoped_ptr<base::Value> value(base::JSONReader::Read(body));
+    scoped_ptr<base::Value> value(base::JSONReader::Read(response));
     base::ListValue* list_value;
     if (!value || !value->GetAsList(&list_value)) {
       ProcessSockets();
@@ -384,6 +389,57 @@
   scoped_ptr<DevToolsAdbBridge::RemoteDevices> remote_devices_;
 };
 
+// AdbProtocolCommand ---------------------------------------------------------
+
+class AdbProtocolCommand : public AdbWebSocket::Delegate {
+ public:
+  AdbProtocolCommand(
+      scoped_refptr<DevToolsAdbBridge> bridge_,
+      scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+      const std::string& socket_name,
+      const std::string& debug_url,
+      const std::string& command);
+
+ private:
+  virtual void OnSocketOpened() OVERRIDE;
+  virtual void OnFrameRead(const std::string& message) OVERRIDE;
+  virtual void OnSocketClosed(bool closed_by_device) OVERRIDE;
+  virtual bool ProcessIncomingMessage(const std::string& message) OVERRIDE;
+
+  scoped_refptr<DevToolsAdbBridge> bridge_;
+  const std::string command_;
+  scoped_refptr<AdbWebSocket> web_socket_;
+
+  DISALLOW_COPY_AND_ASSIGN(AdbProtocolCommand);
+};
+
+AdbProtocolCommand::AdbProtocolCommand(
+    scoped_refptr<DevToolsAdbBridge> bridge,
+    scoped_refptr<DevToolsAdbBridge::AndroidDevice> device,
+    const std::string& socket_name,
+    const std::string& debug_url,
+    const std::string& command)
+    : bridge_(bridge),
+      command_(command) {
+  web_socket_ = new AdbWebSocket(
+      device, socket_name, debug_url, bridge_->GetAdbMessageLoop(), this);
+}
+
+void AdbProtocolCommand::OnSocketOpened() {
+  web_socket_->SendFrame(command_);
+  web_socket_->Disconnect();
+}
+
+void AdbProtocolCommand::OnFrameRead(const std::string& message) {}
+
+void AdbProtocolCommand::OnSocketClosed(bool closed_by_device) {
+  delete this;
+}
+
+bool AdbProtocolCommand::ProcessIncomingMessage(const std::string& message) {
+  return false;
+}
+
 }  // namespace
 
 const char kDevToolsChannelNameFormat[] = "%s_devtools_remote";
@@ -445,7 +501,7 @@
                                  request, callback));
 }
 
-void DevToolsAdbBridge::AndroidDevice::HttpQuery(
+void DevToolsAdbBridge::AndroidDevice::HttpUpgrade(
     const std::string& la_name,
     const std::string& request,
     const SocketCallback& callback) {
@@ -583,23 +639,48 @@
     frontend_url_ = frontend_url_.substr(0, ws_param);
   if (frontend_url_.find("http:") == 0)
     frontend_url_ = "https:" + frontend_url_.substr(5);
-
-  global_id_ = base::StringPrintf(
-      "%s:%s:%s", device->serial().c_str(), socket_.c_str(), id_.c_str());
 }
 
 void DevToolsAdbBridge::RemotePage::Inspect(Profile* profile) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  std::string agent_id = base::StringPrintf("%s:%s:%s",
+    device_->serial().c_str(), socket_.c_str(), id_.c_str());
   AgentHostDelegates::iterator it =
-      g_host_delegates.Get().find(global_id());
+      g_host_delegates.Get().find(agent_id);
   if (it != g_host_delegates.Get().end())
     it->second->OpenFrontend();
   else if (!debug_url_.empty())
     new AgentHostDelegate(
-        global_id_, device_, socket_, debug_url_,
+        agent_id, device_, socket_, debug_url_,
         frontend_url_, bridge_->GetAdbMessageLoop(), profile);
 }
 
+static void Noop(int, const std::string&) {}
+
+void DevToolsAdbBridge::RemotePage::Close() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  if (attached())
+    return;
+  std::string request = base::StringPrintf(kClosePageRequest, id_.c_str());
+  bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE,
+      base::Bind(&AndroidDevice::HttpQuery,
+          device_, socket_, request, base::Bind(&Noop)));
+}
+
+void DevToolsAdbBridge::RemotePage::Reload() {
+  SendProtocolCommand(kPageReloadCommand, NULL);
+}
+
+void DevToolsAdbBridge::RemotePage::SendProtocolCommand(
+    const std::string& method,
+    base::DictionaryValue* params) {
+  if (attached())
+    return;
+  DevToolsProtocol::Command command(1, method, params);
+  new AdbProtocolCommand(
+      bridge_, device_, socket_, debug_url_, command.Serialize());
+}
+
 DevToolsAdbBridge::RemotePage::~RemotePage() {
 }
 
@@ -614,6 +695,35 @@
       name_(name) {
 }
 
+void DevToolsAdbBridge::RemoteBrowser::Open(const std::string& url) {
+  bridge_->GetAdbMessageLoop()->PostTask(FROM_HERE,
+      base::Bind(&AndroidDevice::HttpQuery,
+          device_, socket_, kNewPageRequest,
+          base::Bind(&RemoteBrowser::PageCreatedOnHandlerThread, this, url)));
+}
+
+void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnHandlerThread(
+    const std::string& url, int result, const std::string& response) {
+  if (result < 0)
+    return;
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&RemoteBrowser::PageCreatedOnUIThread, this, response, url));
+}
+
+void DevToolsAdbBridge::RemoteBrowser::PageCreatedOnUIThread(
+    const std::string& response, const std::string& url) {
+  scoped_ptr<base::Value> value(base::JSONReader::Read(response));
+  base::DictionaryValue* dict;
+  if (value && value->GetAsDictionary(&dict)) {
+    scoped_refptr<RemotePage> new_page =
+        new RemotePage(bridge_, device_, socket_, *dict);
+    base::DictionaryValue params;
+    params.SetString(kUrlParam, url);
+    new_page->SendProtocolCommand(kPageNavigateCommand, &params);
+  }
+}
+
 DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() {
 }
 
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index 222edf1..cfd3482 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -95,9 +95,14 @@
     std::string title() { return title_; }
     std::string description() { return description_; }
     std::string favicon_url() { return favicon_url_; }
-    std::string global_id() { return global_id_; }
+    bool attached() { return debug_url_.empty(); }
 
     void Inspect(Profile* profile);
+    void Close();
+    void Reload();
+
+    void SendProtocolCommand(const std::string& method,
+                             base::DictionaryValue* params);
 
    private:
     friend class base::RefCounted<RemotePage>;
@@ -113,7 +118,6 @@
     std::string favicon_url_;
     std::string debug_url_;
     std::string frontend_url_;
-    std::string global_id_;
     DISALLOW_COPY_AND_ASSIGN(RemotePage);
   };
 
@@ -133,10 +137,18 @@
     RemotePages& pages() { return pages_; }
     void AddPage(scoped_refptr<RemotePage> page) { pages_.push_back(page); }
 
+    void Open(const std::string& url);
+
    private:
     friend class base::RefCounted<RemoteBrowser>;
     virtual ~RemoteBrowser();
 
+    void PageCreatedOnHandlerThread(
+        const std::string& url, int result, const std::string& response);
+
+    void PageCreatedOnUIThread(
+        const std::string& response, const std::string& url);
+
     scoped_refptr<DevToolsAdbBridge> bridge_;
     scoped_refptr<AndroidDevice> device_;
     const std::string socket_;
@@ -183,12 +195,12 @@
                             const CommandCallback& callback) = 0;
     virtual void OpenSocket(const std::string& socket_name,
                             const SocketCallback& callback) = 0;
-    virtual void HttpQuery(const std::string& la_name,
-                           const std::string& request,
-                           const CommandCallback& callback);
-    virtual void HttpQuery(const std::string& la_name,
-                           const std::string& request,
-                           const SocketCallback& callback);
+    void HttpQuery(const std::string& la_name,
+                   const std::string& request,
+                   const CommandCallback& callback);
+    void HttpUpgrade(const std::string& la_name,
+                     const std::string& request,
+                     const SocketCallback& callback);
 
     std::string serial() { return serial_; }
 
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.cc b/chrome/browser/devtools/devtools_file_system_indexer.cc
index 683b4b3..34d8ba8 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer.cc
+++ b/chrome/browser/devtools/devtools_file_system_indexer.cc
@@ -342,7 +342,7 @@
   FileUtilProxy::CreateOrOpen(
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE).get(),
       file_path,
-      base::PLATFORM_FILE_OPEN,
+      base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ,
       Bind(&FileSystemIndexingJob::StartFileIndexing, this));
 }
 
diff --git a/chrome/browser/devtools/devtools_protocol.cc b/chrome/browser/devtools/devtools_protocol.cc
new file mode 100644
index 0000000..eed5940
--- /dev/null
+++ b/chrome/browser/devtools/devtools_protocol.cc
@@ -0,0 +1,72 @@
+// 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 "chrome/browser/devtools/devtools_protocol.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+
+namespace {
+const char kIdParam[] = "id";
+const char kMethodParam[] = "method";
+const char kParamsParam[] = "params";
+}  // namespace
+
+DevToolsProtocol::Message::~Message() {
+}
+
+DevToolsProtocol::Message::Message(const std::string& method,
+                                   base::DictionaryValue* params)
+    : method_(method),
+      params_(params ? params->DeepCopy() : NULL) {
+}
+
+DevToolsProtocol::Command::Command(int id,
+                                   const std::string& method,
+                                   base::DictionaryValue* params)
+    : Message(method, params),
+      id_(id) {
+}
+
+DevToolsProtocol::Command::~Command() {
+}
+
+std::string DevToolsProtocol::Command::Serialize() {
+  base::DictionaryValue command;
+  command.SetInteger(kIdParam, id_);
+  command.SetString(kMethodParam, method_);
+  if (params_)
+    command.Set(kParamsParam, params_->DeepCopy());
+
+  std::string json_command;
+  base::JSONWriter::Write(&command, &json_command);
+  return json_command;
+}
+
+DevToolsProtocol::Notification::~Notification() {
+}
+
+DevToolsProtocol::Notification::Notification(const std::string& method,
+                                             base::DictionaryValue* params)
+    : Message(method, params) {
+}
+
+// static
+DevToolsProtocol::Notification* DevToolsProtocol::ParseNotification(
+    const std::string& json) {
+  scoped_ptr<base::Value> value(base::JSONReader::Read(json));
+  if (!value || !value->IsType(Value::TYPE_DICTIONARY))
+    return NULL;
+
+  scoped_ptr<base::DictionaryValue> dict(
+      static_cast<base::DictionaryValue*>(value.release()));
+
+  std::string method;
+  if (!dict->GetString(kMethodParam, &method))
+    return NULL;
+
+  base::DictionaryValue* params = NULL;
+  dict->GetDictionary(kParamsParam, &params);
+  return new Notification(method, params);
+}
diff --git a/chrome/browser/devtools/devtools_protocol.h b/chrome/browser/devtools/devtools_protocol.h
new file mode 100644
index 0000000..9a01eee
--- /dev/null
+++ b/chrome/browser/devtools/devtools_protocol.h
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
+#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/values.h"
+
+// Utility class for processing DevTools remote debugging messages.
+// This is a stripped down clone of content::DevTools which is not accessible
+// from chrome component (see content/browser/devtools/devtools_protocol.*).
+class DevToolsProtocol {
+ public:
+  class Message {
+   public:
+    virtual ~Message();
+
+    std::string method() { return method_; }
+    base::DictionaryValue* params() { return params_.get(); }
+
+   protected:
+    // Takes ownership of |params|.
+    Message(const std::string& method, base::DictionaryValue* params);
+
+    std::string method_;
+    scoped_ptr<base::DictionaryValue> params_;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Message);
+  };
+
+  class Command : public Message {
+   public:
+    // Takes ownership of |params|.
+    Command(int id, const std::string& method, base::DictionaryValue* params);
+    virtual  ~Command();
+
+    int id() { return id_; }
+    std::string Serialize();
+
+   private:
+    int id_;
+
+    DISALLOW_COPY_AND_ASSIGN(Command);
+  };
+
+  class Notification : public Message {
+   public:
+    virtual ~Notification();
+
+   private:
+    friend class DevToolsProtocol;
+
+    // Takes ownership of |params|.
+    Notification(const std::string& method,
+                 base::DictionaryValue* params);
+
+    DISALLOW_COPY_AND_ASSIGN(Notification);
+  };
+
+  static Notification* ParseNotification(const std::string& json);
+
+ private:
+
+  DevToolsProtocol() {}
+  ~DevToolsProtocol() {}
+};
+
+#endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
diff --git a/chrome/browser/devtools/tethering_adb_filter.cc b/chrome/browser/devtools/tethering_adb_filter.cc
index 829e933..887ba94 100644
--- a/chrome/browser/devtools/tethering_adb_filter.cc
+++ b/chrome/browser/devtools/tethering_adb_filter.cc
@@ -8,16 +8,14 @@
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
 #include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/values.h"
 #include "chrome/browser/devtools/adb_client_socket.h"
 #include "chrome/browser/devtools/adb_web_socket.h"
+#include "chrome/browser/devtools/devtools_protocol.h"
 #include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/address_list.h"
@@ -33,9 +31,6 @@
 const int kAdbPort = 5037;
 const int kBufferSize = 16 * 1024;
 
-static const char kIdAttribute[] = "id";
-static const char kMethodAttribute[] = "method";
-static const char kParamsAttribute[] = "params";
 static const char kPortAttribute[] = "port";
 static const char kConnectionIdAttribute[] = "connectionId";
 static const char kTetheringAccepted[] = "Tethering.accepted";
@@ -277,17 +272,10 @@
 }
 
 void TetheringAdbFilter::SendCommand(const std::string& method, int port) {
-  base::DictionaryValue command;
-  command.SetInteger(kIdAttribute, ++command_id_);
-  command.SetString(kMethodAttribute, method);
-
   base::DictionaryValue params;
   params.SetInteger(kPortAttribute, port);
-  command.Set(kParamsAttribute, params.DeepCopy());
-
-  std::string json_command;
-  base::JSONWriter::Write(&command, &json_command);
-  web_socket_->SendFrameOnHandlerThread(json_command);
+  DevToolsProtocol::Command command(++command_id_, method, &params);
+  web_socket_->SendFrameOnHandlerThread(command.Serialize());
 }
 
 bool TetheringAdbFilter::ProcessIncomingMessage(const std::string& message) {
@@ -298,20 +286,15 @@
       message.find(kTetheringAccepted) == std::string::npos)
     return false;
 
-  scoped_ptr<base::Value> value(base::JSONReader::Read(message));
-
-  DictionaryValue* dvalue;
-  if (!value || !value->GetAsDictionary(&dvalue))
+  scoped_ptr<DevToolsProtocol::Notification> notification(
+      DevToolsProtocol::ParseNotification(message));
+  if (!notification)
     return false;
 
-  std::string method;
-  if (!dvalue->GetString(kMethodAttribute, &method) ||
-      method != kTetheringAccepted) {
+  if (notification->method() != kTetheringAccepted)
     return false;
-  }
 
-  DictionaryValue* params = NULL;
-  dvalue->GetDictionary(kParamsAttribute, &params);
+  DictionaryValue* params = notification->params();
   if (!params)
     return false;
 
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index ac386be..b1c89fc 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -13,13 +13,13 @@
 #include "base/time/time.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/safe_browsing/download_feedback_service.h"
-#include "chrome/common/time_format.h"
 #include "content/public/browser/download_danger_type.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/download_item.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/text/bytes_formatting.h"
 #include "ui/base/text/text_elider.h"
 
@@ -519,14 +519,14 @@
 
     return l10n_util::GetStringFUTF16(
         IDS_DOWNLOAD_STATUS_OPEN_IN,
-        TimeFormat::TimeRemainingShort(time_remaining));
+        ui::TimeFormat::TimeRemainingShort(time_remaining));
   }
 
   // In progress download with known time left: "100/120 MB, 10 secs left"
   if (time_remaining_known) {
     return l10n_util::GetStringFUTF16(
         IDS_DOWNLOAD_STATUS_IN_PROGRESS, size_ratio,
-        TimeFormat::TimeRemaining(time_remaining));
+        ui::TimeFormat::TimeRemaining(time_remaining));
   }
 
   // In progress download with no known time left and non-zero completed bytes:
diff --git a/chrome/browser/download/download_util.cc b/chrome/browser/download/download_util.cc
index d660491..8010f97 100644
--- a/chrome/browser/download/download_util.cc
+++ b/chrome/browser/download/download_util.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_paths.h"
-#include "chrome/common/time_format.h"
 #include "content/public/browser/download_item.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/render_view_host.h"
@@ -40,6 +39,7 @@
 #include "third_party/skia/include/core/SkPath.h"
 #include "third_party/skia/include/core/SkShader.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/text/bytes_formatting.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/rect.h"
@@ -229,7 +229,7 @@
   if (download->IsPaused())
     time_remaining = l10n_util::GetStringUTF16(IDS_DOWNLOAD_PROGRESS_PAUSED);
   else if (download->TimeRemaining(&remaining))
-    time_remaining = TimeFormat::TimeRemaining(remaining);
+    time_remaining = ui::TimeFormat::TimeRemaining(remaining);
 
   if (time_remaining.empty()) {
     base::i18n::AdjustStringForLocaleDirection(&amount);
diff --git a/chrome/browser/extensions/DEPS b/chrome/browser/extensions/DEPS
index 0a10421..290e2e5 100644
--- a/chrome/browser/extensions/DEPS
+++ b/chrome/browser/extensions/DEPS
@@ -5,6 +5,7 @@
   # to depend on apps will be lifted.
   "-apps",
   "+apps/app_window_contents.h",
+  "+apps/launcher.h",
   "+apps/native_app_window.h",
   "+apps/shell_window.h",
 
diff --git a/chrome/browser/extensions/OWNERS b/chrome/browser/extensions/OWNERS
index 2ffbdc3..bc2836c 100644
--- a/chrome/browser/extensions/OWNERS
+++ b/chrome/browser/extensions/OWNERS
@@ -14,6 +14,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 2b6c64a..1bfc27b 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -87,7 +87,6 @@
 
 const char kEmptyFile[] = "Filename not yet determined";
 const char kFileAlreadyDeleted[] = "Download file already deleted";
-const char kHostPermission[] = "Access to that hostname must be requested";
 const char kIconNotFound[] = "Icon not found";
 const char kInvalidDangerType[] = "Invalid danger type";
 const char kInvalidFilename[] = "Invalid filename";
@@ -937,12 +936,7 @@
   EXTENSION_FUNCTION_VALIDATE(params.get());
   const extensions::api::downloads::DownloadOptions& options = params->options;
   GURL download_url(options.url);
-  if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_) ||
-      Fault((!download_url.SchemeIs("data") &&
-             (download_url.GetOrigin() != GetExtension()->url().GetOrigin()) &&
-             !extensions::PermissionsData::HasHostPermission(
-                 GetExtension(), download_url)),
-            errors::kHostPermission, &error_))
+  if (Fault(!download_url.is_valid(), errors::kInvalidURL, &error_))
     return false;
 
   Profile* current_profile = profile();
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 16575f8..a6fda46 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -40,7 +40,6 @@
 // Errors that can be returned through chrome.runtime.lastError.message.
 extern const char kEmptyFile[];
 extern const char kFileAlreadyDeleted[];
-extern const char kHostPermission[];
 extern const char kIconNotFound[];
 extern const char kInvalidDangerType[];
 extern const char kInvalidFilename[];
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index c398541..82a5f6f 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -1662,19 +1662,15 @@
       << kInvalidURLs[index];
   }
 
-  static const char* kDisallowedHost[] = {
-    "javascript:document.write(\\\"hello\\\");",
-    "javascript:return false;",
-    "ftp://example.com/example.txt",
-  };
-
-  for (size_t index = 0; index < arraysize(kDisallowedHost); ++index) {
-    EXPECT_STREQ(errors::kHostPermission,
-                  RunFunctionAndReturnError(new DownloadsDownloadFunction(),
-                                            base::StringPrintf(
-        "[{\"url\": \"%s\"}]", kDisallowedHost[index])).c_str())
-      << kDisallowedHost[index];
-  }
+  EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
+      new DownloadsDownloadFunction(),
+      "[{\"url\": \"javascript:document.write(\\\"hello\\\");\"}]").c_str());
+  EXPECT_STREQ("net::ERR_ACCESS_DENIED", RunFunctionAndReturnError(
+      new DownloadsDownloadFunction(),
+      "[{\"url\": \"javascript:return false;\"}]").c_str());
+  EXPECT_STREQ("net::ERR_NOT_IMPLEMENTED", RunFunctionAndReturnError(
+      new DownloadsDownloadFunction(),
+      "[{\"url\": \"ftp://example.com/example.txt\"}]").c_str());
 }
 
 // TODO(benjhayden): Set up a test ftp server, add ftp://localhost* to
diff --git a/chrome/browser/extensions/api/log_private/filter_handler.cc b/chrome/browser/extensions/api/log_private/filter_handler.cc
new file mode 100644
index 0000000..6965932
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/filter_handler.cc
@@ -0,0 +1,58 @@
+// 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/extensions/api/log_private/filter_handler.h"
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+
+namespace {
+
+template <typename T>
+bool IsValidField(const std::vector<T>& filter, const T& field) {
+  return (!filter.size() ||
+          std::find(filter.begin(), filter.end(), field) != filter.end());
+}
+
+}  // namespace
+
+FilterHandler::FilterHandler(const api::log_private::Filter& filter) {
+  scoped_ptr<base::DictionaryValue> filter_value = filter.ToValue();
+  api::log_private::Filter::Populate(*filter_value, &filter_);
+}
+
+FilterHandler::~FilterHandler() {}
+
+bool FilterHandler::IsValidLogEntry(
+    const api::log_private::LogEntry& entry) const {
+  return (IsValidProcess(entry.process) && IsValidLevel(entry.level) &&
+          IsValidTime(entry.timestamp));
+}
+
+bool FilterHandler::IsValidTime(double time) const {
+  const double kInvalidTime = 0;
+  if (filter_.start_timestamp != kInvalidTime &&
+      (filter_.start_timestamp > time || filter_.end_timestamp < time)) {
+    return false;
+  }
+  return true;
+}
+
+bool FilterHandler::IsValidSource(const std::string& source) const {
+  return IsValidField(filter_.sources, source);
+}
+
+bool FilterHandler::IsValidLevel(const std::string& level) const {
+  return IsValidField(filter_.level, level);
+}
+
+bool FilterHandler::IsValidProcess(const std::string& process) const {
+  return IsValidField(filter_.process, process);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/log_private/filter_handler.h b/chrome/browser/extensions/api/log_private/filter_handler.h
new file mode 100644
index 0000000..18e3129
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/filter_handler.h
@@ -0,0 +1,46 @@
+// 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_EXTENSIONS_API_LOG_PRIVATE_FILTER_HANDLER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_FILTER_HANDLER_H_
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+// This class contains multiple filtering methods to filter log entries
+// by multiple fields.
+class FilterHandler {
+ public:
+  explicit FilterHandler(const api::log_private::Filter& filter);
+  ~FilterHandler();
+
+  // This function decides if a log entry should be returned to user.
+  // Returns true if the log entry meets the filtering conditions.
+  bool IsValidLogEntry(const api::log_private::LogEntry& entry) const;
+  // Filters log by timestamp.
+  // Returns true if the timestamp is within the time range of the filter.
+  bool IsValidTime(double time) const;
+  // Filters log by source (syslog, network_event_log, etc).
+  // Returns true if the log is from specified source in the filter.
+  bool IsValidSource(const std::string& source) const;
+  // Filters log by level (DEBUG, ERROR, WARNING).
+  // Returns true if the log level is specified in the filter.
+  bool IsValidLevel(const std::string& level) const;
+  // Filters log by its process name.
+  // Returns true if the process name is specified in the filter.
+  bool IsValidProcess(const std::string& process) const;
+
+  const api::log_private::Filter* GetFilter() const { return &filter_; }
+ private:
+  api::log_private::Filter filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilterHandler);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_FILTER_HANDLER_H_
diff --git a/chrome/browser/extensions/api/log_private/log_parser.cc b/chrome/browser/extensions/api/log_private/log_parser.cc
new file mode 100644
index 0000000..d88c73a
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/log_parser.cc
@@ -0,0 +1,40 @@
+// 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/extensions/api/log_private/log_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/strings/string_split.h"
+#include "chrome/browser/extensions/api/log_private/log_private_api.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+using std::string;
+using std::vector;
+
+namespace extensions {
+
+LogParser::LogParser() {
+}
+
+LogParser::~LogParser() {
+}
+
+void LogParser::Parse(
+    const string& input,
+    std::vector<linked_ptr<api::log_private::LogEntry> >* output,
+    FilterHandler* filter_handler) const {
+  std::vector<string> entries;
+  // Assume there is no newline in the log entry
+  base::SplitString(input, '\n', &entries);
+
+  for (size_t i = 0; i < entries.size(); i++) {
+    ParseEntry(entries[i], output, filter_handler);
+  }
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/log_private/log_parser.h b/chrome/browser/extensions/api/log_private/log_parser.h
new file mode 100644
index 0000000..c73e54f
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/log_parser.h
@@ -0,0 +1,49 @@
+// 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_EXTENSIONS_API_LOG_PRIVATE_LOG_PARSER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_LOG_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "chrome/browser/extensions/api/log_private/filter_handler.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+
+// This is a abstract class of parsers for different logs.
+// All the specific parsers inherit from this class.
+class LogParser {
+ public:
+  enum Error {
+    SUCCESS = 0,
+    PARSE_ERROR = -1,
+    SERIALIZE_ERROR = -2,
+    TOKENIZE_ERROR = -3
+  };
+
+  virtual ~LogParser();
+  // Parses log text into multiple LogEntry objects.
+  void Parse(
+      const std::string& input,
+      std::vector<linked_ptr<api::log_private::LogEntry> >* output,
+      FilterHandler* filter_handler) const;
+
+ protected:
+  explicit LogParser();
+  // Parses a single line of log text into one LogEntry object.
+  virtual Error ParseEntry(
+      const std::string& input,
+      std::vector<linked_ptr<api::log_private::LogEntry> >* output,
+      FilterHandler* filter_handler) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LogParser);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_LOG_PARSER_H_
diff --git a/chrome/browser/extensions/api/log_private/log_private_api.h b/chrome/browser/extensions/api/log_private/log_private_api.h
new file mode 100644
index 0000000..f6f8911
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/log_private_api.h
@@ -0,0 +1,38 @@
+// 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_EXTENSIONS_API_LOG_PRIVATE_LOG_PRIVATE_API_H_
+#define CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_LOG_PRIVATE_API_H_
+
+#include <string>
+
+#include "chrome/browser/chromeos/system_logs/system_logs_fetcher.h"
+#include "chrome/browser/extensions/api/log_private/filter_handler.h"
+#include "chrome/browser/extensions/api/log_private/log_parser.h"
+#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+
+class LogPrivateGetHistoricalFunction : public AsyncExtensionFunction {
+ public:
+  LogPrivateGetHistoricalFunction();
+  DECLARE_EXTENSION_FUNCTION("logPrivate.getHistorical",
+                             LOGPRIVATE_GETHISTORICAL);
+
+ protected:
+  virtual ~LogPrivateGetHistoricalFunction();
+  virtual bool RunImpl() OVERRIDE;
+
+ private:
+  void OnSystemLogsLoaded(scoped_ptr<chromeos::SystemLogsResponse> sys_info);
+
+  scoped_ptr<FilterHandler> filter_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogPrivateGetHistoricalFunction);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_LOG_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
new file mode 100644
index 0000000..055c4ac
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc
@@ -0,0 +1,86 @@
+// 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/extensions/api/log_private/log_private_api.h"
+
+#include <string>
+#include <vector>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/chromeos/system_logs/system_logs_fetcher.h"
+#include "chrome/browser/extensions/api/log_private/filter_handler.h"
+#include "chrome/browser/extensions/api/log_private/log_parser.h"
+#include "chrome/browser/extensions/api/log_private/syslog_parser.h"
+#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+namespace {
+
+scoped_ptr<LogParser> CreateLogParser(const std::string& log_type) {
+  if (log_type == "syslog")
+    return scoped_ptr<LogParser>(new SyslogParser());
+  // TODO(shinfan): Add more parser here
+
+  NOTREACHED() << "Invalid log type: " << log_type;
+  return  scoped_ptr<LogParser>();
+}
+
+void CollectLogInfo(
+    FilterHandler* filter_handler,
+    chromeos::SystemLogsResponse* logs,
+    std::vector<linked_ptr<api::log_private::LogEntry> >* output) {
+  for (chromeos::SystemLogsResponse::const_iterator request_it = logs->begin();
+       request_it != logs->end();
+       ++request_it) {
+    if (!filter_handler->IsValidSource(request_it->first)) {
+      continue;
+    }
+    scoped_ptr<LogParser> parser(CreateLogParser(request_it->first));
+    if (parser) {
+      parser->Parse(request_it->second, output, filter_handler);
+    }
+  }
+}
+
+}  // namespace
+
+LogPrivateGetHistoricalFunction::LogPrivateGetHistoricalFunction() {
+}
+
+LogPrivateGetHistoricalFunction::~LogPrivateGetHistoricalFunction() {
+}
+
+bool LogPrivateGetHistoricalFunction::RunImpl() {
+  // Get parameters
+  scoped_ptr<api::log_private::GetHistorical::Params> params(
+      api::log_private::GetHistorical::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+  filter_handler_.reset(new FilterHandler(params->filter));
+
+  chromeos::SystemLogsFetcher* fetcher = new chromeos::SystemLogsFetcher();
+  fetcher->Fetch(
+      base::Bind(&LogPrivateGetHistoricalFunction::OnSystemLogsLoaded, this));
+  return true;
+}
+
+void LogPrivateGetHistoricalFunction::OnSystemLogsLoaded(
+    scoped_ptr<chromeos::SystemLogsResponse> sys_info) {
+  std::vector<linked_ptr<api::log_private::LogEntry> > data;
+
+  CollectLogInfo(filter_handler_.get(), sys_info.get(), &data);
+
+  // Prepare result
+  api::log_private::Result result;
+  result.data = data;
+  api::log_private::Filter::Populate(
+      *((filter_handler_->GetFilter())->ToValue()), &result.filter);
+  SetResult(result.ToValue().release());
+  SendResponse(true);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/log_private/log_private_api_nonchromeos.cc b/chrome/browser/extensions/api/log_private/log_private_api_nonchromeos.cc
new file mode 100644
index 0000000..c2ae4ad
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/log_private_api_nonchromeos.cc
@@ -0,0 +1,31 @@
+// 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/extensions/api/log_private/log_private_api.h"
+
+namespace extensions {
+
+namespace {
+
+const char kErrorNotImplemented[] = "Not implemented";
+
+}  // namespace
+
+LogPrivateGetHistoricalFunction::LogPrivateGetHistoricalFunction() {
+}
+
+LogPrivateGetHistoricalFunction::~LogPrivateGetHistoricalFunction() {
+}
+
+bool LogPrivateGetHistoricalFunction::RunImpl() {
+  SetError(kErrorNotImplemented);
+  SendResponse(error_.empty());
+  return false;
+}
+
+void LogPrivateGetHistoricalFunction::OnSystemLogsLoaded(
+    scoped_ptr<chromeos::SystemLogsResponse> sys_info) {
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/log_private/syslog_parser.cc b/chrome/browser/extensions/api/log_private/syslog_parser.cc
new file mode 100644
index 0000000..5479886
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/syslog_parser.cc
@@ -0,0 +1,144 @@
+// 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/extensions/api/log_private/syslog_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/time/time.h"
+#include "chrome/browser/extensions/api/log_private/filter_handler.h"
+#include "chrome/browser/extensions/api/log_private/log_parser.h"
+#include "chrome/browser/extensions/api/log_private/log_private_api.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+
+namespace {
+
+const int kExpectedTimeTokenNum = 7;
+const char kLogEntryDelimiters[] = "-:T";
+const char kProcessInfoDelimiters[] = "[]";
+
+}  // namespace
+
+SyslogParser::SyslogParser() {}
+
+SyslogParser::~SyslogParser() {}
+
+SyslogParser::Error SyslogParser::ParseEntry(
+    const std::string& input,
+    std::vector<linked_ptr<api::log_private::LogEntry> >* output,
+    FilterHandler* filter_handler) const {
+  linked_ptr<api::log_private::LogEntry> entry(new api::log_private::LogEntry);
+
+  base::StringTokenizer tokenizer(input, " ");
+  if (!tokenizer.GetNext()) {
+    LOG(ERROR)
+        << "Error when parsing data. Expect: At least 3 tokens. Actual: 0";
+    return TOKENIZE_ERROR;
+  }
+  std::string time = tokenizer.token();
+  if (ParseTime(time, &(entry->timestamp)) != SyslogParser::SUCCESS) {
+    return SyslogParser::PARSE_ERROR;
+  }
+  // Skips "localhost" field.
+  if (!tokenizer.GetNext()) {
+    LOG(ERROR)
+        << "Error when parsing data. Expect: At least 3 tokens. Actual: 1";
+    return TOKENIZE_ERROR;
+  }
+  if (!tokenizer.GetNext()) {
+    LOG(ERROR)
+        << "Error when parsing data. Expect: At least 3 tokens. Actual: 2";
+    return TOKENIZE_ERROR;
+  }
+  ParseProcess(tokenizer.token(), entry.get());
+  ParseLevel(input, entry.get());
+  entry->full_entry = input;
+
+  if (filter_handler->IsValidLogEntry(*(entry.get()))) {
+    output->push_back(entry);
+  }
+
+  return SyslogParser::SUCCESS;
+}
+
+SyslogParser::Error ParseTimeHelper(base::StringTokenizer* tokenizer,
+                                    std::string* output) {
+  if (!tokenizer->GetNext()) {
+    LOG(ERROR) << "Error when parsing time";
+    return SyslogParser::PARSE_ERROR;
+  }
+  *output = tokenizer->token();
+  return SyslogParser::SUCCESS;
+}
+
+SyslogParser::Error SyslogParser::ParseTime(const std::string& input,
+                                            double* output) const {
+  base::StringTokenizer tokenizer(input, kLogEntryDelimiters);
+  std::string tokens[kExpectedTimeTokenNum];
+  for (int i = 0; i < kExpectedTimeTokenNum; i++) {
+    if (ParseTimeHelper(&tokenizer, &(tokens[i])) != SyslogParser::SUCCESS)
+      return SyslogParser::PARSE_ERROR;
+  }
+
+  std::string buffer = tokens[1] + '-' + tokens[2] + '-' + tokens[0] + ' ' +
+                       tokens[3] + ':' + tokens[4] + ":00";
+
+  base::Time parsed_time;
+  if (!base::Time::FromString(buffer.c_str(), &parsed_time)) {
+    LOG(ERROR) << "Error when parsing time";
+    return SyslogParser::PARSE_ERROR;
+  }
+
+  double seconds;
+  base::StringToDouble(tokens[5], &seconds);
+  *output = parsed_time.ToJsTime() +
+            (seconds * base::Time::kMillisecondsPerSecond);
+
+  return SyslogParser::SUCCESS;
+}
+
+SyslogParser::Error SyslogParser::ParseProcess(
+    const std::string& input,
+    api::log_private::LogEntry* entry) const {
+  base::StringTokenizer tokenizer(input, kProcessInfoDelimiters);
+  if (!tokenizer.GetNext()) {
+    LOG(ERROR)
+        << "Error when parsing data. Expect: At least 1 token. Actual: 0";
+    return SyslogParser::PARSE_ERROR;
+  }
+  entry->process = tokenizer.token();
+  entry->process_id = "unknown";
+  if (tokenizer.GetNext()) {
+    std::string token = tokenizer.token();
+    int tmp;
+    if (base::StringToInt(token, &tmp)) {
+      entry->process_id = token;
+    }
+  }
+  return SyslogParser::SUCCESS;
+}
+
+void SyslogParser::ParseLevel(const std::string& input,
+                              api::log_private::LogEntry* entry) const {
+  if (input.find("ERROR") != std::string::npos) {
+    entry->level = "error";
+  } else if (input.find("WARN") != std::string::npos) {
+    entry->level = "warning";
+  } else if (input.find("INFO") != std::string::npos) {
+    entry->level = "info";
+  } else {
+    entry->level = "unknown";
+  }
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/log_private/syslog_parser.h b/chrome/browser/extensions/api/log_private/syslog_parser.h
new file mode 100644
index 0000000..b746334
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/syslog_parser.h
@@ -0,0 +1,46 @@
+// 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_EXTENSIONS_API_LOG_PRIVATE_SYSLOG_PARSER_H_
+#define CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_SYSLOG_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/linked_ptr.h"
+#include "chrome/browser/extensions/api/log_private/log_parser.h"
+#include "chrome/common/extensions/api/log_private.h"
+
+namespace extensions {
+
+// A parser that parses syslog into LogEntry objects.
+class SyslogParser : public LogParser {
+ public:
+  SyslogParser();
+  virtual ~SyslogParser();
+
+ protected:
+  // Parses one line log text into a LogEntry object.
+  virtual Error ParseEntry(
+      const std::string& input,
+      std::vector<linked_ptr<api::log_private::LogEntry> >* output,
+      FilterHandler* filter_handler) const
+      OVERRIDE;
+
+ private:
+  // Parses time token and get time in milliseconds.
+  Error ParseTime(const std::string& input, double* output) const;
+  // Parses process token and get process name and ID.
+  Error ParseProcess(const std::string& input,
+                     api::log_private::LogEntry* entry) const;
+  // Parses level token and get log level.
+  void ParseLevel(const std::string& input,
+                  api::log_private::LogEntry* entry) const;
+
+  DISALLOW_COPY_AND_ASSIGN(SyslogParser);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_LOG_PRIVATE_SYSLOG_PARSER_H_
diff --git a/chrome/browser/extensions/api/log_private/syslog_parser_unittest.cc b/chrome/browser/extensions/api/log_private/syslog_parser_unittest.cc
new file mode 100644
index 0000000..2c0b8f0
--- /dev/null
+++ b/chrome/browser/extensions/api/log_private/syslog_parser_unittest.cc
@@ -0,0 +1,55 @@
+// 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 <stdio.h>
+#include <string>
+#include <vector>
+
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/api/log_private/filter_handler.h"
+#include "chrome/browser/extensions/api/log_private/log_private_api.h"
+#include "chrome/browser/extensions/api/log_private/syslog_parser.h"
+#include "chrome/common/extensions/api/log_private.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+namespace {
+
+const char kShillLogEntry[] =
+    "2013-07-08T11:28:12.440308-07:00 localhost shill:"
+    "[0708/112812:ERROR:manager.cc(480)] Skipping unload of service";
+
+const char kWpaSupplicantLogEntry[] =
+    "2013-07-08T12:39:07.443100-07:00 localhost wpa_supplicant[894]:"
+    "dbus: Failed to construct signal";
+
+}  // namespace
+
+class ExtensionSyslogParserTest : public testing::Test {
+};
+
+TEST_F(ExtensionSyslogParserTest, ParseLog) {
+  std::vector<linked_ptr<api::log_private::LogEntry> > output;
+  api::log_private::Filter filter;
+  FilterHandler filter_handler(filter);
+  SyslogParser p;
+  // Test shill log
+  p.Parse(kShillLogEntry, &output, &filter_handler);
+  EXPECT_STREQ(output[0]->level.c_str(), "error");
+  EXPECT_STREQ(output[0]->process.c_str(), "shill:");
+  EXPECT_STREQ(output[0]->process_id.c_str(), "unknown");
+  EXPECT_STREQ(output[0]->full_entry.c_str(), kShillLogEntry);
+  EXPECT_EQ(output[0]->timestamp, 1373308092440.308);
+  // Test WpaSupplicant log
+  p.Parse(kWpaSupplicantLogEntry, &output, &filter_handler);
+  EXPECT_STREQ(output[1]->level.c_str(), "unknown");
+  EXPECT_STREQ(output[1]->process.c_str(), "wpa_supplicant");
+  EXPECT_STREQ(output[1]->process_id.c_str(), "894");
+  EXPECT_STREQ(output[1]->full_entry.c_str(), kWpaSupplicantLogEntry);
+  EXPECT_EQ(output[1]->timestamp, 1373312347443.1);
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
index c766c21..6e98160 100644
--- a/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
+++ b/chrome/browser/extensions/api/push_messaging/push_messaging_apitest.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
 
+#include "apps/launcher.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_handler.h"
 #include "chrome/browser/extensions/api/push_messaging/push_messaging_invalidation_mapper.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/invalidation/fake_invalidation_service.h"
 #include "chrome/browser/invalidation/invalidation_service.h"
 #include "chrome/browser/invalidation/invalidation_service_factory.h"
diff --git a/chrome/browser/extensions/api/system_cpu/cpu_info_provider.cc b/chrome/browser/extensions/api/system_cpu/cpu_info_provider.cc
index 6da7357..bdadfbf 100644
--- a/chrome/browser/extensions/api/system_cpu/cpu_info_provider.cc
+++ b/chrome/browser/extensions/api/system_cpu/cpu_info_provider.cc
@@ -11,9 +11,8 @@
 using api::system_cpu::CpuInfo;
 
 // Static member intialization.
-template<>
-base::LazyInstance<scoped_refptr<SystemInfoProvider<CpuInfo> > >
-  SystemInfoProvider<CpuInfo>::provider_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<scoped_refptr<CpuInfoProvider> >
+    CpuInfoProvider::provider_ = LAZY_INSTANCE_INITIALIZER;
 
 CpuInfoProvider::CpuInfoProvider() {}
 
@@ -23,6 +22,12 @@
   return info_;
 }
 
+void CpuInfoProvider::InitializeForTesting(
+    scoped_refptr<CpuInfoProvider> provider) {
+  DCHECK(provider.get() != NULL);
+  provider_.Get() = provider;
+}
+
 bool CpuInfoProvider::QueryInfo() {
   info_.num_of_processors = base::SysInfo::NumberOfProcessors();
   info_.arch_name = base::SysInfo::OperatingSystemArchitecture();
@@ -32,7 +37,9 @@
 
 // static
 CpuInfoProvider* CpuInfoProvider::Get() {
-  return CpuInfoProvider::GetInstance<CpuInfoProvider>();
+  if (provider_.Get().get() == NULL)
+    provider_.Get() = new CpuInfoProvider();
+  return provider_.Get();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_cpu/cpu_info_provider.h b/chrome/browser/extensions/api/system_cpu/cpu_info_provider.h
index 0381cbd..2dafa31 100644
--- a/chrome/browser/extensions/api/system_cpu/cpu_info_provider.h
+++ b/chrome/browser/extensions/api/system_cpu/cpu_info_provider.h
@@ -1,35 +1,48 @@
 // 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_EXTENSIONS_API_SYSTEM_CPU_CPU_INFO_PROVIDER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_CPU_CPU_INFO_PROVIDER_H_
 
+#include "base/lazy_instance.h"
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
 #include "chrome/common/extensions/api/system_cpu.h"
 
 namespace extensions {
 
-class CpuInfoProvider
-    : public SystemInfoProvider<api::system_cpu::CpuInfo> {
+class CpuInfoProvider : public SystemInfoProvider {
  public:
-  // Overriden from SystemInfoProvider<CpuInfo>.
-  virtual bool QueryInfo() OVERRIDE;
-
   // Return the single shared instance of CpuInfoProvider.
   static CpuInfoProvider* Get();
 
   const api::system_cpu::CpuInfo& cpu_info() const;
 
+  static void InitializeForTesting(scoped_refptr<CpuInfoProvider> provider);
+
  private:
-  friend class SystemInfoProvider<api::system_cpu::CpuInfo>;
   friend class MockCpuInfoProviderImpl;
 
   CpuInfoProvider();
-
   virtual ~CpuInfoProvider();
+
+  // Overriden from SystemInfoProvider.
+  virtual bool QueryInfo() OVERRIDE;
+
+  // The last information filled up by QueryInfo and is accessed on multiple
+  // threads, but the whole class is being guarded by SystemInfoProvider base
+  // class.
+  //
+  // |info_| is accessed on the UI thread while |is_waiting_for_completion_| is
+  // false and on the sequenced worker pool while |is_waiting_for_completion_|
+  // is true.
+  api::system_cpu::CpuInfo info_;
+
+  static base::LazyInstance<scoped_refptr<CpuInfoProvider> > provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(CpuInfoProvider);
 };
 
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_CPU_CPU_INFO_PROVIDER_H_
-
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider.cc b/chrome/browser/extensions/api/system_display/display_info_provider.cc
index c97435e..e01bb72 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider.cc
@@ -6,19 +6,31 @@
 
 namespace extensions {
 
+DisplayInfoProvider::DisplayInfoProvider() {
+}
+
+DisplayInfoProvider::~DisplayInfoProvider() {
+}
+
 // Static member intialization.
-template<>
-base::LazyInstance<scoped_refptr<SystemInfoProvider<DisplayInfo> > >
-  SystemInfoProvider<DisplayInfo>::provider_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<scoped_refptr<DisplayInfoProvider > >
+    DisplayInfoProvider::provider_ = LAZY_INSTANCE_INITIALIZER;
 
 const DisplayInfo& DisplayInfoProvider::display_info() const {
   return info_;
 }
 
+void DisplayInfoProvider::InitializeForTesting(
+    scoped_refptr<DisplayInfoProvider> provider) {
+  DCHECK(provider.get() != NULL);
+  provider_.Get() = provider;
+}
+
 // static
-DisplayInfoProvider* DisplayInfoProvider::GetProvider() {
-  return DisplayInfoProvider::GetInstance<DisplayInfoProvider>();
+DisplayInfoProvider* DisplayInfoProvider::Get() {
+  if (provider_.Get().get() == NULL)
+    provider_.Get() = new DisplayInfoProvider();
+  return provider_.Get();
 }
 
 }  // namespace extensions
-
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider.h b/chrome/browser/extensions/api/system_display/display_info_provider.h
index 037b5f1..ac9c654 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider.h
+++ b/chrome/browser/extensions/api/system_display/display_info_provider.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/lazy_instance.h"
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
 #include "chrome/common/extensions/api/system_display.h"
 
@@ -15,7 +16,7 @@
 typedef std::vector<linked_ptr<
     api::system_display::DisplayUnitInfo> > DisplayInfo;
 
-class DisplayInfoProvider : public SystemInfoProvider<DisplayInfo> {
+class DisplayInfoProvider : public SystemInfoProvider {
  public:
   typedef base::Callback<void(bool success)>
       RequestInfoCallback;
@@ -23,7 +24,7 @@
       SetInfoCallback;
 
   // Gets a DisplayInfoProvider instance.
-  static DisplayInfoProvider* GetProvider();
+  static DisplayInfoProvider* Get();
 
   // Starts request for the display info, redirecting the request to a worker
   // thread if needed (using SystemInfoProvider<DisplayInfo>::StartQuery()).
@@ -44,15 +45,27 @@
 
   const DisplayInfo& display_info() const;
 
+  static void InitializeForTesting(scoped_refptr<DisplayInfoProvider> provider);
+
  protected:
-  // Overriden from SystemInfoProvider<DisplayInfo>.
+  DisplayInfoProvider();
+  virtual ~DisplayInfoProvider();
+
+  // The last information filled up by QueryInfo and is accessed on multiple
+  // threads, but the whole class is being guarded by SystemInfoProvider base
+  // class.
+  //
+  // |info_| is accessed on the UI thread while |is_waiting_for_completion_| is
+  // false and on the sequenced worker pool while |is_waiting_for_completion_|
+  // is true.
+  DisplayInfo info_;
+
+ private:
+  // Overriden from SystemInfoProvider.
   // The implementation is platform specific.
   virtual bool QueryInfo() OVERRIDE;
 
-  friend class SystemInfoProvider<DisplayInfo>;
-
-  DisplayInfoProvider() {}
-  virtual ~DisplayInfoProvider() {}
+  static base::LazyInstance<scoped_refptr<DisplayInfoProvider> > provider_;
 
   DISALLOW_COPY_AND_ASSIGN(DisplayInfoProvider);
 };
diff --git a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
index 5960313..e7a68e5 100644
--- a/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/system_display/display_info_provider_chromeos_unittest.cc
@@ -20,7 +20,7 @@
 
 void BindRequestDisplayInfoResult(DisplayInfo* target, bool success) {
   ASSERT_TRUE(success);
-  *target = DisplayInfoProvider::GetProvider()->display_info();
+  *target = DisplayInfoProvider::Get()->display_info();
 }
 
 void BindSetDisplayUnitInfoResult(bool* success,
@@ -39,7 +39,7 @@
 
  protected:
   void CallRequestDisplayInfo(DisplayInfo* result) {
-    DisplayInfoProvider::GetProvider()->RequestInfo(
+    DisplayInfoProvider::Get()->RequestInfo(
         base::Bind(&BindRequestDisplayInfoResult, result));
     RunAllPendingInMessageLoop();
   }
@@ -49,7 +49,7 @@
       const api::system_display::DisplayProperties& info,
       bool* success,
       std::string* error) {
-    DisplayInfoProvider::GetProvider()->SetInfo(display_id, info,
+    DisplayInfoProvider::Get()->SetInfo(display_id, info,
         base::Bind(&BindSetDisplayUnitInfoResult, success, error));
     RunAllPendingInMessageLoop();
   }
diff --git a/chrome/browser/extensions/api/system_display/system_display_api.cc b/chrome/browser/extensions/api/system_display/system_display_api.cc
index 8819a8c..36dd2f2 100644
--- a/chrome/browser/extensions/api/system_display/system_display_api.cc
+++ b/chrome/browser/extensions/api/system_display/system_display_api.cc
@@ -14,7 +14,7 @@
 namespace SetDisplayProperties = api::system_display::SetDisplayProperties;
 
 bool SystemDisplayGetInfoFunction::RunImpl() {
-  DisplayInfoProvider::GetProvider()->RequestInfo(
+  DisplayInfoProvider::Get()->RequestInfo(
       base::Bind(
           &SystemDisplayGetInfoFunction::OnGetDisplayInfoCompleted,
           this));
@@ -25,7 +25,7 @@
     bool success) {
   if (success) {
     results_ = api::system_display::GetInfo::Results::Create(
-                   DisplayInfoProvider::GetProvider()->display_info());
+                   DisplayInfoProvider::Get()->display_info());
   } else {
     SetError("Error occurred when querying display information.");
   }
@@ -44,7 +44,7 @@
 
   scoped_ptr<SetDisplayProperties::Params> params(
       SetDisplayProperties::Params::Create(*args_));
-  DisplayInfoProvider::GetProvider()->SetInfo(params->id, params->info,
+  DisplayInfoProvider::Get()->SetInfo(params->id, params->info,
       base::Bind(
           &SystemDisplaySetDisplayPropertiesFunction::OnPropertiesSet,
           this));
diff --git a/chrome/browser/extensions/api/system_info/system_info_provider.cc b/chrome/browser/extensions/api/system_info/system_info_provider.cc
new file mode 100644
index 0000000..07f233b
--- /dev/null
+++ b/chrome/browser/extensions/api/system_info/system_info_provider.cc
@@ -0,0 +1,65 @@
+// 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/extensions/api/system_info/system_info_provider.h"
+
+namespace extensions {
+
+SystemInfoProvider::SystemInfoProvider()
+    : is_waiting_for_completion_(false) {
+  base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
+  worker_pool_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
+      pool->GetSequenceToken(),
+      base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+}
+
+SystemInfoProvider::~SystemInfoProvider() {}
+
+void SystemInfoProvider::PrepareQueryOnUIThread() {}
+
+void SystemInfoProvider::InitializeProvider(const base::Closure&
+    do_query_info_callback) {
+  do_query_info_callback.Run();
+}
+
+void SystemInfoProvider::StartQueryInfo(
+    const QueryInfoCompletionCallback& callback) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(!callback.is_null());
+
+  callbacks_.push(callback);
+
+  if (is_waiting_for_completion_)
+    return;
+
+  is_waiting_for_completion_ = true;
+
+  InitializeProvider(base::Bind(
+      &SystemInfoProvider::StartQueryInfoPostInitialization, this));
+}
+
+void SystemInfoProvider::OnQueryCompleted(bool success) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  while (!callbacks_.empty()) {
+    QueryInfoCompletionCallback callback = callbacks_.front();
+    callback.Run(success);
+    callbacks_.pop();
+  }
+
+  is_waiting_for_completion_ = false;
+}
+
+void SystemInfoProvider::StartQueryInfoPostInitialization() {
+  PrepareQueryOnUIThread();
+  // Post the custom query info task to blocking pool for information querying
+  // and reply with OnQueryCompleted.
+  base::PostTaskAndReplyWithResult(
+      worker_pool_,
+      FROM_HERE,
+      base::Bind(&SystemInfoProvider::QueryInfo, this),
+      base::Bind(&SystemInfoProvider::OnQueryCompleted, this));
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_info/system_info_provider.h b/chrome/browser/extensions/api/system_info/system_info_provider.h
index 0215820..84dbb80 100644
--- a/chrome/browser/extensions/api/system_info/system_info_provider.h
+++ b/chrome/browser/extensions/api/system_info/system_info_provider.h
@@ -1,6 +1,7 @@
 // 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_EXTENSIONS_API_SYSTEM_INFO_SYSTEM_INFO_PROVIDER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_INFO_SYSTEM_INFO_PROVIDER_H_
 
@@ -8,16 +9,16 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
-#include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace extensions {
 
-// A generic template for all kinds of system information providers. Each kind
-// of SystemInfoProvider is a single shared instance. It is created if needed,
-// and destroyed at exit time. This is done via LazyInstance and scoped_refptr.
+// An abstract base class for all kinds of system information providers. Each
+// kind of SystemInfoProvider is a single shared instance. It is created if
+// needed, and destroyed at exit time. This is done via LazyInstance and
+// scoped_refptr.
 //
 // The SystemInfoProvider is designed to query system information on the worker
 // pool. It also maintains a queue of callbacks on the UI thread which are
@@ -27,18 +28,10 @@
 // of query requests, e.g. calling systemInfo.cpu.get repeatedly in an
 // extension process.
 //
-// Template parameter T is the system information type. It could be the
-// structure type generated by IDL parser.
-//
-// The class member |info_| is accessed on multiple threads, but that the whole
-// class is being guarded by SystemInfoProvider.
-//
-// |info_| is accessed on the UI thread while |is_waiting_for_completion_| is
-// false and on the sequenced worker pool while |is_waiting_for_completion_| is
-// true.
-template<class T>
+// Each kind of SystemInfoProvider should satisfy an API query in a subclass on
+// the blocking pool.
 class SystemInfoProvider
-    : public base::RefCountedThreadSafe<SystemInfoProvider<T> > {
+    : public base::RefCountedThreadSafe<SystemInfoProvider> {
  public:
   // Callback type for completing to get information. The argument indicates
   // whether its contents are valid, for example, no error occurs in querying
@@ -46,38 +39,21 @@
   typedef base::Callback<void(bool)> QueryInfoCompletionCallback;
   typedef std::queue<QueryInfoCompletionCallback> CallbackQueue;
 
-  SystemInfoProvider()
-    : is_waiting_for_completion_(false) {
-    base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
-    worker_pool_ = pool->GetSequencedTaskRunnerWithShutdownBehavior(
-                       pool->GetSequenceToken(),
-                       base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-  }
-
-  virtual ~SystemInfoProvider() {}
+  SystemInfoProvider();
 
   // Override to do any prepare work on UI thread before |QueryInfo()| gets
   // called.
-  virtual void PrepareQueryOnUIThread() {}
+  virtual void PrepareQueryOnUIThread();
 
-  // The parameter |do_query_info_callback| is query info task which is posts to
-  // SystemInfoProvider sequenced worker pool.
+  // The parameter |do_query_info_callback| is query info task which is posted
+  // to SystemInfoProvider sequenced worker pool.
   //
   // You can do any initial things of *InfoProvider before start to query info.
   // While overriding this method, |do_query_info_callback| *must* be called
   // directly or indirectly.
   //
   // Sample usage please refer to StorageInfoProvider.
-  virtual void InitializeProvider(const base::Closure& do_query_info_callback) {
-    do_query_info_callback.Run();
-  }
-
-  // For testing
-  static void InitializeForTesting(
-      scoped_refptr<SystemInfoProvider<T> > provider) {
-    DCHECK(provider.get() != NULL);
-    provider_.Get() = provider;
-  }
+  virtual void InitializeProvider(const base::Closure& do_query_info_callback);
 
   // Start to query the system information. Should be called on UI thread.
   // The |callback| will get called once the query is completed.
@@ -85,70 +61,24 @@
   // If the parameter |callback| itself calls StartQueryInfo(callback2),
   // callback2 will be called immediately rather than triggering another call to
   // the system.
-  void StartQueryInfo(const QueryInfoCompletionCallback& callback) {
-    DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-    DCHECK(!callback.is_null());
-
-    callbacks_.push(callback);
-
-    if (is_waiting_for_completion_)
-      return;
-
-    is_waiting_for_completion_ = true;
-
-    InitializeProvider(base::Bind(
-          &SystemInfoProvider<T>::StartQueryInfoPostInitialization, this));
-  }
+  void StartQueryInfo(const QueryInfoCompletionCallback& callback);
 
  protected:
-  // Query the system information synchronously and put the result into |info_|.
+  virtual ~SystemInfoProvider();
+
+ private:
+  friend class base::RefCountedThreadSafe<SystemInfoProvider>;
+
+  // Interface to query the system information synchronously.
   // Return true if no error occurs.
   // Should be called in the blocking pool.
   virtual bool QueryInfo() = 0;
 
-  // Template function for creating the single shared provider instance.
-  // Template paramter I is the type of SystemInfoProvider implementation.
-  template<class I>
-  static I* GetInstance() {
-    if (!provider_.Get().get())
-      provider_.Get() = new I();
-    return static_cast<I*>(provider_.Get().get());
-  }
-
-  // The latest information filled up by QueryInfo implementation. Here we
-  // assume the T is disallowed to copy constructor, aligns with the structure
-  // type generated by IDL parser.
-  T info_;
-
- private:
   // Called on UI thread. The |success| parameter means whether it succeeds
   // to get the information.
-  void OnQueryCompleted(bool success) {
-    DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  void OnQueryCompleted(bool success);
 
-    while (!callbacks_.empty()) {
-      QueryInfoCompletionCallback callback = callbacks_.front();
-      callback.Run(success);
-      callbacks_.pop();
-    }
-
-    is_waiting_for_completion_ = false;
-  }
-
-  void StartQueryInfoPostInitialization() {
-    PrepareQueryOnUIThread();
-    // Post the custom query info task to blocking pool for information querying
-    // and reply with OnQueryCompleted.
-    base::PostTaskAndReplyWithResult(
-        worker_pool_,
-        FROM_HERE,
-        base::Bind(&SystemInfoProvider<T>::QueryInfo, this),
-        base::Bind(&SystemInfoProvider<T>::OnQueryCompleted, this));
-  }
-
-  // The single shared provider instance. We create it only when needed.
-  static typename base::LazyInstance<
-      scoped_refptr<SystemInfoProvider<T> > > provider_;
+  void StartQueryInfoPostInitialization();
 
   // The queue of callbacks waiting for the info querying completion. It is
   // maintained on the UI thread.
@@ -161,7 +91,7 @@
   // executed in order.
   scoped_refptr<base::SequencedTaskRunner> worker_pool_;
 
-  DISALLOW_COPY_AND_ASSIGN(SystemInfoProvider<T>);
+  DISALLOW_COPY_AND_ASSIGN(SystemInfoProvider);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_memory/memory_info_provider.cc b/chrome/browser/extensions/api/system_memory/memory_info_provider.cc
index 0858183..ae5f7a7 100644
--- a/chrome/browser/extensions/api/system_memory/memory_info_provider.cc
+++ b/chrome/browser/extensions/api/system_memory/memory_info_provider.cc
@@ -11,9 +11,8 @@
 using api::system_memory::MemoryInfo;
 
 // Static member intialization.
-template<>
-base::LazyInstance<scoped_refptr<SystemInfoProvider<MemoryInfo> > >
-  SystemInfoProvider<MemoryInfo>::provider_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<scoped_refptr<MemoryInfoProvider> >
+    MemoryInfoProvider::provider_ = LAZY_INSTANCE_INITIALIZER;
 
 MemoryInfoProvider::MemoryInfoProvider() {}
 
@@ -23,17 +22,24 @@
   return info_;
 }
 
+void MemoryInfoProvider::InitializeForTesting(
+    scoped_refptr<MemoryInfoProvider> provider) {
+  DCHECK(provider.get() != NULL);
+  provider_.Get() = provider;
+}
+
 bool MemoryInfoProvider::QueryInfo() {
   info_.capacity = static_cast<double>(base::SysInfo::AmountOfPhysicalMemory());
   info_.available_capacity =
-     static_cast<double>(base::SysInfo::AmountOfAvailablePhysicalMemory());
+      static_cast<double>(base::SysInfo::AmountOfAvailablePhysicalMemory());
   return true;
 }
 
 // static
 MemoryInfoProvider* MemoryInfoProvider::Get() {
-  return MemoryInfoProvider::GetInstance<MemoryInfoProvider>();
+  if (provider_.Get().get() == NULL)
+    provider_.Get() = new MemoryInfoProvider();
+  return provider_.Get();
 }
 
 }  // namespace extensions
-
diff --git a/chrome/browser/extensions/api/system_memory/memory_info_provider.h b/chrome/browser/extensions/api/system_memory/memory_info_provider.h
index 54d0449..f83dd79 100644
--- a/chrome/browser/extensions/api/system_memory/memory_info_provider.h
+++ b/chrome/browser/extensions/api/system_memory/memory_info_provider.h
@@ -5,32 +5,43 @@
 #ifndef CHROME_BROWSER_EXTENSIONS_API_SYSTEM_MEMORY_MEMORY_INFO_PROVIDER_H_
 #define CHROME_BROWSER_EXTENSIONS_API_SYSTEM_MEMORY_MEMORY_INFO_PROVIDER_H_
 
+#include "base/lazy_instance.h"
 #include "chrome/browser/extensions/api/system_info/system_info_provider.h"
 #include "chrome/common/extensions/api/system_memory.h"
 
 namespace extensions {
 
-class MemoryInfoProvider
-    : public SystemInfoProvider<api::system_memory::MemoryInfo> {
+class MemoryInfoProvider : public SystemInfoProvider {
  public:
   static MemoryInfoProvider* Get();
 
-  // Overriden from SystemInfoProvider<MemoryInfo>.
-  virtual bool QueryInfo() OVERRIDE;
-
   const api::system_memory::MemoryInfo& memory_info() const;
 
+  static void InitializeForTesting(scoped_refptr<MemoryInfoProvider> provider);
+
  private:
-  friend class SystemInfoProvider<api::system_memory::MemoryInfo>;
   friend class MockMemoryInfoProviderImpl;
 
   MemoryInfoProvider();
   virtual ~MemoryInfoProvider();
 
+  // Overriden from SystemInfoProvider.
+  virtual bool QueryInfo() OVERRIDE;
+
+  // The last information filled up by QueryInfo and is accessed on multiple
+  // threads, but the whole class is being guarded by SystemInfoProvider base
+  // class.
+  //
+  // |info_| is accessed on the UI thread while |is_waiting_for_completion_| is
+  // false and on the sequenced worker pool while |is_waiting_for_completion_|
+  // is true.
+  api::system_memory::MemoryInfo info_;
+
+  static base::LazyInstance<scoped_refptr<MemoryInfoProvider> > provider_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryInfoProvider);
 };
 
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_SYSTEM_MEMORY_MEMORY_INFO_PROVIDER_H_
-
diff --git a/chrome/browser/extensions/api/system_storage/storage_info_provider.cc b/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
index 0138893..2f1b874 100644
--- a/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
+++ b/chrome/browser/extensions/api/system_storage/storage_info_provider.cc
@@ -38,10 +38,8 @@
 const char kWatchingTokenName[] = "_storage_info_watching_token_";
 
 // Static member intialization.
-template<>
-base::LazyInstance<scoped_refptr<SystemInfoProvider<StorageUnitInfoList> > >
-  SystemInfoProvider<StorageUnitInfoList>::provider_
-      = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<scoped_refptr<StorageInfoProvider> >
+    StorageInfoProvider::provider_ = LAZY_INSTANCE_INITIALIZER;
 
 StorageInfoProvider::StorageInfoProvider()
     : observers_(new ObserverListThreadSafe<StorageFreeSpaceObserver>()),
@@ -60,6 +58,12 @@
   return info_;
 }
 
+void StorageInfoProvider::InitializeForTesting(
+    scoped_refptr<StorageInfoProvider> provider) {
+  DCHECK(provider.get() != NULL);
+  provider_.Get() = provider;
+}
+
 void StorageInfoProvider::PrepareQueryOnUIThread() {
   // Get all available storage devices before invoking |QueryInfo()|.
   GetAllStoragesIntoInfoList();
@@ -150,7 +154,7 @@
        it != storage_list.end(); ++it) {
     if (device_id == it->device_id())
       return base::SysInfo::AmountOfFreeDiskSpace(
-                 base::FilePath(it->location()));
+          base::FilePath(it->location()));
   }
 
   return -1;
@@ -260,7 +264,9 @@
 
 // static
 StorageInfoProvider* StorageInfoProvider::Get() {
-  return StorageInfoProvider::GetInstance<StorageInfoProvider>();
+  if (provider_.Get().get() == NULL)
+    provider_.Get() = new StorageInfoProvider();
+  return provider_.Get();
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/system_storage/storage_info_provider.h b/chrome/browser/extensions/api/system_storage/storage_info_provider.h
index 33c8c67..2dc96f5 100644
--- a/chrome/browser/extensions/api/system_storage/storage_info_provider.h
+++ b/chrome/browser/extensions/api/system_storage/storage_info_provider.h
@@ -7,6 +7,7 @@
 
 #include <set>
 
+#include "base/lazy_instance.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list_threadsafe.h"
 #include "base/timer/timer.h"
@@ -33,12 +34,8 @@
     api::system_storage::StorageUnitInfo> >
         StorageUnitInfoList;
 
-class StorageInfoProvider : public SystemInfoProvider<StorageUnitInfoList> {
+class StorageInfoProvider : public SystemInfoProvider {
  public:
-  StorageInfoProvider();
-
-  explicit StorageInfoProvider(size_t watching_interval);
-
   // Get the single shared instance of StorageInfoProvider.
   static StorageInfoProvider* Get();
 
@@ -65,12 +62,26 @@
 
   const StorageUnitInfoList& storage_unit_info_list() const;
 
+  static void InitializeForTesting(scoped_refptr<StorageInfoProvider> provider);
+
  protected:
+  StorageInfoProvider();
+  explicit StorageInfoProvider(size_t watching_interval);
+
   virtual ~StorageInfoProvider();
 
   // Put all available storages' information into |info_|.
   void GetAllStoragesIntoInfoList();
 
+  // The last information filled up by QueryInfo and is accessed on multiple
+  // threads, but the whole class is being guarded by SystemInfoProvider base
+  // class.
+  //
+  // |info_| is accessed on the UI thread while |is_waiting_for_completion_| is
+  // false and on the sequenced worker pool while |is_waiting_for_completion_|
+  // is true.
+  StorageUnitInfoList info_;
+
  private:
   typedef std::map<std::string, double> StorageTransientIdToSizeMap;
 
@@ -114,6 +125,10 @@
   // The time interval for watching the free space change, in milliseconds.
   // Only changed for testing purposes.
   size_t watching_interval_;
+
+  static base::LazyInstance<scoped_refptr<StorageInfoProvider> > provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(StorageInfoProvider);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
index be4a079..490abfd 100644
--- a/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
+++ b/chrome/browser/extensions/api/tab_capture/tab_capture_apitest.cc
@@ -146,7 +146,7 @@
 }
 
 // http://crbug.com/177163
-#if defined(OS_WIN) && !defined(NDEBUG)
+#if defined(OS_WIN)
 #define MAYBE_ActiveTabPermission DISABLED_ActiveTabPermission
 #else
 #define MAYBE_ActiveTabPermission ActiveTabPermission
diff --git a/chrome/browser/extensions/api/usb/OWNERS b/chrome/browser/extensions/api/usb/OWNERS
new file mode 100644
index 0000000..2adeca5
--- /dev/null
+++ b/chrome/browser/extensions/api/usb/OWNERS
@@ -0,0 +1,3 @@
+# USB API members. For core API change, check with owners in
+# chrome/browser/extensions/OWNERS
+ikarienator@chromium.org
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index ab5ffc5..3408bd6 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -587,6 +587,7 @@
   RECOVERYPRIVATE_CANCELWRITE,
   RECOVERYPRIVATE_DESTROYPARTITIONS,
   FEEDBACKPRIVATE_GETSTRINGS,
+  LOGPRIVATE_GETHISTORICAL,
   ENUM_BOUNDARY // Last entry: Add new entries above.
 };
 
diff --git a/chrome/browser/extensions/extension_install_ui_browsertest.cc b/chrome/browser/extensions/extension_install_ui_browsertest.cc
index 4687be3..f38878b 100644
--- a/chrome/browser/extensions/extension_install_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_install_ui_browsertest.cc
@@ -50,12 +50,8 @@
   // Install the given theme from the data dir and verify expected name.
   void InstallThemeAndVerify(const char* theme_name,
                              const std::string& expected_name) {
-    // If there is already a theme installed, the current theme should be
-    // disabled and the new one installed + enabled.
-    int expected_change = GetTheme() ? 0 : 1;
     const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_name);
-    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, expected_change,
-        browser()));
+    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_path, 1, browser()));
     const Extension* theme = GetTheme();
     ASSERT_TRUE(theme);
     ASSERT_EQ(theme->name(), expected_name);
@@ -92,7 +88,7 @@
   ASSERT_EQ(NULL, GetTheme());
 
   // Set the same theme twice and undo to verify we go back to default theme.
-  ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 0, browser()));
+  ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(theme_crx, 1, browser()));
   theme = GetTheme();
   ASSERT_TRUE(theme);
   ASSERT_EQ(theme_id, theme->id());
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 87d18e9..4deba6c 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -59,13 +59,14 @@
 #include "chrome/browser/extensions/management_policy.h"
 #include "chrome/browser/extensions/pending_extension_manager.h"
 #include "chrome/browser/extensions/permissions_updater.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/extensions/update_observer.h"
 #include "chrome/browser/extensions/updater/extension_updater.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/webui/favicon_source.h"
 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
 #include "chrome/browser/ui/webui/theme_source.h"
@@ -1143,6 +1144,16 @@
       content::Source<Profile>(profile_),
       content::Details<UnloadedExtensionInfo>(&details));
 
+#if defined(ENABLE_THEMES)
+  // If the current theme is being unloaded, tell ThemeService to revert back
+  // to the default theme.
+  if (reason != extension_misc::UNLOAD_REASON_UPDATE && extension->is_theme()) {
+    ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
+    if (extension->id() == theme_service->GetThemeID())
+      theme_service->UseDefaultTheme();
+  }
+#endif
+
   for (content::RenderProcessHost::iterator i(
           content::RenderProcessHost::AllHostsIterator());
        !i.IsAtEnd(); i.Advance()) {
@@ -1972,6 +1983,15 @@
               extension_paths))) {
     NOTREACHED();
   }
+
+#if defined(ENABLE_THEMES)
+  // Also garbage-collect themes.  We check |profile_| to be
+  // defensive; in the future, we may call GarbageCollectExtensions()
+  // from somewhere other than Init() (e.g., in a timer).
+  if (profile_) {
+    ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
+  }
+#endif
 }
 
 void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
@@ -2356,11 +2376,6 @@
                    << extensions::ManifestURL::GetUpdateURL(extension).spec()
                    << "; not installing";
 
-      content::NotificationService::current()->Notify(
-          chrome::NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED,
-          content::Source<Profile>(profile_),
-          content::Details<const Extension>(extension));
-
       // Delete the extension directory since we're not going to
       // load it.
       if (!GetFileTaskRunner()->PostTask(
@@ -2563,6 +2578,20 @@
 
   AddExtension(extension);
 
+#if defined(ENABLE_THEMES)
+  // We do this here since AddExtension() is always called on browser startup,
+  // and we only really care about the last theme installed.
+  // If that ever changes and we have to move this code somewhere
+  // else, it should be somewhere that's not in the startup path.
+  if (extension->is_theme() && extensions_.GetByID(extension->id())) {
+    DCHECK_EQ(extensions_.GetByID(extension->id()), extension);
+    // Now that the theme extension is visible from outside the
+    // ExtensionService, notify the ThemeService about the
+    // newly-installed theme.
+    ThemeServiceFactory::GetForProfile(profile_)->SetTheme(extension);
+  }
+#endif
+
   // If this is a new external extension that was disabled, alert the user
   // so he can reenable it. We do this last so that it has already been
   // added to our list of extensions.
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 18a5652..bf6c949 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -837,9 +837,7 @@
         EXPECT_EQ(0u, loaded_.size()) << path.value();
       } else {
         EXPECT_EQ(1u, loaded_.size()) << path.value();
-        size_t actual_extension_count = service_->extensions()->size() +
-            service_->disabled_extensions()->size();
-        EXPECT_EQ(expected_extensions_count_, actual_extension_count) <<
+        EXPECT_EQ(expected_extensions_count_, service_->extensions()->size()) <<
             path.value();
         extension = loaded_[0].get();
         EXPECT_TRUE(service_->GetExtensionById(extension->id(), false))
@@ -2359,7 +2357,6 @@
 
 TEST_F(ExtensionServiceTest, InstallTheme) {
   InitializeEmptyExtensionService();
-  service_->Init();
 
   // A theme.
   base::FilePath path = data_dir_.AppendASCII("theme.crx");
@@ -2401,8 +2398,6 @@
 TEST_F(ExtensionServiceTest, LoadLocalizedTheme) {
   // Load.
   InitializeEmptyExtensionService();
-  service_->Init();
-
   base::FilePath extension_path = data_dir_
       .AppendASCII("theme_i18n");
 
@@ -2503,8 +2498,6 @@
 
 TEST_F(ExtensionServiceTest, InstallLocalizedTheme) {
   InitializeEmptyExtensionService();
-  service_->Init();
-
   base::FilePath theme_path = data_dir_
       .AppendASCII("theme_i18n");
 
diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc
index a58a259..1f124a8 100644
--- a/chrome/browser/extensions/platform_app_browsertest.cc
+++ b/chrome/browser/extensions/platform_app_browsertest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "apps/launcher.h"
 #include "apps/native_app_window.h"
 #include "apps/shell_window.h"
 #include "base/bind.h"
@@ -27,7 +28,6 @@
 #include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/extensions/extension_test_message_listener.h"
 #include "chrome/browser/extensions/platform_app_browsertest_util.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/extensions/shell_window_registry.h"
 #include "chrome/browser/tab_contents/render_view_context_menu.h"
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/extensions/updater/OWNERS b/chrome/browser/extensions/updater/OWNERS
index 7f60b89..f433f3f 100644
--- a/chrome/browser/extensions/updater/OWNERS
+++ b/chrome/browser/extensions/updater/OWNERS
@@ -1,2 +1,3 @@
 asargent@chromium.org
 joaodasilva@chromium.org
+mek@chromium.org
diff --git a/chrome/browser/first_run/first_run.cc b/chrome/browser/first_run/first_run.cc
index 70fe2a6..e7a6fcc 100644
--- a/chrome/browser/first_run/first_run.cc
+++ b/chrome/browser/first_run/first_run.cc
@@ -393,7 +393,7 @@
               SigninTracker::GetSigninState(profile, NULL) !=
                   SigninTracker::SIGNIN_COMPLETE);
       bool is_promo_bubble_visible =
-          profile->GetPrefs()->GetBoolean(prefs::kSyncPromoShowNTPBubble);
+          profile->GetPrefs()->GetBoolean(prefs::kSignInPromoShowNTPBubble);
 
       if (is_promo_bubble_visible || signin_in_progress)
         return;
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index 511f083..d096e43 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -816,6 +816,10 @@
 #if defined(OS_ANDROID) || defined(OS_IOS)
   registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
   registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
+  registry->RegisterListPref(
+      prefs::kDailyHttpReceivedContentLengthViaDataReductionProxy);
+  registry->RegisterListPref(
+      prefs::kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled);
   registry->RegisterInt64Pref(prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
 #endif
   registry->RegisterBooleanPref(prefs::kBuiltInDnsClientEnabled, true);
diff --git a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc
index 5c5a1a6..4cd6258 100644
--- a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.cc
@@ -7,9 +7,7 @@
 #include "base/callback.h"
 #include "base/json/json_reader.h"
 #include "base/logging.h"
-#include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -40,7 +38,6 @@
     "&scope=%s"
     "&response_type=code"
     "&profile_id=%s"
-    "&profile_name=%s"
     "&device_name=%s";
 
 static const char kAuthorizationHeaderFormat[] =
@@ -60,7 +57,6 @@
 
   // ManagedUserRefreshTokenFetcher implementation:
   virtual void Start(const std::string& managed_user_id,
-                     const string16& name,
                      const std::string& device_name,
                      const TokenCallback& callback) OVERRIDE;
 
@@ -97,7 +93,6 @@
 
   std::string device_name_;
   std::string managed_user_id_;
-  string16 name_;
   TokenCallback callback_;
 
   scoped_ptr<OAuth2TokenService::Request> access_token_request_;
@@ -118,12 +113,10 @@
 
 void ManagedUserRefreshTokenFetcherImpl::Start(
     const std::string& managed_user_id,
-    const string16& name,
     const std::string& device_name,
     const TokenCallback& callback) {
   DCHECK(callback_.is_null());
   managed_user_id_ = managed_user_id;
-  name_ = name;
   device_name_ = device_name;
   callback_ = callback;
   StartFetching();
@@ -162,7 +155,6 @@
           GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
       net::EscapeUrlEncodedData(kChromeSyncManagedOAuth2Scope, true).c_str(),
       net::EscapeUrlEncodedData(managed_user_id_, true).c_str(),
-      net::EscapeUrlEncodedData(UTF16ToUTF8(name_), true).c_str(),
       net::EscapeUrlEncodedData(device_name_, true).c_str());
   url_fetcher_->SetUploadData("application/x-www-form-urlencoded", body);
 
diff --git a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h
index e29cdbe..c671a72 100644
--- a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h
@@ -42,7 +42,6 @@
   virtual ~ManagedUserRefreshTokenFetcher();
 
   virtual void Start(const std::string& managed_user_id,
-                     const string16& name,
                      const std::string& device_name,
                      const TokenCallback& callback) = 0;
 };
diff --git a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
index c547599..75608a6 100644
--- a/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_refresh_token_fetcher_unittest.cc
@@ -5,7 +5,6 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
 #include "chrome/browser/signin/oauth2_token_service.h"
 #include "chrome/test/base/testing_profile.h"
@@ -24,7 +23,6 @@
 namespace {
 
 const char kManagedUserId[] = "abcdef";
-const char kName[] = "Homestar";
 const char kDeviceName[] = "Compy";
 
 const char kAccessToken[] = "accesstoken";
@@ -213,7 +211,7 @@
       weak_ptr_factory_(this) {}
 
 void ManagedUserRefreshTokenFetcherTest::StartFetching() {
-  token_fetcher_->Start(kManagedUserId, UTF8ToUTF16(kName), kDeviceName,
+  token_fetcher_->Start(kManagedUserId, kDeviceName,
                         base::Bind(
                             &ManagedUserRefreshTokenFetcherTest::OnTokenFetched,
                             weak_ptr_factory_.GetWeakPtr()));
@@ -246,9 +244,6 @@
   std::string managed_user_id;
   EXPECT_TRUE(GetValueForKey(upload_data, "profile_id", &managed_user_id));
   EXPECT_EQ(kManagedUserId, managed_user_id);
-  std::string name;
-  EXPECT_TRUE(GetValueForKey(upload_data, "profile_name", &name));
-  EXPECT_EQ(kName, name);
   std::string device_name;
   EXPECT_TRUE(GetValueForKey(upload_data, "device_name", &device_name));
   EXPECT_EQ(kDeviceName, device_name);
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility.cc b/chrome/browser/managed_mode/managed_user_registration_utility.cc
index d782fce..6a46a33 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_utility.cc
@@ -94,7 +94,7 @@
 
   browser_sync::DeviceInfo::GetClientName(
       base::Bind(&ManagedUserRegistrationUtility::FetchToken,
-                 weak_ptr_factory_.GetWeakPtr(), info.name));
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void ManagedUserRegistrationUtility::CancelPendingRegistration() {
@@ -118,10 +118,9 @@
 }
 
 void ManagedUserRegistrationUtility::FetchToken(
-    const string16& name,
     const std::string& client_name) {
   token_fetcher_->Start(
-      pending_managed_user_id_, name, client_name,
+      pending_managed_user_id_, client_name,
       base::Bind(&ManagedUserRegistrationUtility::OnReceivedToken,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility.h b/chrome/browser/managed_mode/managed_user_registration_utility.h
index 368cc1e..5e6fe52 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility.h
+++ b/chrome/browser/managed_mode/managed_user_registration_utility.h
@@ -87,8 +87,7 @@
       scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher,
       ManagedUserSyncService* service);
   // Fetches the managed user token when we have the device name.
-  void FetchToken(const string16& name,
-                  const std::string& client_name);
+  void FetchToken(const std::string& client_name);
 
   // Called when we have received a token for the managed user.
   void OnReceivedToken(const GoogleServiceAuthError& error,
diff --git a/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc b/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
index 76962a9..5bb75de 100644
--- a/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
+++ b/chrome/browser/managed_mode/managed_user_registration_utility_unittest.cc
@@ -68,7 +68,6 @@
 
   // ManagedUserRefreshTokenFetcher implementation:
   virtual void Start(const std::string& managed_user_id,
-                     const string16& name,
                      const std::string& device_name,
                      const TokenCallback& callback) OVERRIDE {
     GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index bbef40f..03ca4c5 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -35,6 +35,10 @@
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 
+#if defined(USE_CRAS)
+#include "media/audio/cras/audio_manager_cras.h"
+#endif
+
 using content::BrowserThread;
 using content::MediaStreamDevices;
 
@@ -193,22 +197,34 @@
     const content::MediaStreamRequest& request,
     const content::MediaResponseCallback& callback,
     const extensions::Extension* extension) {
-  bool component_extension =
+  const bool component_extension =
     extension && extension->location() == extensions::Manifest::COMPONENT;
 
   content::MediaStreamDevices devices;
 
-  bool screen_capture_enabled =
+  const bool screen_capture_enabled =
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableUserMediaScreenCapturing) ||
       IsOriginWhitelistedForScreenCapture(request.security_origin);
 
-  bool origin_is_secure =
+  const bool origin_is_secure =
       request.security_origin.SchemeIsSecure() ||
       request.security_origin.SchemeIs(extensions::kExtensionScheme) ||
       CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kAllowHttpScreenCapture);
 
+  const bool screen_video_capture_requested =
+      request.video_type == content::MEDIA_SCREEN_VIDEO_CAPTURE;
+
+  const bool system_audio_capture_requested =
+      request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE;
+
+#if defined(USE_CRAS)
+  const bool system_audio_capture_supported = true;
+#else
+  const bool system_audio_capture_supported = false;
+#endif
+
   // Approve request only when the following conditions are met:
   //  1. Screen capturing is enabled via command line switch or white-listed for
   //     the given origin.
@@ -216,9 +232,8 @@
   //  3. Video capture is requested for screen video.
   //  4. Audio capture is either not requested, or requested for system audio.
   if (screen_capture_enabled && origin_is_secure &&
-      request.video_type == content::MEDIA_SCREEN_VIDEO_CAPTURE &&
-      (request.audio_type == content::MEDIA_NO_SERVICE ||
-       request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE)) {
+      screen_video_capture_requested &&
+      (!system_audio_capture_requested || system_audio_capture_supported)) {
     // For component extensions, bypass message box.
     bool user_approved = false;
     if (!component_extension) {
@@ -240,9 +255,14 @@
     if (user_approved || component_extension) {
       devices.push_back(content::MediaStreamDevice(
           content::MEDIA_SCREEN_VIDEO_CAPTURE, std::string(), "Screen"));
-      if (request.audio_type == content::MEDIA_SYSTEM_AUDIO_CAPTURE) {
+      if (system_audio_capture_requested) {
+#if defined(USE_CRAS)
+        // Use the special loopback device ID for system audio capture.
         devices.push_back(content::MediaStreamDevice(
-            content::MEDIA_SYSTEM_AUDIO_CAPTURE, std::string(), std::string()));
+            content::MEDIA_SYSTEM_AUDIO_CAPTURE,
+            media::AudioManagerCras::kLoopbackDeviceId,
+            "System Audio"));
+#endif
       }
     }
   }
diff --git a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
new file mode 100644
index 0000000..a6c71e0
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.cc
@@ -0,0 +1,81 @@
+// 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/media_galleries/fileapi/av_scanning_file_validator.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shlobj.h>
+#endif
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
+#include "content/public/browser/browser_thread.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_comptr.h"
+#endif
+
+using content::BrowserThread;
+
+namespace chrome {
+
+namespace {
+
+#if defined(OS_WIN)
+base::PlatformFileError ScanFile(
+    const base::FilePath& dest_platform_path) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+
+  base::win::ScopedComPtr<IAttachmentExecute> attachment_services;
+  HRESULT hr = attachment_services.CreateInstance(CLSID_AttachmentServices);
+
+  if (FAILED(hr)) {
+    // The thread must have COM initialized.
+    DCHECK_NE(CO_E_NOTINITIALIZED, hr);
+    return base::PLATFORM_FILE_ERROR_SECURITY;
+  }
+
+  hr = attachment_services->SetLocalPath(dest_platform_path.value().c_str());
+  if (FAILED(hr))
+    return base::PLATFORM_FILE_ERROR_SECURITY;
+
+  // A failure in the Save() call below could result in the downloaded file
+  // being deleted.
+  HRESULT scan_result = attachment_services->Save();
+  if (scan_result == S_OK)
+    return base::PLATFORM_FILE_OK;
+
+  return base::PLATFORM_FILE_ERROR_SECURITY;
+}
+#endif
+
+}  // namespace
+
+AVScanningFileValidator::~AVScanningFileValidator() {}
+
+void AVScanningFileValidator::StartPostWriteValidation(
+    const base::FilePath& dest_platform_path,
+    const ResultCallback& result_callback) {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+#if defined(OS_WIN)
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE,
+      FROM_HERE,
+      base::Bind(&ScanFile, dest_platform_path),
+      result_callback);
+#else
+  result_callback.Run(base::PLATFORM_FILE_OK);
+#endif
+}
+
+AVScanningFileValidator::AVScanningFileValidator() {
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.h b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.h
new file mode 100644
index 0000000..d06c857
--- /dev/null
+++ b/chrome/browser/media_galleries/fileapi/av_scanning_file_validator.h
@@ -0,0 +1,37 @@
+// 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_MEDIA_GALLERIES_FILEAPI_AV_SCANNING_FILE_VALIDATOR_H_
+#define CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_AV_SCANNING_FILE_VALIDATOR_H_
+
+#include "base/basictypes.h"
+#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+
+namespace base {
+class FilePath;
+}  // namespace base
+
+namespace chrome {
+
+// This class supports AV scanning on post write validation.
+class AVScanningFileValidator : public fileapi::CopyOrMoveFileValidator {
+ public:
+  virtual ~AVScanningFileValidator();
+
+  // Runs AV checks on the resulting file (Windows-only).
+  // Subclasses will not typically override this method.
+  virtual void StartPostWriteValidation(
+      const base::FilePath& dest_platform_path,
+      const ResultCallback& result_callback) OVERRIDE;
+
+ protected:
+  AVScanningFileValidator();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AVScanningFileValidator);
+};
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_MEDIA_GALLERIES_FILEAPI_AV_SCANNING_FILE_VALIDATOR_H_
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
index 24f749b..5677b01 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.cc
@@ -8,7 +8,6 @@
 #include "base/file_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
@@ -29,12 +28,10 @@
 const char kDeviceMediaAsyncFileUtilTempDir[] = "DeviceMediaFileSystem";
 
 // Called on the IO thread.
-MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(
-    FileSystemOperationContext* context) {
+MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(const FileSystemURL& url) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   return MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(
-      context->GetUserValue<std::string>(
-          MediaFileSystemBackend::kMTPDeviceDelegateURLKey));
+      url.filesystem_id());
 }
 
 // Called on a blocking pool thread to create a snapshot file to hold the
@@ -109,7 +106,7 @@
     const FileSystemURL& url,
     const GetFileInfoCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context.get());
+  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
   if (!delegate) {
     OnGetFileInfoError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
     return;
@@ -129,7 +126,7 @@
     const FileSystemURL& url,
     const ReadDirectoryCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context.get());
+  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
   if (!delegate) {
     OnReadDirectoryError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
     return;
@@ -226,7 +223,7 @@
     const FileSystemURL& url,
     const CreateSnapshotFileCallback& callback) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
-  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context.get());
+  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
   if (!delegate) {
     OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
     return;
@@ -243,7 +240,7 @@
                      weak_ptr_factory_.GetWeakPtr(),
                      base::Passed(&context),
                      callback,
-                     url.path(),
+                     url,
                      base::Owned(snapshot_file_path)));
   DCHECK(success);
 }
@@ -319,20 +316,20 @@
 void DeviceMediaAsyncFileUtil::OnSnapshotFileCreatedRunTask(
     scoped_ptr<FileSystemOperationContext> context,
     const AsyncFileUtil::CreateSnapshotFileCallback& callback,
-    const base::FilePath& device_file_path,
+    const FileSystemURL& url,
     base::FilePath* snapshot_file_path) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
   if (!snapshot_file_path || snapshot_file_path->empty()) {
     OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_FAILED);
     return;
   }
-  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(context.get());
+  MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
   if (!delegate) {
     OnCreateSnapshotFileError(callback, base::PLATFORM_FILE_ERROR_NOT_FOUND);
     return;
   }
   delegate->CreateSnapshotFile(
-      device_file_path,
+      url.path(),  // device file path
       *snapshot_file_path,
       base::Bind(&DeviceMediaAsyncFileUtil::OnDidCreateSnapshotFile,
                  weak_ptr_factory_.GetWeakPtr(),
diff --git a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
index cb4c6a8..3cea78a 100644
--- a/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/device_media_async_file_util.h
@@ -165,15 +165,15 @@
       base::PlatformFileError error);
 
   // Called when the snapshot file specified by the |snapshot_file_path| is
-  // created to hold the contents of the |device_file_path|. If the snapshot
+  // created to hold the contents of the url.path(). If the snapshot
   // file is successfully created, |snapshot_file_path| will be an non-empty
   // file path. In case of failure, |snapshot_file_path| will be an empty file
   // path. Forwards the CreateSnapshot request to the delegate to copy the
-  // contents of |device_file_path| to |snapshot_file_path|.
+  // contents of url.path() to |snapshot_file_path|.
   void OnSnapshotFileCreatedRunTask(
       scoped_ptr<fileapi::FileSystemOperationContext> context,
       const AsyncFileUtil::CreateSnapshotFileCallback& callback,
-      const base::FilePath& device_file_path,
+      const fileapi::FileSystemURL& url,
       base::FilePath* snapshot_file_path);
 
   // Profile path.
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
index 88c32a1..641b382 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
@@ -12,7 +12,6 @@
 #include "base/file_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/media_galleries/fileapi/itunes_data_provider.h"
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "chrome/browser/media_galleries/imported_media_gallery_registry.h"
 #include "content/public/browser/browser_thread.h"
@@ -42,9 +41,10 @@
 
 }  // namespace
 
-ItunesFileUtil::ItunesFileUtil()
-    : weak_factory_(this),
-      imported_registry_(NULL)  {
+ItunesFileUtil::ItunesFileUtil(chrome::MediaPathFilter* media_path_filter)
+    : chrome::NativeMediaFileUtil(media_path_filter),
+      weak_factory_(this),
+      imported_registry_(NULL) {
 }
 
 ItunesFileUtil::~ItunesFileUtil() {
@@ -195,13 +195,10 @@
         GetDataProvider()->GetAlbum(components[1], components[2]);
     if (album.size() == 0)
       return base::PLATFORM_FILE_ERROR_NOT_FOUND;
-    chrome::MediaPathFilter* path_filter =
-        context->GetUserValue<chrome::MediaPathFilter*>(
-            chrome::MediaFileSystemBackend::kMediaPathFilterKey);
     ITunesDataProvider::Album::const_iterator it;
     for (it = album.begin(); it != album.end(); ++it) {
       base::PlatformFileInfo file_info;
-      if (path_filter->Match(it->second) &&
+      if (media_path_filter()->Match(it->second) &&
           file_util::GetFileInfo(it->second, &file_info)) {
         file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
                                             file_info.size,
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.h b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
index d87bb51..3aa75f1 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.h
@@ -19,7 +19,7 @@
 
 class ItunesFileUtil : public chrome::NativeMediaFileUtil {
  public:
-  ItunesFileUtil();
+  explicit ItunesFileUtil(chrome::MediaPathFilter* media_path_filter);
   virtual ~ItunesFileUtil();
 
  protected:
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
index d1907cc..cf0bc26 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.cc
@@ -44,10 +44,6 @@
 
 const char MediaFileSystemBackend::kMediaTaskRunnerName[] =
     "media-task-runner";
-const char MediaFileSystemBackend::kMediaPathFilterKey[] =
-    "MediaPathFilterKey";
-const char MediaFileSystemBackend::kMTPDeviceDelegateURLKey[] =
-    "MTPDeviceDelegateKey";
 
 MediaFileSystemBackend::MediaFileSystemBackend(
     const base::FilePath& profile_path,
@@ -56,13 +52,14 @@
       media_task_runner_(media_task_runner),
       media_path_filter_(new MediaPathFilter),
       media_copy_or_move_file_validator_factory_(new MediaFileValidatorFactory),
-      native_media_file_util_(new NativeMediaFileUtil()),
+      native_media_file_util_(
+          new NativeMediaFileUtil(media_path_filter_.get())),
       device_media_async_file_util_(
           DeviceMediaAsyncFileUtil::Create(profile_path_))
 #if defined(OS_WIN) || defined(OS_MACOSX)
       ,
-      picasa_file_util_(new picasa::PicasaFileUtil()),
-      itunes_file_util_(new itunes::ItunesFileUtil())
+      picasa_file_util_(new picasa::PicasaFileUtil(media_path_filter_.get())),
+      itunes_file_util_(new itunes::ItunesFileUtil(media_path_filter_.get()))
 #endif  // defined(OS_WIN) || defined(OS_MACOSX)
 {
 }
@@ -172,14 +169,6 @@
   scoped_ptr<fileapi::FileSystemOperationContext> operation_context(
       new fileapi::FileSystemOperationContext(
           context, media_task_runner_.get()));
-
-  operation_context->SetUserValue(kMediaPathFilterKey,
-                                  media_path_filter_.get());
-  if (url.type() == fileapi::kFileSystemTypeDeviceMedia) {
-    operation_context->SetUserValue(kMTPDeviceDelegateURLKey,
-                                    url.filesystem_id());
-  }
-
   return new fileapi::FileSystemOperationImpl(url, context,
                                               operation_context.Pass());
 }
diff --git a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
index e1763a8..c3b989b 100644
--- a/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
+++ b/chrome/browser/media_galleries/fileapi/media_file_system_backend.h
@@ -26,8 +26,6 @@
 class MediaFileSystemBackend : public fileapi::FileSystemBackend {
  public:
   static const char kMediaTaskRunnerName[];
-  static const char kMediaPathFilterKey[];
-  static const char kMTPDeviceDelegateURLKey[];
 
   MediaFileSystemBackend(
       const base::FilePath& profile_path,
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
index a9b922a..3b73e34 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -13,7 +13,6 @@
 #include "base/files/scoped_platform_file_closer.h"
 #include "base/strings/string_util.h"
 #include "base/task_runner_util.h"
-#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/fileapi/media_path_filter.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/mime_sniffer.h"
@@ -76,15 +75,11 @@
   return context->task_runner()->RunsTasksOnCurrentThread();
 }
 
-MediaPathFilter* GetMediaPathFilter(
-    fileapi::FileSystemOperationContext* context) {
-  return context->GetUserValue<MediaPathFilter*>(
-          MediaFileSystemBackend::kMediaPathFilterKey);
-}
-
 }  // namespace
 
-NativeMediaFileUtil::NativeMediaFileUtil() : weak_factory_(this) {
+NativeMediaFileUtil::NativeMediaFileUtil(MediaPathFilter* media_path_filter)
+    : weak_factory_(this),
+      media_path_filter_(media_path_filter) {
 }
 
 NativeMediaFileUtil::~NativeMediaFileUtil() {
@@ -440,7 +435,7 @@
     return error;
   if (error == base::PLATFORM_FILE_OK && file_info.is_directory)
     return base::PLATFORM_FILE_ERROR_INVALID_OPERATION;
-  if (!GetMediaPathFilter(context)->Match(dest_file_path))
+  if (!media_path_filter_->Match(dest_file_path))
     return base::PLATFORM_FILE_ERROR_SECURITY;
 
   return fileapi::NativeFileUtil::CopyOrMoveFile(src_file_path, dest_file_path,
@@ -472,7 +467,6 @@
   DCHECK(context);
   DCHECK(IsOnTaskRunnerThread(context));
   DCHECK(file_info);
-  DCHECK(GetMediaPathFilter(context));
 
   base::FilePath file_path;
   base::PlatformFileError error = GetLocalFilePath(context, url, &file_path);
@@ -487,7 +481,7 @@
   if (platform_path)
     *platform_path = file_path;
   if (file_info->is_directory ||
-      GetMediaPathFilter(context)->Match(file_path)) {
+      media_path_filter_->Match(file_path)) {
     return base::PLATFORM_FILE_OK;
   }
   return base::PLATFORM_FILE_ERROR_NOT_FOUND;
@@ -541,7 +535,7 @@
     // NativeMediaFileUtil skip criteria.
     if (ShouldSkip(enum_path))
       continue;
-    if (!info.IsDirectory() && !GetMediaPathFilter(context)->Match(enum_path))
+    if (!info.IsDirectory() && !media_path_filter_->Match(enum_path))
       continue;
 
     fileapi::DirectoryEntry entry;
@@ -597,7 +591,7 @@
       GetLocalFilePath(context, file_system_url, &file_path);
   if (error != base::PLATFORM_FILE_OK)
     return error;
-  if (!GetMediaPathFilter(context)->Match(file_path))
+  if (!media_path_filter_->Match(file_path))
     return base::PLATFORM_FILE_ERROR_SECURITY;
 
   *local_file_path = file_path;
@@ -624,7 +618,7 @@
     return base::PLATFORM_FILE_ERROR_FAILED;
 
   if (!file_info.is_directory &&
-      !GetMediaPathFilter(context)->Match(file_path)) {
+      !media_path_filter_->Match(file_path)) {
     return failure_error;
   }
 
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.h b/chrome/browser/media_galleries/fileapi/native_media_file_util.h
index 29de6e6..a797e14 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.h
@@ -11,12 +11,14 @@
 
 namespace chrome {
 
+class MediaPathFilter;
+
 // This class handles native file system operations with media type filtering.
 // To support virtual file systems it implements the AsyncFileUtil interface
 // from scratch and provides synchronous override points.
 class NativeMediaFileUtil : public fileapi::AsyncFileUtil {
  public:
-  NativeMediaFileUtil();
+  explicit NativeMediaFileUtil(MediaPathFilter* media_path_filter);
   virtual ~NativeMediaFileUtil();
 
   // Uses the MIME sniffer code, which actually looks into the file,
@@ -169,6 +171,11 @@
       base::FilePath* platform_path,
       scoped_refptr<webkit_blob::ShareableFileReference>* file_ref);
 
+ protected:
+  chrome::MediaPathFilter* media_path_filter() {
+    return media_path_filter_;
+  }
+
  private:
   // Like GetLocalFilePath(), but always take media_path_filter() into
   // consideration. If the media_path_filter() check fails, return
@@ -193,6 +200,9 @@
 
   base::WeakPtrFactory<NativeMediaFileUtil> weak_factory_;
 
+  // Not owned, owned by the backend which owns this.
+  chrome::MediaPathFilter* media_path_filter_;
+
   DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtil);
 };
 
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc
index d15cb78..fa7bb7a 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.cc
@@ -53,8 +53,9 @@
 const char kPicasaDirAlbums[]  = "albums";
 const char kPicasaDirFolders[] = "folders";
 
-PicasaFileUtil::PicasaFileUtil()
-    : weak_factory_(this) {
+PicasaFileUtil::PicasaFileUtil(chrome::MediaPathFilter* media_path_filter)
+    : chrome::NativeMediaFileUtil(media_path_filter),
+      weak_factory_(this) {
 }
 
 PicasaFileUtil::~PicasaFileUtil() {}
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h
index f17cb66..69d7c06 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util.h
@@ -18,7 +18,7 @@
 
 class PicasaFileUtil : public chrome::NativeMediaFileUtil {
  public:
-  PicasaFileUtil();
+  explicit PicasaFileUtil(chrome::MediaPathFilter* media_path_filter);
   virtual ~PicasaFileUtil();
 
  protected:
diff --git a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc
index 978b0dc..cd19e3b 100644
--- a/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa/picasa_file_util_unittest.cc
@@ -178,8 +178,10 @@
 
 class TestPicasaFileUtil : public PicasaFileUtil {
  public:
-  explicit TestPicasaFileUtil(PicasaDataProvider* data_provider)
-      : data_provider_(data_provider) {
+  TestPicasaFileUtil(chrome::MediaPathFilter* media_path_filter,
+                     PicasaDataProvider* data_provider)
+      : PicasaFileUtil(media_path_filter),
+        data_provider_(data_provider) {
   }
   virtual ~TestPicasaFileUtil() {}
  private:
@@ -225,12 +227,14 @@
     scoped_refptr<quota::SpecialStoragePolicy> storage_policy =
         new quota::MockSpecialStoragePolicy();
 
+    media_path_filter_.reset(new chrome::MediaPathFilter());
     picasa_data_provider_.reset(new TestPicasaDataProvider());
 
     ScopedVector<fileapi::FileSystemBackend> additional_providers;
     additional_providers.push_back(new TestMediaFileSystemBackend(
         profile_dir_.path(),
-        new TestPicasaFileUtil(picasa_data_provider_.get())));
+        new TestPicasaFileUtil(media_path_filter_.get(),
+                               picasa_data_provider_.get())));
 
     file_system_context_ = new fileapi::FileSystemContext(
         base::MessageLoopProxy::current().get(),
@@ -333,6 +337,7 @@
   base::ScopedTempDir profile_dir_;
 
   scoped_refptr<fileapi::FileSystemContext> file_system_context_;
+  scoped_ptr<chrome::MediaPathFilter> media_path_filter_;
   scoped_ptr<TestPicasaDataProvider> picasa_data_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(PicasaFileUtilTest);
diff --git a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
index 9ae7625..24a400b 100644
--- a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
@@ -116,19 +116,6 @@
                  weak_factory_.GetWeakPtr()));
 }
 
-void SupportedImageTypeValidator::StartPostWriteValidation(
-    const base::FilePath& dest_platform_path,
-    const ResultCallback& result_callback) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
-  post_write_callback_ = result_callback;
-
-  // TODO(gbillock): Insert AV call here in the right validator.
-  BrowserThread::PostTask(
-      BrowserThread::IO,
-      FROM_HERE,
-      base::Bind(post_write_callback_, base::PLATFORM_FILE_OK));
-}
-
 SupportedImageTypeValidator::SupportedImageTypeValidator(
     const base::FilePath& path)
     : path_(path),
diff --git a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.h b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.h
index c74d762..11e479f 100644
--- a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.h
+++ b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.h
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
-#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
+#include "chrome/browser/media_galleries/fileapi/av_scanning_file_validator.h"
 
 class ImageDecoder;
 
@@ -19,7 +19,7 @@
 
 // Use ImageDecoder to determine if the file decodes without error. Handles
 // image files supported by Chrome.
-class SupportedImageTypeValidator : public fileapi::CopyOrMoveFileValidator {
+class SupportedImageTypeValidator : public AVScanningFileValidator {
  public:
   virtual ~SupportedImageTypeValidator();
 
@@ -28,10 +28,6 @@
   virtual void StartPreWriteValidation(
       const ResultCallback& result_callback) OVERRIDE;
 
-  virtual void StartPostWriteValidation(
-      const base::FilePath& dest_platform_path,
-      const ResultCallback& result_callback) OVERRIDE;
-
  private:
   friend class MediaFileValidatorFactory;
 
@@ -42,7 +38,6 @@
   base::FilePath path_;
   scoped_refptr<ImageDecoder> decoder_;
   fileapi::CopyOrMoveFileValidator::ResultCallback callback_;
-  fileapi::CopyOrMoveFileValidator::ResultCallback post_write_callback_;
   base::WeakPtrFactory<SupportedImageTypeValidator> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SupportedImageTypeValidator);
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.cc b/chrome/browser/nacl_host/nacl_host_message_filter.cc
index 5980d72..c7c7935 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.cc
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.cc
@@ -186,9 +186,9 @@
                  pp_instance));
 }
 
-void NaClHostMessageFilter::OnTranslationFinished(int instance) {
+void NaClHostMessageFilter::OnTranslationFinished(int instance, bool success) {
   PnaclHost::GetInstance()->TranslationFinished(
-      render_process_id_, instance);
+      render_process_id_, instance, success);
 }
 
 void NaClHostMessageFilter::OnNaClErrorStatus(int render_view_id,
diff --git a/chrome/browser/nacl_host/nacl_host_message_filter.h b/chrome/browser/nacl_host/nacl_host_message_filter.h
index dccdf08..7d31a90 100644
--- a/chrome/browser/nacl_host/nacl_host_message_filter.h
+++ b/chrome/browser/nacl_host/nacl_host_message_filter.h
@@ -59,7 +59,7 @@
   void OnGetNexeFd(int render_view_id,
                    int pp_instance,
                    const nacl::PnaclCacheInfo& cache_info);
-  void OnTranslationFinished(int instance);
+  void OnTranslationFinished(int instance, bool success);
   void OnNaClErrorStatus(int render_view_id, int error_id);
   void OnOpenNaClExecutable(int render_view_id,
                             const GURL& file_url,
diff --git a/chrome/browser/nacl_host/pnacl_host.cc b/chrome/browser/nacl_host/pnacl_host.cc
index 6eb3ea0..9bb5b72 100644
--- a/chrome/browser/nacl_host/pnacl_host.cc
+++ b/chrome/browser/nacl_host/pnacl_host.cc
@@ -180,7 +180,9 @@
 
 /////////////////// Cleanup
 
-void PnaclHost::TranslationFinished(int render_process_id, int pp_instance) {
+void PnaclHost::TranslationFinished(int render_process_id,
+                                    int pp_instance,
+                                    bool success) {
   DCHECK(thread_checker_.CalledOnValidThread());
   if (cache_state_ != CacheReady)
     return;
diff --git a/chrome/browser/nacl_host/pnacl_host.h b/chrome/browser/nacl_host/pnacl_host.h
index e449ce2..2093b44 100644
--- a/chrome/browser/nacl_host/pnacl_host.h
+++ b/chrome/browser/nacl_host/pnacl_host.h
@@ -63,9 +63,11 @@
                  const NexeFdCallback& cb);
 
   // Called after the translation of a pexe instance identified by
-  // |render_process_id| and |pp_instance| finishes. Store the nexe translated
-  // for the instance in the cache.
-  void TranslationFinished(int render_process_id, int pp_instance);
+  // |render_process_id| and |pp_instance| finishes. If |success| is true,
+  // store the nexe translated for the instance in the cache.
+  void TranslationFinished(int render_process_id,
+                           int pp_instance,
+                           bool success);
 
   // Called when the renderer identified by |render_process_id| is closing.
   // Clean up any outstanding translations for that renderer.
diff --git a/chrome/browser/nacl_host/pnacl_host_unittest.cc b/chrome/browser/nacl_host/pnacl_host_unittest.cc
index 7796aa6..cb5e8ef 100644
--- a/chrome/browser/nacl_host/pnacl_host_unittest.cc
+++ b/chrome/browser/nacl_host/pnacl_host_unittest.cc
@@ -73,7 +73,7 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_PENDING_TRANSLATIONS(1);
   ExpectCallbackCount(1);
-  host_->TranslationFinished(0, 0);
+  host_->TranslationFinished(0, 0, true);
   EXPECT_PENDING_TRANSLATIONS(0);
   host_->RendererClosing(0);
 }
@@ -89,7 +89,7 @@
       base::Bind(&PnaclHostTest::CallbackExpectMiss, base::Unretained(this)));
 
   EXPECT_PENDING_TRANSLATIONS(1);
-  host_->TranslationFinished(0, 1);  // nonexistent translation
+  host_->TranslationFinished(0, 1, true);  // nonexistent translation
   EXPECT_PENDING_TRANSLATIONS(1);
   host_->RendererClosing(1);  // nonexistent renderer
   EXPECT_PENDING_TRANSLATIONS(1);
diff --git a/chrome/browser/net/chrome_network_delegate.cc b/chrome/browser/net/chrome_network_delegate.cc
index 6697181..76c09db 100644
--- a/chrome/browser/net/chrome_network_delegate.cc
+++ b/chrome/browser/net/chrome_network_delegate.cc
@@ -212,12 +212,12 @@
   }
 }
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
 // Increments an int64, stored as a string, in a ListPref at the specified
 // index.  The value must already exist and be a string representation of a
 // number.
 void AddInt64ToListPref(size_t index, int64 length,
-                        ListPrefUpdate& list_update) {
+                        base::ListValue* list_update) {
   int64 value = 0;
   std::string old_string_value;
   bool rv = list_update->GetString(index, &old_string_value);
@@ -229,10 +229,67 @@
   value += length;
   list_update->Set(index, Value::CreateStringValue(base::Int64ToString(value)));
 }
-#endif  // defined(OS_ANDROID)
+
+int64 ListPrefInt64Value(const base::ListValue& list_update, size_t index) {
+  std::string string_value;
+  if (!list_update.GetString(index, &string_value))
+    return 0;
+
+  int64 value = 0;
+  bool rv = base::StringToInt64(string_value, &value);
+  DCHECK(rv);
+  return value;
+}
+
+void RecordDailyContentLengthHistograms(
+    int64 original_length,
+    int64 received_length,
+    int64 length_with_data_reduction_enabled,
+    int64 length_via_data_reduction_proxy) {
+  // Record metrics in KB.
+  UMA_HISTOGRAM_COUNTS(
+      "Net.DailyHttpOriginalContentLength", original_length >> 10);
+  UMA_HISTOGRAM_COUNTS(
+      "Net.DailyHttpReceivedContentLength", received_length >> 10);
+  UMA_HISTOGRAM_COUNTS(
+      "Net.DailyHttpContentLengthWithDataReductionProxyEnabled",
+      length_with_data_reduction_enabled >> 10);
+  UMA_HISTOGRAM_COUNTS(
+      "Net.DailyHttpContentLengthViaDataReductionProxy",
+      length_via_data_reduction_proxy >> 10);
+
+  if (original_length > 0 && received_length > 0) {
+    int percent = (100 * (original_length - received_length)) / original_length;
+    // UMA percentage cannot be negative.
+    if (percent < 0)
+      percent = 0;
+    UMA_HISTOGRAM_PERCENTAGE("Net.DailyHttpContentSavings", percent);
+    // If the data reduction proxy is enabled for some responses.
+    if (length_with_data_reduction_enabled > 0) {
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Net.DailyHttpContentSavings_DataReductionProxy", percent);
+    }
+  }
+  if (received_length > 0 && length_with_data_reduction_enabled >= 0) {
+    DCHECK_GE(received_length, length_with_data_reduction_enabled);
+    UMA_HISTOGRAM_PERCENTAGE(
+        "Net.DailyReceivedContentWithDataReductionProxyEnabled",
+        (100 * length_with_data_reduction_enabled) / received_length);
+  }
+  if (received_length > 0 &&
+      length_via_data_reduction_proxy >= 0) {
+    DCHECK_GE(received_length, length_via_data_reduction_proxy);
+    UMA_HISTOGRAM_PERCENTAGE(
+        "Net.DailyReceivedContentViaDataReductionProxy",
+        (100 * length_via_data_reduction_proxy) / received_length);
+  }
+}
+
+#endif  // defined(OS_ANDROID) || defined(OS_IOS)
 
 void UpdateContentLengthPrefs(int received_content_length,
-                              int original_content_length) {
+                              int original_content_length,
+                              bool data_reduction_proxy_was_used) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   DCHECK_GE(received_content_length, 0);
   DCHECK_GE(original_content_length, 0);
@@ -252,7 +309,7 @@
   prefs->SetInt64(prefs::kHttpReceivedContentLength, total_received);
   prefs->SetInt64(prefs::kHttpOriginalContentLength, total_original);
 
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
   base::Time now = base::Time::Now().LocalMidnight();
   const size_t kNumDaysInHistory = 60;
 
@@ -263,6 +320,11 @@
   // |kNumDaysInHistory| days are maintained.
   ListPrefUpdate original_update(prefs, prefs::kDailyHttpOriginalContentLength);
   ListPrefUpdate received_update(prefs, prefs::kDailyHttpReceivedContentLength);
+  ListPrefUpdate data_reduction_enabled_update(
+      prefs,
+      prefs::kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled);
+  ListPrefUpdate via_data_reduction_update(
+      prefs, prefs::kDailyHttpReceivedContentLengthViaDataReductionProxy);
 
   // Determine how many days it has been since the last update.
   int64 then_internal = prefs->GetInt64(
@@ -282,23 +344,47 @@
       // values.
       original_update->Remove(kNumDaysInHistory - 1, NULL);
       received_update->Remove(kNumDaysInHistory - 1, NULL);
+      data_reduction_enabled_update->Remove(kNumDaysInHistory - 1, NULL);
+      via_data_reduction_update->Remove(kNumDaysInHistory - 1, NULL);
       original_update->Insert(0, new StringValue(base::Int64ToString(0)));
       received_update->Insert(0, new StringValue(base::Int64ToString(0)));
+      data_reduction_enabled_update->Insert(
+          0, new StringValue(base::Int64ToString(0)));
+      via_data_reduction_update->Insert(
+          0, new StringValue(base::Int64ToString(0)));
       days_since_last_update = 0;
 
     } else if (days_since_last_update < -1) {
       // Erase all entries if the system went backwards in time by more than
       // a day.
       original_update->Clear();
+      received_update->Clear();
+      data_reduction_enabled_update->Clear();
+      via_data_reduction_update->Clear();
       days_since_last_update = kNumDaysInHistory;
     }
 
+    // A new day. Report the previous day's data if exists. We'll lose usage
+    // data if Chrome isn't run for a day. Here, we prefer collecting less data
+    // but the collected data are associated with an accurate date.
+    if (days_since_last_update == 1) {
+      RecordDailyContentLengthHistograms(
+          ListPrefInt64Value(*original_update, original_update->GetSize() - 1),
+          ListPrefInt64Value(*received_update, received_update->GetSize() - 1),
+          ListPrefInt64Value(*data_reduction_enabled_update,
+                             data_reduction_enabled_update->GetSize() - 1),
+          ListPrefInt64Value(*via_data_reduction_update,
+                             via_data_reduction_update->GetSize() - 1));
+    }
+
     // Add entries for days since last update.
     for (int i = 0;
          i < days_since_last_update && i < static_cast<int>(kNumDaysInHistory);
          ++i) {
       original_update->AppendString(base::Int64ToString(0));
       received_update->AppendString(base::Int64ToString(0));
+      data_reduction_enabled_update->AppendString(base::Int64ToString(0));
+      via_data_reduction_update->AppendString(base::Int64ToString(0));
     }
 
     // Maintain the invariant that there should never be more than
@@ -307,30 +393,51 @@
       original_update->Remove(0, NULL);
     while (received_update->GetSize() > kNumDaysInHistory)
       received_update->Remove(0, NULL);
+    while (data_reduction_enabled_update->GetSize() > kNumDaysInHistory)
+      data_reduction_enabled_update->Remove(0, NULL);
+    while (via_data_reduction_update->GetSize() > kNumDaysInHistory)
+      via_data_reduction_update->Remove(0, NULL);
   }
+
   DCHECK_EQ(kNumDaysInHistory, original_update->GetSize());
   DCHECK_EQ(kNumDaysInHistory, received_update->GetSize());
+  DCHECK_EQ(kNumDaysInHistory, data_reduction_enabled_update->GetSize());
+  DCHECK_EQ(kNumDaysInHistory, via_data_reduction_update->GetSize());
 
   // Update the counts for the current day.
   AddInt64ToListPref(kNumDaysInHistory - 1,
-                     original_content_length, original_update);
+                     original_content_length, original_update.Get());
   AddInt64ToListPref(kNumDaysInHistory - 1,
-                     received_content_length, received_update);
+                     received_content_length, received_update.Get());
+
+  if (g_browser_process->profile_manager()->GetDefaultProfile()->
+          GetPrefs()->GetBoolean(prefs::kSpdyProxyAuthEnabled)) {
+    AddInt64ToListPref(kNumDaysInHistory - 1,
+                       received_content_length,
+                       data_reduction_enabled_update.Get());
+  }
+  if (data_reduction_proxy_was_used) {
+    AddInt64ToListPref(kNumDaysInHistory - 1,
+                       received_content_length,
+                       via_data_reduction_update.Get());
+  }
 #endif
 }
 
 void StoreAccumulatedContentLength(int received_content_length,
-                                   int original_content_length) {
+                                   int original_content_length,
+                                   bool data_reduction_proxy_was_used) {
   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
       base::Bind(&UpdateContentLengthPrefs,
-                 received_content_length, original_content_length));
+                 received_content_length, original_content_length,
+                 data_reduction_proxy_was_used));
 }
 
 void RecordContentLengthHistograms(
     int64 received_content_length,
     int64 original_content_length,
     const base::TimeDelta& freshness_lifetime) {
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
   // Add the current resource to these histograms only when a valid
   // X-Original-Content-Length header is present.
   if (original_content_length >= 0) {
@@ -581,6 +688,10 @@
       int64 original_content_length =
           request->response_info().headers->GetInt64HeaderValue(
               "x-original-content-length");
+      bool data_reduction_proxy_was_used =
+          request->response_info().headers->HasHeaderValue(
+              "via", "1.1 Chrome Compression Proxy");
+
       // Since there was no indication of the original content length, presume
       // it is no different from the number of bytes read.
       int64 adjusted_original_content_length = original_content_length;
@@ -590,7 +701,8 @@
           request->response_info().headers->GetFreshnessLifetime(
               request->response_info().response_time);
       AccumulateContentLength(received_content_length,
-                              adjusted_original_content_length);
+                              adjusted_original_content_length,
+                              data_reduction_proxy_was_used);
       RecordContentLengthHistograms(received_content_length,
                                     original_content_length,
                                     freshness_lifetime);
@@ -798,11 +910,13 @@
 }
 
 void ChromeNetworkDelegate::AccumulateContentLength(
-    int64 received_content_length, int64 original_content_length) {
+    int64 received_content_length, int64 original_content_length,
+    bool data_reduction_proxy_was_used) {
   DCHECK_GE(received_content_length, 0);
   DCHECK_GE(original_content_length, 0);
   StoreAccumulatedContentLength(received_content_length,
-                                original_content_length);
+                                original_content_length,
+                                data_reduction_proxy_was_used);
   received_content_length_ += received_content_length;
   original_content_length_ += original_content_length;
 }
diff --git a/chrome/browser/net/chrome_network_delegate.h b/chrome/browser/net/chrome_network_delegate.h
index 25a79ec..e9bf978 100644
--- a/chrome/browser/net/chrome_network_delegate.h
+++ b/chrome/browser/net/chrome_network_delegate.h
@@ -167,7 +167,8 @@
                                         RequestWaitState state) OVERRIDE;
 
   void AccumulateContentLength(
-      int64 received_payload_byte_count, int64 original_payload_byte_count);
+      int64 received_payload_byte_count, int64 original_payload_byte_count,
+      bool data_reduction_proxy_was_used);
 
   scoped_refptr<extensions::EventRouterForwarder> event_router_;
   void* profile_;
diff --git a/chrome/browser/net/sqlite_server_bound_cert_store.cc b/chrome/browser/net/sqlite_server_bound_cert_store.cc
index 8432267..337fe4e 100644
--- a/chrome/browser/net/sqlite_server_bound_cert_store.cc
+++ b/chrome/browser/net/sqlite_server_bound_cert_store.cc
@@ -247,13 +247,16 @@
   }
 
   while (smt.Step()) {
+    net::SSLClientCertType type =
+        static_cast<net::SSLClientCertType>(smt.ColumnInt(3));
+    if (type != net::CLIENT_CERT_ECDSA_SIGN)
+      continue;
     std::string private_key_from_db, cert_from_db;
     smt.ColumnBlobAsString(1, &private_key_from_db);
     smt.ColumnBlobAsString(2, &cert_from_db);
     scoped_ptr<net::DefaultServerBoundCertStore::ServerBoundCert> cert(
         new net::DefaultServerBoundCertStore::ServerBoundCert(
             smt.ColumnString(0),  // origin
-            static_cast<net::SSLClientCertType>(smt.ColumnInt(3)),
             base::Time::FromInternalValue(smt.ColumnInt64(5)),
             base::Time::FromInternalValue(smt.ColumnInt64(4)),
             private_key_from_db,
@@ -296,8 +299,9 @@
                    << "version 2.";
       return false;
     }
-    // All certs in version 1 database are rsa_sign, which has a value of 1.
-    if (!db_->Execute("UPDATE origin_bound_certs SET cert_type = 1")) {
+    // All certs in version 1 database are rsa_sign, which are unsupported.
+    // Just discard them all.
+    if (!db_->Execute("DELETE from origin_bound_certs")) {
       LOG(WARNING) << "Unable to update server bound cert database to "
                    << "version 2.";
       return false;
@@ -518,7 +522,7 @@
         add_smt.BindBlob(1, private_key.data(), private_key.size());
         const std::string& cert = po->cert().cert();
         add_smt.BindBlob(2, cert.data(), cert.size());
-        add_smt.BindInt(3, po->cert().type());
+        add_smt.BindInt(3, net::CLIENT_CERT_ECDSA_SIGN);
         add_smt.BindInt64(4, po->cert().expiration_time().ToInternalValue());
         add_smt.BindInt64(5, po->cert().creation_time().ToInternalValue());
         if (!add_smt.Run())
diff --git a/chrome/browser/net/sqlite_server_bound_cert_store_unittest.cc b/chrome/browser/net/sqlite_server_bound_cert_store_unittest.cc
index e475e58..686138a 100644
--- a/chrome/browser/net/sqlite_server_bound_cert_store_unittest.cc
+++ b/chrome/browser/net/sqlite_server_bound_cert_store_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/test_data_directory.h"
+#include "net/ssl/ssl_client_cert_type.h"
 #include "net/test/cert_test_util.h"
 #include "sql/statement.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -89,7 +90,6 @@
     store_->AddServerBoundCert(
         net::DefaultServerBoundCertStore::ServerBoundCert(
             "google.com",
-            net::CLIENT_CERT_RSA_SIGN,
             base::Time::FromInternalValue(1),
             base::Time::FromInternalValue(2),
             "a", "b"));
@@ -106,7 +106,6 @@
   store_->AddServerBoundCert(
       net::DefaultServerBoundCertStore::ServerBoundCert(
           "foo.com",
-          net::CLIENT_CERT_ECDSA_SIGN,
           base::Time::FromInternalValue(3),
           base::Time::FromInternalValue(4),
           "c", "d"));
@@ -124,27 +123,25 @@
   // Reload and test for persistence
   Load(&certs);
   ASSERT_EQ(2U, certs.size());
-  net::DefaultServerBoundCertStore::ServerBoundCert* ec_cert;
-  net::DefaultServerBoundCertStore::ServerBoundCert* rsa_cert;
-  if (net::CLIENT_CERT_RSA_SIGN == certs[0]->type()) {
-    rsa_cert = certs[0];
-    ec_cert = certs[1];
+  net::DefaultServerBoundCertStore::ServerBoundCert* goog_cert;
+  net::DefaultServerBoundCertStore::ServerBoundCert* foo_cert;
+  if (certs[0]->server_identifier() == "google.com") {
+    goog_cert = certs[0];
+    foo_cert = certs[1];
   } else {
-    rsa_cert = certs[1];
-    ec_cert = certs[0];
+    goog_cert = certs[1];
+    foo_cert = certs[0];
   }
-  ASSERT_STREQ("google.com", rsa_cert->server_identifier().c_str());
-  ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, rsa_cert->type());
-  ASSERT_STREQ("a", rsa_cert->private_key().c_str());
-  ASSERT_STREQ("b", rsa_cert->cert().c_str());
-  ASSERT_EQ(1, rsa_cert->creation_time().ToInternalValue());
-  ASSERT_EQ(2, rsa_cert->expiration_time().ToInternalValue());
-  ASSERT_STREQ("foo.com", ec_cert->server_identifier().c_str());
-  ASSERT_EQ(net::CLIENT_CERT_ECDSA_SIGN, ec_cert->type());
-  ASSERT_STREQ("c", ec_cert->private_key().c_str());
-  ASSERT_STREQ("d", ec_cert->cert().c_str());
-  ASSERT_EQ(3, ec_cert->creation_time().ToInternalValue());
-  ASSERT_EQ(4, ec_cert->expiration_time().ToInternalValue());
+  ASSERT_EQ("google.com", goog_cert->server_identifier());
+  ASSERT_STREQ("a", goog_cert->private_key().c_str());
+  ASSERT_STREQ("b", goog_cert->cert().c_str());
+  ASSERT_EQ(1, goog_cert->creation_time().ToInternalValue());
+  ASSERT_EQ(2, goog_cert->expiration_time().ToInternalValue());
+  ASSERT_EQ("foo.com", foo_cert->server_identifier());
+  ASSERT_STREQ("c", foo_cert->private_key().c_str());
+  ASSERT_STREQ("d", foo_cert->cert().c_str());
+  ASSERT_EQ(3, foo_cert->creation_time().ToInternalValue());
+  ASSERT_EQ(4, foo_cert->expiration_time().ToInternalValue());
 
   // Now delete the cert and check persistence again.
   store_->DeleteServerBoundCert(*certs[0]);
@@ -207,23 +204,10 @@
     ScopedVector<net::DefaultServerBoundCertStore::ServerBoundCert> certs;
     store_ = new SQLiteServerBoundCertStore(v1_db_path, NULL);
 
-    // Load the database and ensure the certs can be read and are marked as RSA.
+    // Load the database. Because the existing v1 certs are implicitly of type
+    // RSA, which is unsupported, they're discarded.
     Load(&certs);
-    ASSERT_EQ(2U, certs.size());
-
-    ASSERT_STREQ("google.com", certs[0]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
-    ASSERT_EQ(GetTestCertExpirationTime(),
-              certs[0]->expiration_time());
-    ASSERT_EQ(key_data, certs[0]->private_key());
-    ASSERT_EQ(cert_data, certs[0]->cert());
-
-    ASSERT_STREQ("foo.com", certs[1]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[1]->type());
-    // Undecodable cert, expiration time will be uninitialized.
-    ASSERT_EQ(base::Time(), certs[1]->expiration_time());
-    ASSERT_STREQ("\xaa", certs[1]->private_key().c_str());
-    ASSERT_STREQ("\xbb", certs[1]->cert().c_str());
+    ASSERT_EQ(0U, certs.size());
 
     store_ = NULL;
     base::RunLoop().RunUntilIdle();
@@ -273,7 +257,7 @@
     add_smt.BindString(0, "google.com");
     add_smt.BindBlob(1, key_data.data(), key_data.size());
     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
-    add_smt.BindInt64(3, 1);
+    add_smt.BindInt64(3, 64);
     ASSERT_TRUE(add_smt.Run());
 
     ASSERT_TRUE(db.Execute(
@@ -291,19 +275,17 @@
     ScopedVector<net::DefaultServerBoundCertStore::ServerBoundCert> certs;
     store_ = new SQLiteServerBoundCertStore(v2_db_path, NULL);
 
-    // Load the database and ensure the certs can be read and are marked as RSA.
+    // Load the database and ensure the certs can be read.
     Load(&certs);
     ASSERT_EQ(2U, certs.size());
 
-    ASSERT_STREQ("google.com", certs[0]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
+    ASSERT_EQ("google.com", certs[0]->server_identifier());
     ASSERT_EQ(GetTestCertExpirationTime(),
               certs[0]->expiration_time());
     ASSERT_EQ(key_data, certs[0]->private_key());
     ASSERT_EQ(cert_data, certs[0]->cert());
 
-    ASSERT_STREQ("foo.com", certs[1]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_ECDSA_SIGN, certs[1]->type());
+    ASSERT_EQ("foo.com", certs[1]->server_identifier());
     // Undecodable cert, expiration time will be uninitialized.
     ASSERT_EQ(base::Time(), certs[1]->expiration_time());
     ASSERT_STREQ("\xaa", certs[1]->private_key().c_str());
@@ -359,7 +341,7 @@
     add_smt.BindString(0, "google.com");
     add_smt.BindBlob(1, key_data.data(), key_data.size());
     add_smt.BindBlob(2, cert_data.data(), cert_data.size());
-    add_smt.BindInt64(3, 1);
+    add_smt.BindInt64(3, 64);
     add_smt.BindInt64(4, 1000);
     ASSERT_TRUE(add_smt.Run());
 
@@ -378,20 +360,18 @@
     ScopedVector<net::DefaultServerBoundCertStore::ServerBoundCert> certs;
     store_ = new SQLiteServerBoundCertStore(v3_db_path, NULL);
 
-    // Load the database and ensure the certs can be read and are marked as RSA.
+    // Load the database and ensure the certs can be read.
     Load(&certs);
     ASSERT_EQ(2U, certs.size());
 
-    ASSERT_STREQ("google.com", certs[0]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_RSA_SIGN, certs[0]->type());
+    ASSERT_EQ("google.com", certs[0]->server_identifier());
     ASSERT_EQ(1000, certs[0]->expiration_time().ToInternalValue());
     ASSERT_EQ(GetTestCertCreationTime(),
               certs[0]->creation_time());
     ASSERT_EQ(key_data, certs[0]->private_key());
     ASSERT_EQ(cert_data, certs[0]->cert());
 
-    ASSERT_STREQ("foo.com", certs[1]->server_identifier().c_str());
-    ASSERT_EQ(net::CLIENT_CERT_ECDSA_SIGN, certs[1]->type());
+    ASSERT_EQ("foo.com", certs[1]->server_identifier());
     ASSERT_EQ(2000, certs[1]->expiration_time().ToInternalValue());
     // Undecodable cert, creation time will be uninitialized.
     ASSERT_EQ(base::Time(), certs[1]->creation_time());
@@ -414,3 +394,76 @@
     }
   }
 }
+
+TEST_F(SQLiteServerBoundCertStoreTest, TestRSADiscarded) {
+  // Reset the store.  We'll be using a different database for this test.
+  store_ = NULL;
+
+  base::FilePath v4_db_path(temp_dir_.path().AppendASCII("v4dbrsa"));
+
+  std::string key_data;
+  std::string cert_data;
+  ReadTestKeyAndCert(&key_data, &cert_data);
+
+  // Create a version 4 database with a mix of RSA and ECDSA certs.
+  {
+    sql::Connection db;
+    ASSERT_TRUE(db.Open(v4_db_path));
+    ASSERT_TRUE(db.Execute(
+        "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
+            "value LONGVARCHAR);"
+        "INSERT INTO \"meta\" VALUES('version','4');"
+        "INSERT INTO \"meta\" VALUES('last_compatible_version','1');"
+        "CREATE TABLE origin_bound_certs ("
+            "origin TEXT NOT NULL UNIQUE PRIMARY KEY,"
+            "private_key BLOB NOT NULL,"
+            "cert BLOB NOT NULL,"
+            "cert_type INTEGER,"
+            "expiration_time INTEGER,"
+            "creation_time INTEGER);"
+        ));
+
+    sql::Statement add_smt(db.GetUniqueStatement(
+        "INSERT INTO origin_bound_certs "
+        "(origin, private_key, cert, cert_type, expiration_time, creation_time)"
+        " VALUES (?,?,?,?,?,?)"));
+    add_smt.BindString(0, "google.com");
+    add_smt.BindBlob(1, key_data.data(), key_data.size());
+    add_smt.BindBlob(2, cert_data.data(), cert_data.size());
+    add_smt.BindInt64(3, 64);
+    add_smt.BindInt64(4, GetTestCertExpirationTime().ToInternalValue());
+    add_smt.BindInt64(5, base::Time::Now().ToInternalValue());
+    ASSERT_TRUE(add_smt.Run());
+
+    add_smt.Clear();
+    add_smt.Assign(db.GetUniqueStatement(
+        "INSERT INTO origin_bound_certs "
+        "(origin, private_key, cert, cert_type, expiration_time, creation_time)"
+        " VALUES (?,?,?,?,?,?)"));
+    add_smt.BindString(0, "foo.com");
+    add_smt.BindBlob(1, key_data.data(), key_data.size());
+    add_smt.BindBlob(2, cert_data.data(), cert_data.size());
+    add_smt.BindInt64(3, 1);
+    add_smt.BindInt64(4, GetTestCertExpirationTime().ToInternalValue());
+    add_smt.BindInt64(5, base::Time::Now().ToInternalValue());
+    ASSERT_TRUE(add_smt.Run());
+  }
+
+  ScopedVector<net::DefaultServerBoundCertStore::ServerBoundCert> certs;
+  store_ = new SQLiteServerBoundCertStore(v4_db_path, NULL);
+
+  // Load the database and ensure the certs can be read.
+  Load(&certs);
+  // Only the ECDSA cert (for google.com) is read, the RSA one is discarded.
+  ASSERT_EQ(1U, certs.size());
+
+  ASSERT_EQ("google.com", certs[0]->server_identifier());
+  ASSERT_EQ(GetTestCertExpirationTime(),
+            certs[0]->expiration_time());
+  ASSERT_EQ(key_data, certs[0]->private_key());
+  ASSERT_EQ(cert_data, certs[0]->cert());
+
+  store_ = NULL;
+  // Make sure we wait until the destructor has run.
+  base::RunLoop().RunUntilIdle();
+}
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index b249f49..5661734 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -36,21 +36,22 @@
 
 MessageCenterNotificationManager::MessageCenterNotificationManager(
     message_center::MessageCenter* message_center,
-    PrefService* local_state)
+    PrefService* local_state,
+    scoped_ptr<message_center::NotifierSettingsProvider> settings_provider)
     : message_center_(message_center),
 #if defined(OS_WIN)
       first_run_idle_timeout_(
           base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)),
       weak_factory_(this),
 #endif
-      settings_controller_(new MessageCenterSettingsController) {
+      settings_provider_(settings_provider.Pass()) {
 #if defined(OS_WIN)
   first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state);
 #endif
 
   message_center_->SetDelegate(this);
   message_center_->AddObserver(this);
-  message_center_->SetNotifierSettingsProvider(settings_controller_.get());
+  message_center_->SetNotifierSettingsProvider(settings_provider_.get());
 
 #if defined(OS_WIN) || defined(OS_MACOSX) \
   || (defined(USE_AURA) && !defined(USE_ASH))
diff --git a/chrome/browser/notifications/message_center_notification_manager.h b/chrome/browser/notifications/message_center_notification_manager.h
index 91701d2..be2621e 100644
--- a/chrome/browser/notifications/message_center_notification_manager.h
+++ b/chrome/browser/notifications/message_center_notification_manager.h
@@ -34,9 +34,10 @@
       public message_center::MessageCenter::Delegate,
       public message_center::MessageCenterObserver {
  public:
-  explicit MessageCenterNotificationManager(
+  MessageCenterNotificationManager(
       message_center::MessageCenter* message_center,
-      PrefService* local_state);
+      PrefService* local_state,
+      scoped_ptr<message_center::NotifierSettingsProvider> settings_provider);
   virtual ~MessageCenterNotificationManager();
 
   // NotificationUIManager
@@ -220,7 +221,7 @@
   base::WeakPtrFactory<MessageCenterNotificationManager> weak_factory_;
 #endif
 
-  scoped_ptr<MessageCenterSettingsController> settings_controller_;
+  scoped_ptr<message_center::NotifierSettingsProvider> settings_provider_;
 
   // Registrar for the other kind of notifications (event signaling).
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/notifications/message_center_notifications_unittest_win.cc b/chrome/browser/notifications/message_center_notifications_unittest_win.cc
index fd674e6..01c8534 100644
--- a/chrome/browser/notifications/message_center_notifications_unittest_win.cc
+++ b/chrome/browser/notifications/message_center_notifications_unittest_win.cc
@@ -17,9 +17,11 @@
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/fake_notifier_settings_provider.h"
 #include "ui/message_center/message_center_impl.h"
 #include "ui/message_center/message_center_tray.h"
 #include "ui/message_center/message_center_tray_delegate.h"
+#include "ui/message_center/notifier_settings.h"
 
 namespace message_center {
 class FakeMessageCenterTrayDelegate : public MessageCenterTrayDelegate {
@@ -72,8 +74,10 @@
     // Initialize message center infrastructure with mock tray delegate.
     MessageCenter::Initialize();
     message_center_ = MessageCenter::Get();
-    notification_manager_.reset(
-        new MessageCenterNotificationManager(message_center_, &local_state_));
+    scoped_ptr<NotifierSettingsProvider> settings_provider(
+        new FakeNotifierSettingsProvider(notifiers_));
+    notification_manager_.reset(new MessageCenterNotificationManager(
+        message_center_, &local_state_, settings_provider.Pass()));
     delegate_ = new FakeMessageCenterTrayDelegate(message_center_,
                                                   run_loop_->QuitClosure());
     notification_manager_->SetMessageCenterTrayDelegateForTest(delegate_);
@@ -111,6 +115,7 @@
   scoped_ptr<base::RunLoop> run_loop_;
   TestingPrefServiceSimple local_state_;
   MessageCenter* message_center_;
+  std::vector<Notifier*> notifiers_;
   scoped_ptr<MessageCenterNotificationManager> notification_manager_;
   FakeMessageCenterTrayDelegate* delegate_;
   content::TestBrowserThreadBundle thread_bundle_;
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 5e9a588..ef91c33 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/i18n/string_compare.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/app_icon_loader_impl.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -19,6 +20,8 @@
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
 #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/cancelable_task_tracker.h"
 #include "chrome/common/extensions/extension_constants.h"
@@ -32,16 +35,39 @@
 #include "ui/gfx/image/image.h"
 #include "ui/message_center/message_center_style.h"
 
-#if defined(USE_ASH)
-#include "ash/shell.h"
-#include "ash/system/web_notification/web_notification_tray.h"
-#endif
-
 using message_center::Notifier;
 using message_center::NotifierId;
 
-namespace {
+namespace message_center {
+class ProfileNotifierGroup : public message_center::NotifierGroup {
+ public:
+  ProfileNotifierGroup(const gfx::Image& icon,
+                       const string16& display_name,
+                       const string16& login_info,
+                       size_t index,
+                       const base::FilePath& profile_path);
+  virtual ~ProfileNotifierGroup() {}
 
+  Profile* profile() const { return profile_; }
+
+ private:
+  Profile* profile_;
+};
+
+ProfileNotifierGroup::ProfileNotifierGroup(const gfx::Image& icon,
+                                           const string16& display_name,
+                                           const string16& login_info,
+                                           size_t index,
+                                           const base::FilePath& profile_path)
+    : message_center::NotifierGroup(icon, display_name, login_info, index),
+      profile_(NULL) {
+  // Try to get the profile
+  profile_ =
+      g_browser_process->profile_manager()->GetProfileByPath(profile_path);
+}
+}  // namespace message_center
+
+namespace {
 class NotifierComparator {
  public:
   explicit NotifierComparator(icu::Collator* collator) : collator_(collator) {}
@@ -61,13 +87,26 @@
 
 }  // namespace
 
-MessageCenterSettingsController::MessageCenterSettingsController()
-  : profile_(NULL) {
-  // We set the profile associated with the settings at the beginning and fail
-  // silently if this profile is destroyed later. This is a temporary fix for
-  // http://crbug.com/263193
-  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
-                 content::NotificationService::AllSources());
+MessageCenterSettingsController::MessageCenterSettingsController(
+    ProfileInfoCache* profile_info_cache)
+    : current_notifier_group_(0), profile_info_cache_(profile_info_cache) {
+  DCHECK(profile_info_cache_);
+  // The following events all represent changes that may need to be reflected in
+  // the profile selector context menu, so listen for them all.  We'll just
+  // rebuild the list when we get any of them.
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_PROFILE_CREATED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_PROFILE_ADDED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_PROFILE_DESTROYED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  registrar_.Add(this,
+                 chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
+                 content::NotificationService::AllBrowserContextsAndSources());
+  RebuildNotifierGroups();
 }
 
 MessageCenterSettingsController::~MessageCenterSettingsController() {
@@ -83,15 +122,47 @@
   observers_.RemoveObserver(observer);
 }
 
+size_t MessageCenterSettingsController::GetNotifierGroupCount() const {
+  return notifier_groups_.size();
+}
+
+const message_center::NotifierGroup&
+MessageCenterSettingsController::GetNotifierGroupAt(size_t index) const {
+  DCHECK_LT(index, notifier_groups_.size());
+  return *(notifier_groups_[index]);
+}
+
+const message_center::NotifierGroup&
+MessageCenterSettingsController::GetActiveNotifierGroup() const {
+  DCHECK_LT(current_notifier_group_, notifier_groups_.size());
+  return *(notifier_groups_[current_notifier_group_]);
+}
+
+void MessageCenterSettingsController::SwitchToNotifierGroup(size_t index) {
+  DCHECK_LT(index, notifier_groups_.size());
+  if (current_notifier_group_ == index)
+    return;
+
+  current_notifier_group_ = index;
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
+                    observers_,
+                    NotifierGroupChanged());
+}
+
 void MessageCenterSettingsController::GetNotifierList(
     std::vector<Notifier*>* notifiers) {
   DCHECK(notifiers);
   // TODO(mukai): Fix this for multi-profile.
   // Temporarily use the last used profile to prevent chrome from crashing when
   // the default profile is not loaded.
-  profile_ = ProfileManager::GetLastUsedProfileAllowedByPolicy();
+  message_center::ProfileNotifierGroup* group =
+      notifier_groups_[current_notifier_group_];
+  Profile* profile = group->profile();
+  if (!profile)
+    return;
+
   DesktopNotificationService* notification_service =
-      DesktopNotificationServiceFactory::GetForProfile(profile_);
+      DesktopNotificationServiceFactory::GetForProfile(profile);
 
   UErrorCode error;
   scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error));
@@ -99,7 +170,7 @@
   if (!U_FAILURE(error))
     comparator.reset(new NotifierComparator(collator.get()));
 
-  ExtensionService* extension_service = profile_->GetExtensionService();
+  ExtensionService* extension_service = profile->GetExtensionService();
   const ExtensionSet* extension_set = extension_service->extensions();
   // The extension icon size has to be 32x32 at least to load bigger icons if
   // the icon doesn't exist for the specified size, and in that case it falls
@@ -107,9 +178,10 @@
   // dialog. See chrome/browser/extensions/extension_icon_image.cc and
   // crbug.com/222931
   app_icon_loader_.reset(new extensions::AppIconLoaderImpl(
-      profile_, extension_misc::EXTENSION_ICON_SMALL, this));
+      profile, extension_misc::EXTENSION_ICON_SMALL, this));
   for (ExtensionSet::const_iterator iter = extension_set->begin();
-       iter != extension_set->end(); ++iter) {
+       iter != extension_set->end();
+       ++iter) {
     const extensions::Extension* extension = iter->get();
     if (!extension->HasAPIPermission(
             extensions::APIPermission::kNotification)) {
@@ -128,7 +200,7 @@
           CommandLine::ForCurrentProcess())) {
     notifier::ChromeNotifierService* sync_notifier_service =
         notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
-            profile_, Profile::EXPLICIT_ACCESS);
+            profile, Profile::EXPLICIT_ACCESS);
     sync_notifier_service->GetSyncedNotificationServices(notifiers);
 
     if (comparator)
@@ -141,8 +213,8 @@
 
   ContentSettingsForOneType settings;
   notification_service->GetNotificationsSettings(&settings);
-  FaviconService* favicon_service = FaviconServiceFactory::GetForProfile(
-      profile_, Profile::EXPLICIT_ACCESS);
+  FaviconService* favicon_service =
+      FaviconServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS);
   favicon_tracker_.reset(new CancelableTaskTracker());
   patterns_.clear();
   for (ContentSettingsForOneType::const_iterator iter = settings.begin();
@@ -163,7 +235,9 @@
         notification_service->IsNotifierEnabled(notifier_id)));
     patterns_[name] = iter->primary_pattern;
     FaviconService::FaviconForURLParams favicon_params(
-        profile_, url, chrome::FAVICON | chrome::TOUCH_ICON,
+        profile,
+        url,
+        chrome::FAVICON | chrome::TOUCH_ICON,
         message_center::kSettingsIconSize);
     // Note that favicon service obtains the favicon from history. This means
     // that it will fail to obtain the image if there are no history data for
@@ -201,12 +275,11 @@
 void MessageCenterSettingsController::SetNotifierEnabled(
     const Notifier& notifier,
     bool enabled) {
-  // TODO(mukai): Fix this for multi-profile.
-  // If the profile has been destroyed, fail silently.
-  if (!profile_)
-    return;
+  Profile* profile = notifier_groups_[current_notifier_group_]->profile();
+  DCHECK(profile);
+
   DesktopNotificationService* notification_service =
-      DesktopNotificationServiceFactory::GetForProfile(profile_);
+      DesktopNotificationServiceFactory::GetForProfile(profile);
 
   if (notifier.notifier_id.type == NotifierId::WEB_PAGE) {
     // WEB_PAGE notifier cannot handle in DesktopNotificationService
@@ -243,7 +316,7 @@
     if (notifier.notifier_id.type == NotifierId::SYNCED_NOTIFICATION_SERVICE) {
       notifier::ChromeNotifierService* notifier_service =
           notifier::ChromeNotifierServiceFactory::GetInstance()->GetForProfile(
-              profile_, Profile::EXPLICIT_ACCESS);
+              profile, Profile::EXPLICIT_ACCESS);
       notifier_service->OnSyncedNotificationServiceEnabled(
           notifier.notifier_id.id, enabled);
     }
@@ -256,17 +329,6 @@
   patterns_.clear();
 }
 
-void MessageCenterSettingsController::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (type == chrome::NOTIFICATION_PROFILE_DESTROYED &&
-      content::Source<Profile>(source).ptr() == profile_) {
-    // Our profile just got destroyed, so we delete our pointer to it.
-    profile_ = NULL;
-  }
-}
-
 void MessageCenterSettingsController::OnFaviconLoaded(
     const GURL& url,
     const chrome::FaviconImageResult& favicon_result) {
@@ -283,3 +345,32 @@
                     UpdateIconImage(NotifierId(NotifierId::APPLICATION, id),
                                     gfx::Image(image)));
 }
+
+void MessageCenterSettingsController::Observe(
+    int type,
+    const content::NotificationSource& source,
+    const content::NotificationDetails& details) {
+  RebuildNotifierGroups();
+  FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
+                    observers_,
+                    NotifierGroupChanged());
+}
+
+void MessageCenterSettingsController::RebuildNotifierGroups() {
+  notifier_groups_.clear();
+  current_notifier_group_ = 0;
+
+  const size_t count = profile_info_cache_->GetNumberOfProfiles();
+  for (size_t i = 0; i < count; ++i) {
+    message_center::ProfileNotifierGroup* group =
+        new message_center::ProfileNotifierGroup(
+            profile_info_cache_->GetAvatarIconOfProfileAtIndex(i),
+            profile_info_cache_->GetNameOfProfileAtIndex(i),
+            profile_info_cache_->GetUserNameOfProfileAtIndex(i),
+            i,
+            profile_info_cache_->GetPathOfProfileAtIndex(i));
+    if (group->profile() != NULL) {
+      notifier_groups_.push_back(group);
+    }
+  }
+}
diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h
index 1a66099..4adc136 100644
--- a/chrome/browser/notifications/message_center_settings_controller.h
+++ b/chrome/browser/notifications/message_center_settings_controller.h
@@ -10,28 +10,36 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/observer_list.h"
 #include "chrome/browser/extensions/app_icon_loader.h"
-#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/content_settings.h"
+#include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_source.h"
 #include "ui/message_center/notifier_settings.h"
 
 class CancelableTaskTracker;
+class ProfileInfoCache;
 
 namespace chrome {
 struct FaviconImageResult;
 }
 
+namespace message_center {
+class ProfileNotifierGroup;
+}
+
 // The class to bridge between the settings UI of notifiers and the preference
 // storage.
 class MessageCenterSettingsController
     : public message_center::NotifierSettingsProvider,
-      public extensions::AppIconLoader::Delegate,
-      public content::NotificationObserver {
+      public content::NotificationObserver,
+      public extensions::AppIconLoader::Delegate {
  public:
-  MessageCenterSettingsController();
+  explicit MessageCenterSettingsController(
+      ProfileInfoCache* profile_info_cache);
   virtual ~MessageCenterSettingsController();
 
   // Overridden from message_center::NotifierSettingsProvider.
@@ -39,12 +47,16 @@
       message_center::NotifierSettingsObserver* observer) OVERRIDE;
   virtual void RemoveObserver(
       message_center::NotifierSettingsObserver* observer) OVERRIDE;
-  virtual void GetNotifierList(
-      std::vector<message_center::Notifier*>* notifiers)
+  virtual size_t GetNotifierGroupCount() const OVERRIDE;
+  virtual const message_center::NotifierGroup& GetNotifierGroupAt(
+      size_t index) const OVERRIDE;
+  virtual void SwitchToNotifierGroup(size_t index) OVERRIDE;
+  virtual const message_center::NotifierGroup& GetActiveNotifierGroup() const
       OVERRIDE;
-  virtual void SetNotifierEnabled(
-      const message_center::Notifier& notifier,
-      bool enabled) OVERRIDE;
+  virtual void GetNotifierList(
+      std::vector<message_center::Notifier*>* notifiers) OVERRIDE;
+  virtual void SetNotifierEnabled(const message_center::Notifier& notifier,
+                                  bool enabled) OVERRIDE;
   virtual void OnNotifierSettingsClosing() OVERRIDE;
 
   // Overridden from extensions::AppIconLoader::Delegate.
@@ -60,6 +72,8 @@
   void OnFaviconLoaded(const GURL& url,
                        const chrome::FaviconImageResult& favicon_result);
 
+  void RebuildNotifierGroups();
+
   // The views displaying notifier settings.
   ObserverList<message_center::NotifierSettingsObserver> observers_;
 
@@ -70,12 +84,14 @@
 
   std::map<string16, ContentSettingsPattern> patterns_;
 
-  // The Registrar used to register for notifications.
+  // The list of all configurable notifier groups. This is each profile that is
+  // loaded (and in the ProfileInfoCache - so no incognito profiles go here).
+  ScopedVector<message_center::ProfileNotifierGroup> notifier_groups_;
+  size_t current_notifier_group_;
+
   content::NotificationRegistrar registrar_;
 
-  // TODO(sidharthms): Fix this for multi-profile.
-  // The profile associated with message center settings.
-  Profile* profile_;
+  ProfileInfoCache* profile_info_cache_;
 
   DISALLOW_COPY_AND_ASSIGN(MessageCenterSettingsController);
 };
diff --git a/chrome/browser/notifications/message_center_settings_controller_unittest.cc b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
new file mode 100644
index 0000000..e46505c
--- /dev/null
+++ b/chrome/browser/notifications/message_center_settings_controller_unittest.cc
@@ -0,0 +1,71 @@
+// 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 <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/notifications/message_center_settings_controller.h"
+#include "chrome/browser/prefs/pref_service_syncable.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/message_center/notifier_settings.h"
+
+class MessageCenterSettingsControllerTest : public testing::Test {
+ protected:
+  MessageCenterSettingsControllerTest()
+      : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {};
+  virtual ~MessageCenterSettingsControllerTest() {};
+
+  base::FilePath GetProfilePath(const std::string& base_name) {
+    return testing_profile_manager_.profile_manager()->user_data_dir()
+        .AppendASCII(base_name);
+  }
+
+  virtual void SetUp() OVERRIDE {
+    ASSERT_TRUE(testing_profile_manager_.SetUp());
+  }
+
+  ProfileInfoCache* GetCache() {
+    return testing_profile_manager_.profile_info_cache();
+  }
+
+  void CreateProfile(const std::string& name) {
+    testing_profile_manager_.CreateTestingProfile(name);
+  }
+
+  TestingProfileManager testing_profile_manager_;
+};
+
+TEST_F(MessageCenterSettingsControllerTest, NotifierGroups) {
+  CreateProfile("Profile-1");
+  CreateProfile("Profile-2");
+
+  scoped_ptr<MessageCenterSettingsController> controller(
+      new MessageCenterSettingsController(GetCache()));
+
+  EXPECT_EQ(controller->GetNotifierGroupCount(), 2u);
+
+  EXPECT_EQ(controller->GetNotifierGroupAt(0).name, UTF8ToUTF16("Profile-1"));
+  EXPECT_EQ(controller->GetNotifierGroupAt(0).index, 0u);
+
+  EXPECT_EQ(controller->GetNotifierGroupAt(1).name, UTF8ToUTF16("Profile-2"));
+  EXPECT_EQ(controller->GetNotifierGroupAt(1).index, 1u);
+
+  EXPECT_EQ(controller->GetActiveNotifierGroup().name,
+            UTF8ToUTF16("Profile-1"));
+  EXPECT_EQ(controller->GetActiveNotifierGroup().index, 0u);
+
+  controller->SwitchToNotifierGroup(1);
+  EXPECT_EQ(controller->GetActiveNotifierGroup().name,
+            UTF8ToUTF16("Profile-2"));
+  EXPECT_EQ(controller->GetActiveNotifierGroup().index, 1u);
+
+  controller->SwitchToNotifierGroup(0);
+  EXPECT_EQ(controller->GetActiveNotifierGroup().name,
+            UTF8ToUTF16("Profile-1"));
+}
diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc
index 8bbafe7..19e6c24 100644
--- a/chrome/browser/notifications/notification_ui_manager.cc
+++ b/chrome/browser/notifications/notification_ui_manager.cc
@@ -4,10 +4,14 @@
 
 #include "chrome/browser/notifications/notification_ui_manager.h"
 
+#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
 #include "chrome/browser/notifications/message_center_notification_manager.h"
+#include "chrome/browser/notifications/message_center_settings_controller.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "ui/message_center/message_center_util.h"
 
 // static
@@ -24,9 +28,16 @@
 #if !defined(OS_MACOSX)
 // static
 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
-  if (DelegatesToMessageCenter())
+  if (DelegatesToMessageCenter()) {
+    ProfileInfoCache* profile_info_cache =
+        &g_browser_process->profile_manager()->GetProfileInfoCache();
+    scoped_ptr<message_center::NotifierSettingsProvider> settings_provider(
+        new MessageCenterSettingsController(profile_info_cache));
     return new MessageCenterNotificationManager(
-        g_browser_process->message_center(), local_state);
+        g_browser_process->message_center(),
+        local_state,
+        settings_provider.Pass());
+  }
 
   BalloonNotificationUIManager* balloon_manager =
       new BalloonNotificationUIManager(local_state);
diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm
index 5222aa1..d0b783c 100644
--- a/chrome/browser/notifications/notification_ui_manager_mac.mm
+++ b/chrome/browser/notifications/notification_ui_manager_mac.mm
@@ -6,12 +6,16 @@
 
 #include "base/mac/cocoa_protocols.h"
 #include "base/mac/mac_util.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/notification.h"
 #include "chrome/browser/notifications/balloon_notification_ui_manager.h"
 #include "chrome/browser/notifications/message_center_notification_manager.h"
+#include "chrome/browser/notifications/message_center_settings_controller.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_info_cache.h"
+#include "chrome/browser/profiles/profile_manager.h"
 #include "ui/message_center/message_center_util.h"
 
 @class NSUserNotificationCenter;
@@ -101,8 +105,14 @@
   // TODO(rsesek): Remove this function and merge it with the one in
   // notification_ui_manager.cc.
   if (DelegatesToMessageCenter()) {
+    ProfileInfoCache* profile_info_cache =
+        &g_browser_process->profile_manager()->GetProfileInfoCache();
+    scoped_ptr<message_center::NotifierSettingsProvider> settings_provider(
+        new MessageCenterSettingsController(profile_info_cache));
     return new MessageCenterNotificationManager(
-        g_browser_process->message_center(), local_state);
+        g_browser_process->message_center(),
+        local_state,
+        settings_provider.Pass());
   }
 
   BalloonNotificationUIManager* balloon_manager = NULL;
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index e15504b..c45b476 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -1297,18 +1297,7 @@
 }
 #endif
 
-// There's a bug filed for flakiness on windows: http://crbug.com/248464.
-// Unfortunately, the bug doesn't contain any actionable information, so this
-// test is temporarily enabled to get some cycles on the builders in order to
-// gather data on the nature of the flakes.
-#if defined(OS_WIN)
-// TODO(mnissler): Flip back to DISABLED after obtaining logs from flaky runs.
-#define MAYBE_ExtensionInstallBlacklist ExtensionInstallBlacklist
-#else
-#define MAYBE_ExtensionInstallBlacklist ExtensionInstallBlacklist
-#endif
-
-IN_PROC_BROWSER_TEST_F(PolicyTest, MAYBE_ExtensionInstallBlacklist) {
+IN_PROC_BROWSER_TEST_F(PolicyTest, ExtensionInstallBlacklistSelective) {
   // Verifies that blacklisted extensions can't be installed.
   ExtensionService* service = extension_service();
   ASSERT_FALSE(service->GetExtensionById(kGoodCrxId, true));
@@ -1330,15 +1319,24 @@
   EXPECT_EQ(kAdBlockCrxId, adblock->id());
   EXPECT_EQ(adblock,
             service->GetExtensionById(kAdBlockCrxId, true));
+}
 
-  // Now blacklist all extensions.
-  blacklist.Clear();
+IN_PROC_BROWSER_TEST_F(PolicyTest, ExtensionInstallBlacklistWildcard) {
+  // Verify that a wildcard blacklist takes effect.
+  EXPECT_TRUE(InstallExtension(kAdBlockCrxName));
+  ExtensionService* service = extension_service();
+  ASSERT_FALSE(service->GetExtensionById(kGoodCrxId, true));
+  ASSERT_TRUE(service->GetExtensionById(kAdBlockCrxId, true));
+  base::ListValue blacklist;
   blacklist.Append(base::Value::CreateStringValue("*"));
+  PolicyMap policies;
   policies.Set(key::kExtensionInstallBlacklist, POLICY_LEVEL_MANDATORY,
                POLICY_SCOPE_USER, blacklist.DeepCopy(), NULL);
   UpdateProviderPolicy(policies);
+
   // AdBlock was automatically removed.
   ASSERT_FALSE(service->GetExtensionById(kAdBlockCrxId, true));
+
   // And can't be installed again, nor can good.crx.
   EXPECT_FALSE(InstallExtension(kAdBlockCrxName));
   EXPECT_FALSE(service->GetExtensionById(kAdBlockCrxId, true));
diff --git a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
index 06deb8b..a88f58f 100644
--- a/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
+++ b/chrome/browser/policy/proto/chromeos/chrome_device_policy.proto
@@ -236,6 +236,12 @@
   optional string timezone = 1;
 }
 
+message SystemUse24HourClockProto {
+  // Specifies an owner-determined clock format that applies to the login
+  // screen and all users.
+  optional bool use_24hour_clock = 1;
+}
+
 // Parameters for Kiosk App device-local accounts.
 message KioskAppInfoProto {
   // Indicates the Kiosk App for the corresponding device-local account. The
@@ -539,4 +545,5 @@
   optional AccessibilitySettingsProto accessibility_settings = 27;
   optional SupervisedUsersSettingsProto supervised_users_settings = 28;
   optional LoginScreenPowerManagementProto login_screen_power_management = 29;
+  optional SystemUse24HourClockProto use_24hour_clock = 30;
 }
diff --git a/chrome/browser/policy/test/policy_testserver.py b/chrome/browser/policy/test/policy_testserver.py
index c7113b5..1ccf35a 100644
--- a/chrome/browser/policy/test/policy_testserver.py
+++ b/chrome/browser/policy/test/policy_testserver.py
@@ -310,7 +310,7 @@
     # else return a descriptive default value.
     response = dm.DeviceManagementResponse()
     response.service_api_access_response.auth_code = policy.get(
-        'robot_api_auth_code', 'policy_test_server.py-auth_code')
+        'robot_api_auth_code', 'policy_testserver.py-auth_code')
     self.DumpMessage('Response', response)
 
     return (200, response.SerializeToString())
@@ -592,6 +592,9 @@
     policy_data.valid_serial_number_missing = (
         token_info['machine_id'] in BAD_MACHINE_IDS)
     policy_data.settings_entity_id = msg.settings_entity_id
+    policy_data.service_account_identity = policy.get(
+        'service_account_identity',
+        'policy_testserver.py-service_account_identity')
 
     if signing_key:
       policy_data.public_key_version = current_key_index + 1
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 957e655..f954807 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -178,6 +178,12 @@
 // Chrome To Mobile has been removed; this pref will be cleared from user data.
 const char kChromeToMobilePref[] = "chrome_to_mobile.device_list";
 
+#if !defined(OS_ANDROID)
+// The sync promo error message preference has been removed; this pref will
+// be cleared from user data.
+const char kSyncPromoErrorMessage[] = "sync_promo.error_message";
+#endif
+
 }  // namespace
 
 namespace chrome {
@@ -388,6 +394,12 @@
   registry->RegisterListPref(
       kChromeToMobilePref,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#if !defined(OS_ANDROID)
+  registry->RegisterStringPref(
+      kSyncPromoErrorMessage,
+      std::string(),
+      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+#endif
 }
 
 void RegisterUserProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
@@ -415,6 +427,12 @@
   // Cleanup prefs from now-removed Chrome To Mobile feature.
   prefs->ClearPref(kChromeToMobilePref);
 
+#if !defined(OS_ANDROID)
+  // Cleanup now-removed sync promo error message preference.
+  // TODO(fdoray): Remove this when it's safe to do so (crbug.com/268442).
+  prefs->ClearPref(kSyncPromoErrorMessage);
+#endif
+
   PrefsTabHelper::MigrateUserPrefs(prefs);
   PromoResourceService::MigrateUserPrefs(prefs);
   TranslatePrefs::MigrateUserPrefs(prefs);
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index be72377..8a4993e 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -445,8 +445,6 @@
 }
 
 TEST_F(ProfileResetterTest, ResetExtensionsByDisabling) {
-  service_->Init();
-
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
diff --git a/chrome/browser/profiles/avatar_menu_model.cc b/chrome/browser/profiles/avatar_menu_model.cc
index 8b1a4d1..99f9d89 100644
--- a/chrome/browser/profiles/avatar_menu_model.cc
+++ b/chrome/browser/profiles/avatar_menu_model.cc
@@ -249,7 +249,7 @@
 #if defined(ENABLE_MANAGED_USERS)
     ManagedUserService* service = ManagedUserServiceFactory::GetForProfile(
         browser_->profile());
-    base::string16 custodian = UTF8ToUTF16(service->GetCustodianName());
+    base::string16 custodian = UTF8ToUTF16(service->GetCustodianEmailAddress());
     return l10n_util::GetStringFUTF16(IDS_MANAGED_USER_INFO, custodian);
 #endif
   }
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index 7ce8ca2..9a0d9ed 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -527,7 +527,6 @@
   ListDesktopShortcutsWithCommandLine(chrome_exe, command_line, false,
                                       &shortcuts);
 
-  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
   for (size_t i = 0; i < shortcuts.size(); ++i) {
     // Use base::DeleteFile() instead of ShellUtil::RemoveShortcut(), as the
     // latter causes non-profile taskbar shortcuts to be unpinned.
diff --git a/chrome/browser/resources/bookmark_manager/css/bmm.css b/chrome/browser/resources/bookmark_manager/css/bmm.css
index 848482e..5c10770 100644
--- a/chrome/browser/resources/bookmark_manager/css/bmm.css
+++ b/chrome/browser/resources/bookmark_manager/css/bmm.css
@@ -269,6 +269,10 @@
   width: 32px;
 }
 
+html:not(.focus-outline-visible) .logo:focus {
+  outline: none;
+}
+
 .header form {
   float: left;
   margin: 14px 2px 0 2px;
diff --git a/chrome/browser/resources/bookmark_manager/js/main.js b/chrome/browser/resources/bookmark_manager/js/main.js
index 0452c28..f0b2654 100644
--- a/chrome/browser/resources/bookmark_manager/js/main.js
+++ b/chrome/browser/resources/bookmark_manager/js/main.js
@@ -1297,6 +1297,7 @@
     canOpenNewWindows = result;
   });
 
+  cr.ui.FocusOutlineManager.forDocument(document);
   initializeSplitter();
   bmm.addBookmarkModelListeners();
   dnd.init(selectItemsAfterUserAction);
diff --git a/chrome/browser/resources/bookmark_manager/main.html b/chrome/browser/resources/bookmark_manager/main.html
index f8acdf6..e9eb1bf 100644
--- a/chrome/browser/resources/bookmark_manager/main.html
+++ b/chrome/browser/resources/bookmark_manager/main.html
@@ -30,6 +30,7 @@
 <script src="chrome://resources/js/cr/ui/touch_handler.js"></script>
 <script src="chrome://resources/js/cr/ui/array_data_model.js"></script>
 <script src="chrome://resources/js/cr/ui/command.js"></script>
+<script src="chrome://resources/js/cr/ui/focus_outline_manager.js"></script>
 <script src="chrome://resources/js/cr/ui/menu_item.js"></script>
 <script src="chrome://resources/js/cr/ui/menu.js"></script>
 <script src="chrome://resources/js/cr/ui/position_util.js"></script>
diff --git a/chrome/browser/resources/file_manager/js/action_choice.js b/chrome/browser/resources/file_manager/js/action_choice.js
index 936d431..c247ee2 100644
--- a/chrome/browser/resources/file_manager/js/action_choice.js
+++ b/chrome/browser/resources/file_manager/js/action_choice.js
@@ -438,7 +438,7 @@
   }
 
   if (action == this.watchSingleVideoAction_) {
-    chrome.fileBrowserPrivate.viewFiles([this.singleVideo_.toURL()], 'watch',
+    chrome.fileBrowserPrivate.viewFiles([this.singleVideo_.toURL()],
         function(success) {});
     this.recordAction_('watch-single-video');
     this.close_();
diff --git a/chrome/browser/resources/file_manager/js/butter_bar.js b/chrome/browser/resources/file_manager/js/butter_bar.js
index f372539..2be649a 100644
--- a/chrome/browser/resources/file_manager/js/butter_bar.js
+++ b/chrome/browser/resources/file_manager/js/butter_bar.js
@@ -255,15 +255,16 @@
 ButterBar.prototype.showProgress_ = function(progress) {
   this.progress_ = progress;
   var options = {
-    progress: this.progress_.percentage,
+    progress: progress.completedBytes / progress.totalBytes,
     actions: {},
     timeout: false
   };
 
+  var pendingItems = progress.totalItems - progress.completedItems;
   var type = this.transferType_();
-  var progressString = (this.progress_.pendingItems === 1) ?
-          strf(type + '_FILE_NAME', this.progress_.filename) :
-          strf(type + '_ITEMS_REMAINING', this.progress_.pendingItems);
+  var progressString = (pendingItems === 1) ?
+          strf(type + '_FILE_NAME', progress.filename) :
+          strf(type + '_ITEMS_REMAINING', pendingItems);
 
   if (this.currentMode_ == ButterBar.Mode.COPY) {
     this.update_(progressString, options);
diff --git a/chrome/browser/resources/file_manager/js/directory_tree.js b/chrome/browser/resources/file_manager/js/directory_tree.js
index 81bbaa1..9214d23 100644
--- a/chrome/browser/resources/file_manager/js/directory_tree.js
+++ b/chrome/browser/resources/file_manager/js/directory_tree.js
@@ -88,18 +88,19 @@
 };
 
 /**
- * Finds a parent directory of the {@code path} from the {@code items}, and
- * invokes the DirectoryItem.selectPath() of the found directory.
+ * Finds a parent directory of the {@code entry} from the {@code items}, and
+ * invokes the DirectoryItem.selectByEntry() of the found directory.
  *
  * @param {Array.<DirectoryItem>} items Items to be searched.
- * @param {string} path Path to be searched for.
+ * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be
+ *     a fake.
  * @return {boolean} True if the parent item is found.
  */
-DirectoryTreeUtil.searchAndSelectPath = function(items, path) {
+DirectoryTreeUtil.searchAndSelectByEntry = function(items, entry) {
   for (var i = 0; i < items.length; i++) {
     var item = items[i];
-    if (PathUtil.isParentPath(item.entry.fullPath, path)) {
-      item.selectPath(path);
+    if (util.isParentEntry(item.entry, entry)) {
+      item.selectByEntry(entry);
       return true;
     }
   }
@@ -262,19 +263,18 @@
    * The DirectoryEntry corresponding to this DirectoryItem. This may be
    * a dummy DirectoryEntry.
    * @type {DirectoryEntry|Object}
-   * @override
-   **/
+   */
   get entry() {
-      return this.dirEntry_;
+    return this.dirEntry_;
   },
 
   /**
    * The element containing the label text and the icon.
    * @type {!HTMLElement}
    * @override
-   **/
+   */
   get labelElement() {
-      return this.firstElementChild.querySelector('.label');
+    return this.firstElementChild.querySelector('.label');
   }
 };
 
@@ -418,22 +418,22 @@
 };
 
 /**
- * Select the item corresponding to the given {@code path}.
- * @param {string} path Path to be selected.
+ * Select the item corresponding to the given {@code entry}.
+ * @param {DirectoryEntry|Object} entry The entry to be selected. Can be a fake.
  */
-DirectoryItem.prototype.selectPath = function(path) {
-  if (path == this.fullPath) {
+DirectoryItem.prototype.selectByEntry = function(entry) {
+  if (util.isSameEntry(entry, this.entry)) {
     this.selected = true;
     return;
   }
 
-  if (DirectoryTreeUtil.searchAndSelectPath(this.items, path))
+  if (DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
     return;
 
   // If the path doesn't exist, updates sub directories and tryes again.
   this.updateSubDirectories(
       false /* recursive */,
-      DirectoryTreeUtil.searchAndSelectPath.bind(null, this.items, path));
+      DirectoryTreeUtil.searchAndSelectByEntry.bind(null, this.items, entry));
 };
 
 /**
@@ -530,18 +530,21 @@
   this.dirEntry_ = null;
 
   /**
-   * The path of the current directory.
-   * @type {string}
+   * The currently selected entry.
+   * For special search entries, this could be a fake DirectoryEntry.
+   * @type {DirectoryEntry|Object}
    */
-  this.currentPath_ = null;
+  this.currentEntry_ = null;
 
   this.directoryModel_.addEventListener('directory-changed',
       this.onCurrentDirectoryChanged_.bind(this));
 
   // Add a handler for directory change.
   this.addEventListener('change', function() {
-    if (this.selectedItem && this.currentPath_ != this.selectedItem.fullPath) {
-      this.currentPath_ = this.selectedItem.fullPath;
+    if (this.selectedItem &&
+        (!this.currentEntry_ ||
+         !util.isSameEntry(this.currentEntry_, this.selectedItem.entry))) {
+      this.currentEntry_ = this.selectedItem.entry;
       this.selectedItem.doAction();
       return;
     }
@@ -557,27 +560,30 @@
 };
 
 /**
- * Select the item corresponding to the given path.
- * @param {string} path Path to be selected.
+ * Select the item corresponding to the given entry.
+ * @param {DirectoryEntry|Object} entry The directory entry to be selected. Can
+ *     be a fake.
  */
-DirectoryTree.prototype.selectPath = function(path) {
-  if ((this.entry && this.entry.fullPath == path) || this.currentPath_ == path)
-    return;
-  this.currentPath_ = path;
-  if (DirectoryTreeUtil.shouldHideTree(path))
+DirectoryTree.prototype.selectByEntry = function(entry) {
+  if ((this.entry && util.isSameEntry(this.entry, entry)) ||
+      (this.currentEntry_ && util.isSameEntry(this.currentEntry_, entry)))
     return;
 
-  this.selectPathInternal_(path);
+  this.currentEntry_ = entry;
+  if (DirectoryTreeUtil.shouldHideTree(entry.fullPath))
+    return;
+
+  this.selectByEntryInternal_(entry);
 };
 
 /**
- * Select the item corresponding to the given path. This method is used
+ * Select the item corresponding to the given entry. This method is used
  * internally.
- * @param {string} path Path to be selected.
+ * @param {DirectoryEntry|Object} entry The directory entry to be selected.
  * @private
  */
-DirectoryTree.prototype.selectPathInternal_ = function(path) {
-  var rootDirPath = PathUtil.getRootPath(path);
+DirectoryTree.prototype.selectByEntryInternal_ = function(entry) {
+  var rootDirPath = PathUtil.getRootPath(entry.fullPath);
 
   if (PathUtil.isSpecialSearchRoot(rootDirPath) ||
       PathUtil.getRootType(rootDirPath) == RootType.DRIVE) {
@@ -589,36 +595,39 @@
   }.bind(this);
 
   if (this.fullPath != rootDirPath || !this.dirEntry_) {
+    // The old root is not the one for the new entry. So, first we try to set
+    // the root, then retry.
     this.fullPath = rootDirPath;
 
     this.directoryModel_.resolveDirectory(
         rootDirPath,
-        function(entry) {
+        function(rootDirEntry) {
           if (this.fullPath != rootDirPath)
             return;
 
-          this.dirEntry_ = entry;
-          this.selectPathInternal_(path);
+          this.dirEntry_ = rootDirEntry;
+          this.selectByEntryInternal_(entry);
         }.bind(this),
         onError);
-  } else {
-    if (this.selectedItem && path == this.selectedItem.fullPath)
-      return;
-
-    if (DirectoryTreeUtil.searchAndSelectPath(this.items, path))
-      return;
-
-    this.selectedItem = null;
-    this.updateSubDirectories(
-        false /* recursive */,
-        function() {
-          if (!DirectoryTreeUtil.searchAndSelectPath(
-              this.items, this.currentPath_))
-            this.selectedItem = null;
-          cr.dispatchSimpleEvent(this, 'content-updated');
-        }.bind(this),
-        onError);
+    return;
   }
+
+  if (this.selectedItem && util.isSameEntry(entry, this.selectedItem.entry))
+    return;
+
+  if (DirectoryTreeUtil.searchAndSelectByEntry(this.items, entry))
+    return;
+
+  this.selectedItem = null;
+  this.updateSubDirectories(
+      false /* recursive */,
+      function() {
+        if (!DirectoryTreeUtil.searchAndSelectByEntry(
+            this.items, this.currentEntry_))
+          this.selectedItem = null;
+        cr.dispatchSimpleEvent(this, 'content-updated');
+      }.bind(this),
+      onError);
 };
 
 /**
@@ -629,7 +638,7 @@
  */
 DirectoryTree.prototype.updateSubDirectories = function(
     recursive, opt_successCallback, opt_errorCallback) {
-  if (!this.currentPath_)
+  if (!this.currentEntry_)
     return;
 
   DirectoryTreeUtil.updateSubDirectories(
@@ -663,7 +672,8 @@
  */
 DirectoryTree.prototype.onFilterChanged_ = function() {
   // Returns immediately, if the tree is hidden.
-  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
+  if (!this.currentEntry_ ||
+      DirectoryTreeUtil.shouldHideTree(this.currentEntry_.fullPath))
     return;
 
   this.redraw(true /* recursive */);
@@ -677,7 +687,8 @@
  */
 DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) {
   // Returns immediately, if the tree is hidden.
-  if (!this.currentPath_ || DirectoryTreeUtil.shouldHideTree(this.currentPath_))
+  if (!this.currentEntry_ ||
+      DirectoryTreeUtil.shouldHideTree(this.currentEntry_.fullPath))
     return;
 
   if (event.eventType == 'changed') {
@@ -692,7 +703,7 @@
  * @private
  */
 DirectoryTree.prototype.onCurrentDirectoryChanged_ = function(event) {
-  this.selectPath(event.newDirEntry.fullPath);
+  this.selectByEntry(event.newDirEntry);
 };
 
 /**
diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager.js b/chrome/browser/resources/file_manager/js/file_copy_manager.js
index 9d911ef..f374a3d 100644
--- a/chrome/browser/resources/file_manager/js/file_copy_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js
@@ -56,6 +56,144 @@
 };
 
 /**
+ * Copies a file from source to the parent directory with newName.
+ * See also copyFileByStream_ and copyFileOnDrive_ for the implementation
+ * details.
+ *
+ * @param {FileEntry} source The file entry to be copied.
+ * @param {DirectoryEntry} parent The entry of the destination directory.
+ * @param {string} newName The name of copied file.
+ * @param {function(FileEntry, number)} progressCallback Callback invoked
+ *     periodically during the file writing. It takes source and the number of
+ *     copied bytes since the last invocation. This is also called just before
+ *     starting the operation (with '0' bytes) and just after the finishing the
+ *     operation (with the total copied size).
+ * @param {function(FileEntry)} successCallback Callback invoked when the copy
+ *     is successfully done with the entry of the created file.
+ * @param {function(FileError)} errorCallback Callback invoked when an error
+ *     is found.
+ * @return {function()} Callback to cancle the current file copy operation.
+ *     When the cancel is done, errorCallback will be called. The returned
+ *     callback must not be called more than once.
+ */
+fileOperationUtil.copyFile = function(
+    source, parent, newName, progressCallback, successCallback, errorCallback) {
+  if (!PathUtil.isDriveBasedPath(source.fullPath) &&
+      !PathUtil.isDriveBasedPath(parent.fullPath)) {
+    // Copying a file between non-Drive file systems.
+    return fileOperationUtil.copyFileByStream_(
+        source, parent, newName, progressCallback, successCallback,
+        errorCallback);
+  } else {
+    // Copying related to the Drive file system.
+    return fileOperationUtil.copyFileOnDrive_(
+        source, parent, newName, progressCallback, successCallback,
+        errorCallback);
+  }
+};
+
+/**
+ * Copies a file by using File and FileWriter objects.
+ *
+ * This is a js-implementation of FileEntry.copyTo(). Unfortunately, copyTo
+ * doesn't support periodical progress updating nor cancelling. To support
+ * these operations, this method implements copyTo by streaming way in
+ * JavaScript.
+ *
+ * Note that this is designed for file copying on local file system. We have
+ * some special cases about copying on Drive file system. See also
+ * copyFileOnDrive_() for more details.
+ *
+ * @param {FileEntry} source The file entry to be copied.
+ * @param {DirectoryEntry} parent The entry of the destination directory.
+ * @param {string} newName The name of copied file.
+ * @param {function(FileEntry, number)} progressCallback Callback invoked
+ *     periodically during the file writing. It takes source and the number of
+ *     copied bytes since the last invocation. This is also called just before
+ *     starting the operation (with '0' bytes) and just after the finishing the
+ *     operation (with the total copied size).
+ * @param {function(FileEntry)} successCallback Callback invoked when the copy
+ *     is successfully done with the entry of the created file.
+ * @param {function(FileError)} errorCallback Callback invoked when an error
+ *     is found.
+ * @return {function()} Callback to cancel the current file copy operation.
+ *     When the cancel is done, errorCallback will be called. The returned
+ *     callback must not be called more than once.
+ * @private
+ */
+fileOperationUtil.copyFileByStream_ = function(
+    source, parent, newName, progressCallback, successCallback, errorCallback) {
+  // Set to true when cancel is requested.
+  var cancelRequested = false;
+
+  source.file(function(file) {
+    if (cancelRequested) {
+      errorCallback(util.createFileError(FileError.ABORT_ERR));
+      return;
+    }
+
+    parent.getFile(newName, {create: true, exclusive: true}, function(target) {
+      if (cancelRequested) {
+        errorCallback(util.createFileError(FileError.ABORT_ERR));
+        return;
+      }
+
+      target.createWriter(function(writer) {
+        if (cancelRequested) {
+          errorCallback(util.createFileError(FileError.ABORT_ERR));
+          return;
+        }
+
+        writer.onerror = writer.onabort = function(progress) {
+          errorCallback(cancelRequested ?
+              util.createFileError(FileError.ABORT_ERR) :
+                  writer.error);
+        };
+
+        var reportedProgress = 0;
+        writer.onprogress = function(progress) {
+          if (cancelRequested) {
+            // If the copy was cancelled, we should abort the operation.
+            // The errorCallback will be called by writer.onabort after the
+            // termination.
+            writer.abort();
+            return;
+          }
+
+          // |progress.loaded| will contain total amount of data copied by now.
+          // |progressCallback| expects data amount delta from the last progress
+          // update.
+          progressCallback(target, progress.loaded - reportedProgress);
+          reportedProgress = progress.loaded;
+        };
+
+        writer.onwrite = function() {
+          if (cancelRequested) {
+            errorCallback(util.createFileError(FileError.ABORT_ERR));
+            return;
+          }
+
+          source.getMetadata(function(metadata) {
+            if (cancelRequested) {
+              errorCallback(util.createFileError(FileError.ABORT_ERR));
+              return;
+            }
+
+            fileOperationUtil.setLastModified(
+                target, metadata.modificationTime);
+            successCallback(target);
+          }, errorCallback);
+        };
+
+        writer.write(file);
+      }, errorCallback);
+    }, errorCallback);
+  }, errorCallback);
+
+  return function() { cancelRequested = true; };
+};
+
+/**
  * Copies a file a) from Drive to local, b) from local to Drive, or c) from
  * Drive to Drive.
  * Currently, we need to take care about following two things for Drive:
@@ -96,8 +234,9 @@
  * @return {function()} Callback to cancel the current file copy operation.
  *     When the cancel is done, errorCallback will be called. The returned
  *     callback must not be called more than once.
+ * @private
  */
-fileOperationUtil.copyFileOnDrive = function(
+fileOperationUtil.copyFileOnDrive_ = function(
     source, parent, newName, progressCallback, successCallback, errorCallback) {
   // Set to true when cancel is requested.
   var cancelRequested = false;
@@ -328,18 +467,24 @@
   this.zipBaseDirEntry = opt_zipBaseDirEntry;
   this.originalEntries = null;
 
-  this.pendingDirectories = [];
-  this.pendingFiles = [];
-  this.pendingBytes = 0;
+  // TODO(hidehiko): When we support recursive copy, we should be able to
+  // rely on originalEntries. Then remove this.
+  this.entries = [];
 
-  this.completedDirectories = [];
-  this.completedFiles = [];
+  /**
+   * The index of entries being processed. The entries should be processed
+   * from 0, so this is also the number of completed entries.
+   * @type {number}
+   */
+  this.entryIndex = 0;
+  this.totalBytes = 0;
   this.completedBytes = 0;
 
   this.deleteAfterCopy = false;
   this.move = false;
   this.zip = false;
 
+  // TODO(hidehiko): After we support recursive copy, we don't need this.
   // If directory already exists, we try to make a copy named 'dir (X)',
   // where X is a number. When we do this, all subsequent copies from
   // inside the subtree should be mapped to the new directory name.
@@ -348,92 +493,46 @@
   this.renamedDirectories_ = [];
 };
 
-
 /**
  * @param {Array.<Entry>} entries Entries.
  * @param {function()} callback When entries resolved.
  */
 FileCopyManager.Task.prototype.setEntries = function(entries, callback) {
-  var self = this;
   this.originalEntries = entries;
+
   // When moving directories, FileEntry.moveTo() is used if both source
   // and target are on Drive. There is no need to recurse into directories.
   util.recurseAndResolveEntries(entries, !this.move, function(result) {
-    self.pendingDirectories = result.dirEntries;
-    self.pendingFiles = result.fileEntries;
-    self.totalBytes = result.fileBytes;
-    self.completedBytes = 0;
+    if (this.move) {
+      // This may be moving from search results, where it fails if we move
+      // parent entries earlier than child entries. We should process the
+      // deepest entry first. Since move of each entry is done by a single
+      // moveTo() call, we don't need to care about the recursive traversal
+      // order.
+      this.entries = result.dirEntries.concat(result.fileEntries).sort(
+          function(entry1, entry2) {
+            return entry2.fullPath.length - entry1.fullPath.length;
+          });
+    } else {
+      // Copying tasks are recursively processed. So, directories must be
+      // processed earlier than their child files. Since
+      // util.recurseAndResolveEntries is already listing entries in the
+      // recursive traversal order, we just keep the ordering.
+      this.entries = result.dirEntries.concat(result.fileEntries);
+    }
 
+    this.totalBytes = result.fileBytes;
     callback();
-  });
-};
-
-/**
- * @return {Entry} Next entry.
- */
-FileCopyManager.Task.prototype.getNextEntry = function() {
-  // We should keep the file in pending list and remove it after complete.
-  // Otherwise, if we try to get status in the middle of copying. The returned
-  // status is wrong (miss count the pasting item in totalItems).
-  var nextEntry = null;
-  if (this.move) {
-    // This may be moving from search results, where it fails if we move parent
-    // entries earlier than child entries. We should process the deepest entry
-    // first. Since move of each entry is done by a single .MoveTo() call, we
-    // don't need to care about the recursive traversal order.
-    nextEntry = this.getDeepestEntry_();
-  } else {
-    // Copying tasks are recursively processed. So, directories must be
-    // processed earlier than their child files. Since
-    // util.recurseAndResolveEntries is already listing entries in the recursive
-    // traversal order, we just keep the ordering.
-    if (this.pendingDirectories.length)
-      nextEntry = this.pendingDirectories[0];
-    else if (this.pendingFiles.length)
-      nextEntry = this.pendingFiles[0];
-  }
-  if (nextEntry)
-    nextEntry.inProgress = true;
-  return nextEntry;
-};
-
-/**
- * Remove the completed entry from the pending lists.
- * @param {Entry} entry Entry.
- * @param {number} size Bytes completed.
- */
-FileCopyManager.Task.prototype.markEntryComplete = function(entry, size) {
-  if (entry.isDirectory && this.pendingDirectories) {
-    for (var i = 0; i < this.pendingDirectories.length; i++) {
-      if (this.pendingDirectories[i].inProgress) {
-        this.completedDirectories.push(entry);
-        this.pendingDirectories.splice(i, 1);
-        return;
-      }
-    }
-  } else if (this.pendingFiles) {
-    for (var i = 0; i < this.pendingFiles.length; i++) {
-      if (this.pendingFiles[i].inProgress) {
-        this.completedFiles.push(entry);
-        this.completedBytes += size;
-        this.pendingFiles.splice(i, 1);
-        return;
-      }
-    }
-  }
-  throw new Error('Try to remove a source entry which is not correspond to' +
-                  ' the finished target entry');
+  }.bind(this));
 };
 
 /**
  * Updates copy progress status for the entry.
  *
- * @param {Entry} entry Entry which is being coppied.
  * @param {number} size Number of bytes that has been copied since last update.
  */
-FileCopyManager.Task.prototype.updateFileCopyProgress = function(entry, size) {
-  if (entry.isFile && this.pendingFiles && this.pendingFiles[0].inProgress)
-    this.completedBytes += size;
+FileCopyManager.Task.prototype.updateFileCopyProgress = function(size) {
+  this.completedBytes += size;
 };
 
 /**
@@ -465,26 +564,6 @@
 };
 
 /**
- * Obtains the deepest entry by referring to its full path.
- * @return {Entry} The deepest entry.
- * @private
- */
-FileCopyManager.Task.prototype.getDeepestEntry_ = function() {
-  var result = null;
-  for (var i = 0; i < this.pendingDirectories.length; i++) {
-    if (!result ||
-        this.pendingDirectories[i].fullPath.length > result.fullPath.length)
-    result = this.pendingDirectories[i];
-  }
-  for (var i = 0; i < this.pendingFiles.length; i++) {
-    if (!result ||
-        this.pendingFiles[i].fullPath.length > result.fullPath.length)
-    result = this.pendingFiles[i];
-  }
-  return result;
-};
-
-/**
  * Error class used to report problems with a copy operation.
  * If the code is UNEXPECTED_SOURCE_FILE, data should be a path of the file.
  * If the code is TARGET_EXISTS, data should be the existing Entry.
@@ -532,64 +611,47 @@
  * @return {Object} Status object.
  */
 FileCopyManager.prototype.getStatus = function() {
+  // TODO(hidehiko): Reorganize the structure when delete queue is merged
+  // into copy task queue.
   var rv = {
-    pendingItems: 0,  // Files + Directories
-    pendingFiles: 0,
-    pendingDirectories: 0,
-    pendingBytes: 0,
+    totalItems: 0,
+    completedItems: 0,
 
-    completedItems: 0,  // Files + Directories
-    completedFiles: 0,
-    completedDirectories: 0,
+    totalBytes: 0,
     completedBytes: 0,
 
-    percentage: NaN,
     pendingCopies: 0,
     pendingMoves: 0,
     pendingZips: 0,
-    filename: ''  // In case pendingItems == 1
+
+    // In case the number of the incompleted entry is exactly one.
+    filename: '',
   };
 
-  var pendingFile = null;
-
+  var pendingEntry = null;
   for (var i = 0; i < this.copyTasks_.length; i++) {
     var task = this.copyTasks_[i];
-    var pendingFiles = task.pendingFiles.length;
-    var pendingDirectories = task.pendingDirectories.length;
-    rv.pendingFiles += pendingFiles;
-    rv.pendingDirectories += pendingDirectories;
-    rv.pendingBytes += (task.totalBytes - task.completedBytes);
+    rv.totalItems += task.entries.length;
+    rv.completedItems += task.entryIndex;
 
-    rv.completedFiles += task.completedFiles.length;
-    rv.completedDirectories += task.completedDirectories.length;
+    rv.totalBytes += task.totalBytes;
     rv.completedBytes += task.completedBytes;
 
+    var numPendingEntries = task.entries.length - task.entryIndex;
     if (task.zip) {
-      rv.pendingZips += pendingFiles + pendingDirectories;
+      rv.pendingZips += numPendingEntries;
     } else if (task.move || task.deleteAfterCopy) {
-      rv.pendingMoves += pendingFiles + pendingDirectories;
+      rv.pendingMoves += numPendingEntries;
     } else {
-      rv.pendingCopies += pendingFiles + pendingDirectories;
+      rv.pendingCopies += numPendingEntries;
     }
 
-    if (task.pendingFiles.length === 1)
-      pendingFile = task.pendingFiles[0];
-
-    if (task.pendingDirectories.length === 1)
-      pendingFile = task.pendingDirectories[0];
-
+    if (numPendingEntries == 1)
+      pendingEntry = task.entries[task.entries.length - 1];
   }
-  rv.pendingItems = rv.pendingFiles + rv.pendingDirectories;
-  rv.completedItems = rv.completedFiles + rv.completedDirectories;
 
-  rv.totalFiles = rv.pendingFiles + rv.completedFiles;
-  rv.totalDirectories = rv.pendingDirectories + rv.completedDirectories;
-  rv.totalItems = rv.pendingItems + rv.completedItems;
-  rv.totalBytes = rv.pendingBytes + rv.completedBytes;
-
-  rv.percentage = rv.completedBytes / rv.totalBytes;
-  if (rv.pendingItems === 1)
-    rv.filename = pendingFile.name;
+  if (rv.totalItems - rv.completedItems == 1 && pendingEntry)
+    rv.filename = pendingEntry.name;
 
   return rv;
 };
@@ -932,7 +994,7 @@
     errorCallback) {
   // TODO(hidehiko): We should be able to share the code to iterate on entries
   // with serviceMoveTask_().
-  if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
+  if (task.entries.length == 0) {
     successCallback();
     return;
   }
@@ -962,9 +1024,11 @@
   };
 
   var onEntryServiced = function() {
+    task.entryIndex++;
+
     // We should not dispatch a PROGRESS event when there is no pending items
     // in the task.
-    if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
+    if (task.entryIndex >= task.entries.length) {
       if (task.deleteAfterCopy) {
         deleteOriginals();
       } else {
@@ -975,13 +1039,13 @@
 
     progressCallback();
     self.processCopyEntry_(
-        task, task.getNextEntry(), entryChangedCallback, progressCallback,
-        onEntryServiced, errorCallback);
+        task, task.entries[task.entryIndex], entryChangedCallback,
+        progressCallback, onEntryServiced, errorCallback);
   };
 
   this.processCopyEntry_(
-      task, task.getNextEntry(), entryChangedCallback, progressCallback,
-      onEntryServiced, errorCallback);
+      task, task.entries[task.entryIndex], entryChangedCallback,
+      progressCallback, onEntryServiced, errorCallback);
 };
 
 /**
@@ -1022,9 +1086,8 @@
   originalPath = task.applyRenames(originalPath);
 
   var onDeduplicated = function(targetRelativePath) {
-    var onCopyComplete = function(entry, size) {
+    var onCopyComplete = function(entry) {
       entryChangedCallback(util.EntryChangedType.CREATED, entry);
-      task.markEntryComplete(entry, size);
       successCallback();
     };
 
@@ -1042,57 +1105,24 @@
             if (targetRelativePath != originalPath) {
               task.registerRename(originalPath, targetRelativePath);
             }
-            onCopyComplete(targetEntry, 0);
+            onCopyComplete(targetEntry);
           },
           util.flog('Error getting dir: ' + targetRelativePath,
                     onFilesystemError));
-      return;
-    }
-
-    var onCopyProgress = function(entry, size) {
-      task.updateFileCopyProgress(entry, size);
-      progressCallback();
-    };
-
-    // Hereafter copy a file.
-    var isSourceOnDrive = PathUtil.isDriveBasedPath(sourceEntry.fullPath);
-    var isTargetOnDrive = PathUtil.isDriveBasedPath(targetDirEntry.fullPath);
-
-    if (!isSourceOnDrive && !isTargetOnDrive) {
-      // Sending a file from local to local.
-      // To copy local file, we use File blob and FileWriter to take the
-      // progress.
-      targetDirEntry.getFile(
-          targetRelativePath,
-          {create: true, exclusive: true},
-          function(targetEntry) {
-            self.cancelCallback_ = self.copyFileEntry_(
-                sourceEntry, targetEntry,
-                onCopyProgress,
-                function(entry, size) {
-                  self.cancelCallback_ = null;
-                  onCopyComplete(entry, size);
-                },
-                function(error) {
-                  self.cancelCallback_ = null;
-                  onFilesystemError(error);
-                });
-          },
-          util.flog('Error getting file: ' + targetRelativePath,
-                    onFilesystemError));
-      return;
     } else {
-      // Sending a file from a) Drive to Drive, b) Drive to local or c) local
-      // to Drive.
+      // Copy a file.
       targetDirEntry.getDirectory(
           PathUtil.dirname(targetRelativePath), {create: false},
           function(dirEntry) {
-            self.cancelCallback_ = fileOperationUtil.copyFileOnDrive(
+            self.cancelCallback_ = fileOperationUtil.copyFile(
                 sourceEntry, dirEntry, PathUtil.basename(targetRelativePath),
-                onCopyProgress,
+                function(entry, size) {
+                  task.updateFileCopyProgress(size);
+                  progressCallback();
+                },
                 function(entry) {
                   self.cancelCallback_ = null;
-                  onCopyComplete(entry, 0);
+                  onCopyComplete(entry);
                 },
                 function(error) {
                   self.cancelCallback_ = null;
@@ -1108,97 +1138,6 @@
 };
 
 /**
- * Copies the contents of sourceEntry into targetEntry.
- * TODO(hidehiko): Move this method into fileOperationUtil.
- *
- * @param {FileEntry} sourceEntry The file entry that will be copied.
- * @param {FileEntry} targetEntry The file entry to which sourceEntry will be
- *     copied.
- * @param {function(FileEntry, number)} progressCallback Function that will be
- *     called when a part of the source entry is copied. It takes |targetEntry|
- *     and size of the last copied chunk as parameters.
- * @param {function(FileEntry, number)} successCallback Function that will be
- *     called the copy operation finishes. It takes |targetEntry| and size of
- *     the last (not previously reported) copied chunk as parameters.
- * @param {function(FileError)} errorCallback Function that will be called
- *     if an error is encountered. Takes error type and additional error data
- *     as parameters.
- * @return {function()} Callback to cancel the current file copy operation.
- *     When the cancel is done, errorCallback will be called. The returned
- *     callback must not be called more than once.
- * @private
- */
-FileCopyManager.prototype.copyFileEntry_ = function(sourceEntry,
-                                                    targetEntry,
-                                                    progressCallback,
-                                                    successCallback,
-                                                    errorCallback) {
-  // Set to true when cancel is requested.
-  var cancelRequested = false;
-
-  sourceEntry.file(function(file) {
-    if (cancelRequested) {
-      errorCallback(util.createFileError(FileError.ABORT_ERR));
-      return;
-    }
-
-    targetEntry.createWriter(function(writer) {
-      if (cancelRequested) {
-        errorCallback(util.createFileError(FileError.ABORT_ERR));
-        return;
-      }
-
-      var reportedProgress = 0;
-      writer.onerror = writer.onabort = function(progress) {
-        errorCallback(cancelRequested ?
-            util.createFileError(FileError.ABORT_ERR) :
-            writer.error);
-      };
-
-      writer.onprogress = function(progress) {
-        if (cancelRequested) {
-          // If the copy was cancelled, we should abort the operation.
-          // The errorCallback will be called by writer.onabort after the
-          // termination.
-          writer.abort();
-          return;
-        }
-
-        // |progress.loaded| will contain total amount of data copied by now.
-        // |progressCallback| expects data amount delta from the last progress
-        // update.
-        progressCallback(targetEntry, progress.loaded - reportedProgress);
-        reportedProgress = progress.loaded;
-      };
-
-      writer.onwrite = function() {
-        if (cancelRequested) {
-          errorCallback(util.createFileError(FileError.ABORT_ERR));
-          return;
-        }
-
-        sourceEntry.getMetadata(function(metadata) {
-          if (cancelRequested) {
-            errorCallback(util.createFileError(FileError.ABORT_ERR));
-            return;
-          }
-
-          fileOperationUtil.setLastModified(
-              targetEntry, metadata.modificationTime);
-          successCallback(targetEntry, file.size - reportedProgress);
-        });
-      };
-
-      writer.write(file);
-    }, errorCallback);
-  }, errorCallback);
-
-  return function() {
-    cancelRequested = true;
-  };
-};
-
-/**
  * Moves all entries in the task.
  *
  * @param {FileCopyManager.Task} task A move task to be run.
@@ -1213,17 +1152,19 @@
 FileCopyManager.prototype.serviceMoveTask_ = function(
     task, entryChangedCallback, progressCallback, successCallback,
     errorCallback) {
-  if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
+  if (task.entries.length == 0) {
     successCallback();
     return;
   }
 
   this.processMoveEntry_(
-      task, task.getNextEntry(), entryChangedCallback,
+      task, task.entries[task.entryIndex], entryChangedCallback,
       (function onCompleted() {
+        task.entryIndex++;
+
         // We should not dispatch a PROGRESS event when there is no pending
         // items in the task.
-        if (task.pendingDirectories.length + task.pendingFiles.length == 0) {
+        if (task.entryIndex >= task.entries.length) {
           successCallback();
           return;
         }
@@ -1231,7 +1172,7 @@
         // Move the next entry.
         progressCallback();
         this.processMoveEntry_(
-            task, task.getNextEntry(), entryChangedCallback,
+            task, task.entries[task.entryIndex], entryChangedCallback,
             onCompleted.bind(this), errorCallback);
       }).bind(this),
       errorCallback);
@@ -1294,7 +1235,6 @@
                         util.EntryChangedType.CREATED, targetEntry);
                     entryChangedCallback(
                         util.EntryChangedType.DELETED, sourceEntry);
-                    task.markEntryComplete(targetEntry, 0);
                     successCallback();
                   },
                   onFilesystemError);
@@ -1335,7 +1275,7 @@
         progressCallback();
 
         fileOperationUtil.zipSelection(
-            task.pendingDirectories.concat(task.pendingFiles),
+            task.entries,
             task.zipBaseDirEntry,
             destPath,
             function(entry) {
diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js
index 093b23a..657a7f2 100644
--- a/chrome/browser/resources/file_manager/js/file_manager.js
+++ b/chrome/browser/resources/file_manager/js/file_manager.js
@@ -493,9 +493,9 @@
     this.gearButton_.addEventListener('menushow',
         this.refreshRemainingSpace_.bind(this,
                                          false /* Without loading caption. */));
-    cr.ui.decorate(this.gearButton_, cr.ui.MenuButton);
     this.dialogDom_.querySelector('#gear-menu').menuItemSelector =
       'menuitem, hr';
+    cr.ui.decorate(this.gearButton_, cr.ui.MenuButton);
 
     if (this.dialogType == DialogType.FULL_PAGE) {
       var maximizeButton = this.dialogDom_.querySelector('#maximize-button');
@@ -570,13 +570,13 @@
         Commands.changeDefaultAppCommand, this);
 
     CommandUtil.registerCommand(this.navigationList_, 'unmount',
-        Commands.unmountCommand, this.navigationList_, this);
+        Commands.unmountCommand, this);
 
     CommandUtil.registerCommand(this.navigationList_, 'import-photos',
         Commands.importCommand, this.navigationList_);
 
     CommandUtil.registerCommand(this.dialogContainer_, 'format',
-        Commands.formatCommand, this.navigationList_, this,
+        Commands.formatCommand, this,
         this.directoryModel_);
 
     CommandUtil.registerCommand(this.dialogContainer_, 'delete',
diff --git a/chrome/browser/resources/file_manager/js/file_manager_commands.js b/chrome/browser/resources/file_manager/js/file_manager_commands.js
index 67d781b..914c7c5 100644
--- a/chrome/browser/resources/file_manager/js/file_manager_commands.js
+++ b/chrome/browser/resources/file_manager/js/file_manager_commands.js
@@ -171,19 +171,18 @@
 Commands.unmountCommand = {
   /**
    * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
+   * @param {FileManager} fileManager The file manager instance.
    */
-  execute: function(event, navigationList, fileManager) {
-    var root = CommandUtil.getCommandPath(navigationList);
+  execute: function(event, fileManager) {
+    var root = CommandUtil.getCommandPath(event.target);
     if (root)
       fileManager.unmountVolume(PathUtil.getRootPath(root));
   },
   /**
    * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
    */
-  canExecute: function(event, navigationList) {
-    var rootType = CommandUtil.getCommandRootType(navigationList);
+  canExecute: function(event) {
+    var rootType = CommandUtil.getCommandRootType(event.target);
 
     event.canExecute = (rootType == RootType.ARCHIVE ||
                         rootType == RootType.REMOVABLE);
@@ -200,11 +199,10 @@
 Commands.formatCommand = {
   /**
    * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
    * @param {FileManager} fileManager The file manager instance.
    */
-  execute: function(event, navigationList, fileManager) {
-    var root = CommandUtil.getCommandPath(navigationList);
+  execute: function(event, fileManager) {
+    var root = CommandUtil.getCommandPath(event.target);
 
     if (root) {
       var url = util.makeFilesystemUrl(PathUtil.getRootPath(root));
@@ -215,12 +213,11 @@
   },
   /**
    * @param {Event} event Command event.
-   * @param {NavigationList} navigationList Target navigation list.
    * @param {FileManager} fileManager The file manager instance.
    * @param {DirectoryModel} directoryModel The directory model instance.
    */
-  canExecute: function(event, navigationList, fileManager, directoryModel) {
-    var root = CommandUtil.getCommandPath(navigationList);
+  canExecute: function(event, fileManager, directoryModel) {
+    var root = CommandUtil.getCommandPath(event.target);
     var removable = root &&
                     PathUtil.getRootType(root) == RootType.REMOVABLE;
     var isReadOnly = root && directoryModel.isPathReadOnly(root);
@@ -599,7 +596,7 @@
     var eligible = path && PathUtil.isEligibleForFolderShortcut(path);
     event.canExecute =
         eligible && onlyOneFolderSelected && !folderShortcutExists;
-    event.command.setHidden(!onlyOneFolderSelected);
+    event.command.setHidden(!eligible || !onlyOneFolderSelected);
   }
 };
 
@@ -635,7 +632,7 @@
     var eligible = path && PathUtil.isEligibleForFolderShortcut(path);
     var isShortcut = path && fileManager.folderShortcutExists(path);
     event.canExecute = isShortcut && eligible;
-    event.command.setHidden(!isShortcut);
+    event.command.setHidden(!event.canExecute);
   }
 };
 
diff --git a/chrome/browser/resources/file_manager/js/file_tasks.js b/chrome/browser/resources/file_manager/js/file_tasks.js
index e6072ee..fd72362 100644
--- a/chrome/browser/resources/file_manager/js/file_tasks.js
+++ b/chrome/browser/resources/file_manager/js/file_tasks.js
@@ -286,7 +286,7 @@
     }.bind(this);
 
     this.checkAvailability_(function() {
-      chrome.fileBrowserPrivate.viewFiles(urls, 'default', callback);
+      chrome.fileBrowserPrivate.viewFiles(urls, callback);
     }.bind(this));
   }
 
@@ -448,7 +448,7 @@
 
   if (id == 'view-pdf' || id == 'view-swf' || id == 'view-in-browser' ||
       id == 'install-crx' || id.match(/^open-hosted-/) || id == 'watch') {
-    chrome.fileBrowserPrivate.viewFiles(urls, id, function(success) {
+    chrome.fileBrowserPrivate.viewFiles(urls, function(success) {
       if (!success)
         console.error('chrome.fileBrowserPrivate.viewFiles failed', urls);
     });
diff --git a/chrome/browser/resources/file_manager/js/navigation_list.js b/chrome/browser/resources/file_manager/js/navigation_list.js
index 9e2f357..476fe6d 100644
--- a/chrome/browser/resources/file_manager/js/navigation_list.js
+++ b/chrome/browser/resources/file_manager/js/navigation_list.js
@@ -85,26 +85,6 @@
 };
 
 /**
- * Type of the item on the navigation list.
- * @enum {number}
- */
-NavigationListModel.ItemType = {
-  ROOT: 1,
-  PINNED: 2
-};
-
-/**
- * Returns the type of the item at the given index.
- * @param {number} index The index of the entry to get.
- * @return {NavigationListModel.ItemType} The type of the item.
- */
-NavigationListModel.prototype.getItemType = function(index) {
-  var offset = this.volumesList_.length;
-  return index < offset ?
-      NavigationListModel.ItemType.ROOT : NavigationListModel.ItemType.PINNED;
-};
-
-/**
  * Returns the number of items in the model.
  * @return {number} The length of the model.
  * @private
diff --git a/chrome/browser/resources/file_manager/js/path_util.js b/chrome/browser/resources/file_manager/js/path_util.js
index c22013b..774cb13 100644
--- a/chrome/browser/resources/file_manager/js/path_util.js
+++ b/chrome/browser/resources/file_manager/js/path_util.js
@@ -341,5 +341,6 @@
  */
 PathUtil.isEligibleForFolderShortcut = function(directoryPath) {
   return !PathUtil.isSpecialSearchRoot(directoryPath) &&
-         !PathUtil.isRootPath(directoryPath);
+         !PathUtil.isRootPath(directoryPath) &&
+         PathUtil.isDriveBasedPath(directoryPath);
 };
diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js
index 2023266..966c8e6 100644
--- a/chrome/browser/resources/file_manager/js/util.js
+++ b/chrome/browser/resources/file_manager/js/util.js
@@ -1176,3 +1176,26 @@
     code: { get: function() { return code; } }
   });
 };
+
+/**
+ * @param {Entry|Object} entry1 The entry to be compared. Can be a fake.
+ * @param {Entry|Object} entry2 The entry to be compared. Can be a fake.
+ * @return {boolean} True if the both entry represents a same file or directory.
+ */
+util.isSameEntry = function(entry1, entry2) {
+  // Currently, we can assume there is only one root.
+  // When we support multi-file system, we need to look at filesystem, too.
+  return entry1.fullPath == entry2.fullPath;
+};
+
+/**
+ * @param {Entry|Object} parent The parent entry. Can be a fake.
+ * @param {Entry|Object} child The child entry. Can be a fake.
+ * @return {boolean} True if parent entry is actualy the parent of the child
+ *     entry.
+ */
+util.isParentEntry = function(parent, child) {
+  // Currently, we can assume there is only one root.
+  // When we support multi-file system, we need to look at filesystem, too.
+  return PathUtil.isParentPath(parent.fullPath, child.fullPath);
+};
diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html
index 7bcc2fd..d2b05db 100644
--- a/chrome/browser/resources/file_manager/main.html
+++ b/chrome/browser/resources/file_manager/main.html
@@ -215,16 +215,18 @@
     </menu>
 
     <menu id="gear-menu" class="chrome-menu" showShortcuts>
-      <menuitem command="#newwindow"></menuitem>
-      <menuitem command="#newfolder"></menuitem>
-      <menuitem command="#change-default-app"></menuitem>
+      <menuitem id="gear-menu-newwindow" command="#newwindow"></menuitem>
+      <menuitem id="gear-menu-newfolder" command="#newfolder"></menuitem>
+      <menuitem id="gear-menu-change-default-app"
+                command="#change-default-app"></menuitem>
       <hr id="drive-separator">
       <menuitem id="drive-sync-settings"
                 i18n-content=DRIVE_MOBILE_CONNECTION_OPTION></menuitem>
       <menuitem id="drive-hosted-settings"
                 i18n-content=DRIVE_SHOW_HOSTED_FILES_OPTION></menuitem>
       <hr command="#drive-clear-local-cache">
-      <menuitem command="#drive-clear-local-cache"></menuitem>
+      <menuitem id="gear-menu-drive-clear-local-cache"
+                command="#drive-clear-local-cache"></menuitem>
       <hr>
       <div>
         View
@@ -236,9 +238,12 @@
               i18n-values="aria-label:THUMBNAIL_VIEW_TOOLTIP">
       </menuitem>
       <hr>
-      <menuitem command="#drive-buy-more-space"></menuitem>
-      <menuitem command="#drive-go-to-drive"></menuitem>
-      <menuitem command="#volume-help"></menuitem>
+      <menuitem id="gear-menu-drive-buy-more-space"
+                command="#drive-buy-more-space"></menuitem>
+      <menuitem id="gear-menu-drive-go-to-drive"
+                command="#drive-go-to-drive"></menuitem>
+      <menuitem id="gear-menu-volume-help"
+                command="#volume-help"></menuitem>
       <hr>
       <div id="volume-space-info">
         <div id="volume-space-info-contents">
@@ -295,7 +300,8 @@
           <div class="buttonbar">
             <button class="menubutton" id="gear-button" tabindex="10"
                     menu="#gear-menu"
-                    i18n-values="aria-label:GEAR_BUTTON_TOOLTIP">
+                    i18n-values="aria-label:GEAR_BUTTON_TOOLTIP"
+                    aria-activedescendant="gear-menu">
             </button>
             <button id="maximize-button" visibleif="full-page" tabindex="-1">
             </button>
diff --git a/chrome/browser/resources/google_now/utility.js b/chrome/browser/resources/google_now/utility.js
index 7a8b2b1..0ab7c4b 100644
--- a/chrome/browser/resources/google_now/utility.js
+++ b/chrome/browser/resources/google_now/utility.js
@@ -257,6 +257,9 @@
     return function() {
       // This is the wrapper for the callback.
       try {
+        verify(!isInInstrumentedCallback, 'Re-entering instrumented callback');
+        isInInstrumentedCallback = true;
+
         if (isTaskCallback) {
           verify(!isInTask, 'wrapCallback: already in task');
           isInTask = true;
@@ -265,12 +268,7 @@
           delete pendingCallbacks[callbackId];
 
         // Call the original callback.
-        verify(!isInInstrumentedCallback, 'Re-entering instrumented callback');
-        isInInstrumentedCallback = true;
         callback.apply(null, arguments);
-        verify(isInInstrumentedCallback,
-               'Instrumented callback is not instrumented upon exit');
-        isInInstrumentedCallback = false;
 
         if (isTaskCallback) {
           verify(isInTask, 'wrapCallback: not in task at exit');
@@ -278,6 +276,10 @@
           if (--taskPendingCallbackCount == 0)
             finish();
         }
+
+        verify(isInInstrumentedCallback,
+               'Instrumented callback is not instrumented upon exit');
+        isInInstrumentedCallback = false;
       } catch (error) {
         var message = 'Uncaught exception:\n' + error.stack;
         console.error(message);
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 6316a17..83775d83 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -101,9 +101,32 @@
 
 a {
   color: rgb(17, 85, 204);
+  padding: 0 3px;
   text-decoration: none;
 }
 
+a.disabled {
+  opacity: 0.5;
+  pointer-events: none;
+}
+
+.open {
+  margin-bottom: -4px;
+  margin-top: 5px;
+}
+
+.open > input {
+  border: 1px solid #aaa;
+  height: 17px;
+  line-height: 17px;
+  margin-left: 20px;
+  padding: 0 2px;
+}
+
+.open > button {
+  line-height: 13px;
+}
+
 #port-forwarding-settings {
   position: absolute;
   right: 20px;
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 856744b..8ce04b8 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -10,6 +10,14 @@
   chrome.send('terminate', [data]);
 }
 
+function reload(data) {
+  chrome.send('reload', [data]);
+}
+
+function open(browserId, url) {
+  chrome.send('open', [browserId, url]);
+}
+
 function removeChildren(element_id) {
   var element = $(element_id);
   element.textContent = '';
@@ -77,43 +85,122 @@
 }
 
 function populateDeviceLists(devices) {
-  var devicesDigest = JSON.stringify(devices);
-  if (!devices || devicesDigest == window.devicesDigest)
+  if (!devices)
     return;
 
-  window.devicesDigest = devicesDigest;
+  function alreadyDisplayed(element, data) {
+    var json = JSON.stringify(data);
+    if (element.cachedJSON == json)
+      return true;
+    element.cachedJSON = json;
+    return false;
+  }
 
-  var containerElement = $('devices');
-  containerElement.textContent = '';
+  var deviceList = $('devices');
+  if (alreadyDisplayed(deviceList, devices))
+    return;
 
-  // Populate with new entries
+  function removeObsolete(validIds, section) {
+    if (validIds.indexOf(section.id) < 0)
+      section.remove();
+  }
+
+  var newDeviceIds = devices.map(function(d) { return d.adbGlobalId });
+  Array.prototype.forEach.call(
+      deviceList.querySelectorAll('.device'),
+      removeObsolete.bind(null, newDeviceIds));
+
   for (var d = 0; d < devices.length; d++) {
     var device = devices[d];
 
-    var deviceHeader = document.createElement('div');
-    deviceHeader.className = 'section';
-    deviceHeader.textContent = device.adbModel;
-    containerElement.appendChild(deviceHeader);
+    var browserList;
+    var deviceSection = $(device.adbGlobalId);
+    if (deviceSection) {
+      browserList = deviceSection.querySelector('.browsers');
+    } else {
+      deviceSection = document.createElement('div');
+      deviceSection.id = device.adbGlobalId;
+      deviceSection.className = 'device list';
+      deviceList.appendChild(deviceSection);
 
-    var deviceContent = document.createElement('div');
-    deviceContent.className = 'list';
-    containerElement.appendChild(deviceContent);
+      var deviceHeader = document.createElement('div');
+      deviceHeader.className = 'section';
+      deviceHeader.textContent = device.adbModel;
+      deviceSection.appendChild(deviceHeader);
+
+      browserList = document.createElement('div');
+      browserList.className = 'browsers';
+      deviceSection.appendChild(browserList);
+    }
+
+    if (alreadyDisplayed(deviceSection, device))
+      continue;
+
+    var newBrowserIds =
+        device.browsers.map(function(b) { return b.adbGlobalId });
+    Array.prototype.forEach.call(
+        browserList.querySelectorAll('.browser'),
+        removeObsolete.bind(null, newBrowserIds));
 
     for (var b = 0; b < device.browsers.length; b++) {
       var browser = device.browsers[b];
 
-      var browserHeader = document.createElement('div');
-      browserHeader.className = 'small-section';
-      browserHeader.textContent = browser.adbBrowserName;
-      deviceContent.appendChild(browserHeader);
+      var pageList;
+      var browserSection = $(browser.adbGlobalId);
+      if (browserSection) {
+        pageList = browserSection.querySelector('.pages');
+        pageList.textContent = '';
+      } else {
+        browserSection = document.createElement('div');
+        browserSection.id = browser.adbGlobalId;
+        browserSection.className = 'browser';
+        browserList.appendChild(browserSection);
 
-      var browserPages = document.createElement('div');
-      browserPages.className = 'list package';
-      deviceContent.appendChild(browserPages);
+        var browserHeader = document.createElement('div');
+        browserHeader.className = 'small-section';
+        browserHeader.textContent = browser.adbBrowserName;
+        browserSection.appendChild(browserHeader);
+
+        var newPage = document.createElement('div');
+        newPage.className = 'open';
+
+        var newPageUrl = document.createElement('input');
+        newPageUrl.type = 'text';
+        newPageUrl.placeholder = 'Open tab with url';
+        newPage.appendChild(newPageUrl);
+
+        var openHandler = function(browserId, input) {
+          open(browserId, input.value || 'about:blank');
+          input.value = '';
+        }.bind(null, browser.adbGlobalId, newPageUrl);
+        newPageUrl.addEventListener('keyup', function(handler, event) {
+          if (event.keyIdentifier == 'Enter' && event.target.value)
+            handler();
+        }.bind(null, openHandler), true);
+
+        var newPageButton = document.createElement('button');
+        newPageButton.textContent = 'Open';
+        newPage.appendChild(newPageButton);
+        newPageButton.addEventListener('click', openHandler, true);
+
+        browserSection.appendChild(newPage);
+
+        pageList = document.createElement('div');
+        pageList.className = 'list pages';
+        browserSection.appendChild(pageList);
+      }
+
+      if (alreadyDisplayed(browserSection, browser))
+        continue;
 
       for (var p = 0; p < browser.pages.length; p++) {
-        addTargetToList(
-            browser.pages[p], browserPages, ['faviconUrl', 'name', 'url']);
+        var page = browser.pages[p];
+        var row = addTargetToList(
+            page, pageList, ['faviconUrl', 'name', 'url']);
+        row.appendChild(createActionLink(
+            'reload', reload.bind(null, page), page.attached));
+        row.appendChild(createActionLink(
+            'close', terminate.bind(null, page), page.attached));
       }
     }
   }
@@ -132,10 +219,9 @@
 }
 
 function addToWorkersList(data) {
-  addTargetToList(data,
-                  $('workers'),
-                  ['name', 'url', 'pid'],
-                  true);
+  var row = addTargetToList(data, $('workers'), ['name', 'url', 'pid']);
+  row.appendChild(createActionLink(
+      'terminate', terminate.bind(null, data), data.attached));
 }
 
 function addToOthersList(data) {
@@ -165,45 +251,31 @@
   return span;
 }
 
-function addTargetToList(data, list, properties, canTerminate) {
+function addTargetToList(data, list, properties) {
   var row = document.createElement('div');
   row.className = 'row';
   for (var j = 0; j < properties.length; j++)
     row.appendChild(formatValue(data, properties[j]));
 
-  row.appendChild(createInspectElement(data));
-
-  if (canTerminate)
-    row.appendChild(createTerminateElement(data));
+  row.appendChild(createActionLink('inspect', inspect.bind(null, data)));
 
   row.processId = data.processId;
   row.routeId = data.routeId;
 
   list.appendChild(row);
+  return row;
 }
 
-function createInspectElement(data) {
+function createActionLink(text, handler, opt_disabled) {
   var link = document.createElement('a');
-  link.setAttribute('href', '#');
-  link.textContent = ' inspect ';
-  link.addEventListener(
-      'click',
-      inspect.bind(this, data),
-      true);
-  return link;
-}
-
-function createTerminateElement(data) {
-  var link = document.createElement('a');
-  if (data.attached)
-    link.disabled = true;
+  if (opt_disabled)
+    link.classList.add('disabled');
+  else
+    link.classList.remove('disabled');
 
   link.setAttribute('href', '#');
-  link.textContent = ' terminate ';
-  link.addEventListener(
-      'click',
-      terminate.bind(this, data),
-      true);
+  link.textContent = text;
+  link.addEventListener('click', handler, true);
   return link;
 }
 
diff --git a/chrome/browser/resources/options/browser_options.css b/chrome/browser/resources/options/browser_options.css
index 6e24d02..13ad987 100644
--- a/chrome/browser/resources/options/browser_options.css
+++ b/chrome/browser/resources/options/browser_options.css
@@ -11,6 +11,7 @@
   max-width: 400px;
   overflow: hidden;
   text-overflow: ellipsis;
+  vertical-align: top;
 }
 
 #default-browser-state {
diff --git a/chrome/browser/resources/options/import_data_overlay.html b/chrome/browser/resources/options/import_data_overlay.html
index 526c811..2b78735 100644
--- a/chrome/browser/resources/options/import_data_overlay.html
+++ b/chrome/browser/resources/options/import_data_overlay.html
@@ -12,7 +12,8 @@
       <div id="import-checkboxes">
         <div i18n-content="importDescription"></div>
         <div class="checkbox">
-          <span class="controlled-setting-with-label">
+          <span id="import-history-with-label"
+              class="controlled-setting-with-label">
             <input id="import-history" type="checkbox" pref="import_history">
             <span>
               <label for="import-history" i18n-content="importHistory"></label>
@@ -22,7 +23,8 @@
           </span>
         </div>
         <div class="checkbox">
-          <span class="controlled-setting-with-label">
+          <span id="import-favorites-with-label"
+              class="controlled-setting-with-label">
             <input id="import-favorites" type="checkbox"
                 pref="import_bookmarks">
             <span>
@@ -35,7 +37,8 @@
           </span>
         </div>
         <div class="checkbox">
-          <span class="controlled-setting-with-label">
+          <span id="import-passwords-with-label"
+              class="controlled-setting-with-label">
             <input id="import-passwords" type="checkbox"
                 pref="import_saved_passwords">
             <span>
@@ -48,7 +51,8 @@
           </span>
         </div>
         <div class="checkbox">
-          <span class="controlled-setting-with-label">
+          <span id="import-search-with-label"
+              class="controlled-setting-with-label">
             <input id="import-search" type="checkbox"
                 pref="import_search_engine">
             <span>
diff --git a/chrome/browser/resources/options/import_data_overlay.js b/chrome/browser/resources/options/import_data_overlay.js
index ba7949c..8841b73 100644
--- a/chrome/browser/resources/options/import_data_overlay.js
+++ b/chrome/browser/resources/options/import_data_overlay.js
@@ -69,11 +69,11 @@
       };
 
       // Form controls are disabled until the profile list has been loaded.
-      self.setControlsSensitive_(false);
+      self.setAllControlsEnabled_(false);
     },
 
     /**
-     * Set enabled and checked state of the commit button.
+     * Sets the enabled and checked state of the commit button.
      * @private
      */
     validateCommitButton_: function() {
@@ -84,25 +84,29 @@
     },
 
     /**
-     * Sets the sensitivity of all the checkboxes and the commit button.
+     * Sets the enabled state of all the checkboxes and the commit button.
      * @private
      */
-    setControlsSensitive_: function(sensitive) {
+    setAllControlsEnabled_: function(enabled) {
       var checkboxes =
           document.querySelectorAll('#import-checkboxes input[type=checkbox]');
       for (var i = 0; i < checkboxes.length; i++)
-        this.setUpCheckboxState_(checkboxes[i], sensitive);
-      $('import-data-commit').disabled = !sensitive;
+        this.setUpCheckboxState_(checkboxes[i], enabled);
+      $('import-data-commit').disabled = !enabled;
     },
 
     /**
-     * Set enabled and checked states a checkbox element.
+     * Sets the enabled and checked states of a checkbox element.
      * @param {Object} checkbox A checkbox element.
-     * @param {boolean} enabled The enabled state of the chekbox.
+     * @param {boolean} enabled The enabled state of the checkbox. If false,
+     * the checkbox is disabled and unchecked. If true, the checkbox is enabled
+     * and checked.
+     * @param {boolean} visible The visible state of the checkbox.
      * @private
      */
     setUpCheckboxState_: function(checkbox, enabled) {
-       checkbox.setDisabled('noProfileData', !enabled);
+      checkbox.setDisabled('noProfileData', !enabled);
+      checkbox.checked = enabled;
     },
 
     /**
@@ -119,6 +123,8 @@
         var checkbox = $('import-' + importOptions[i]);
         var enable = browserProfile && browserProfile[importOptions[i]];
         this.setUpCheckboxState_(checkbox, enable);
+        var checkboxWithLabel = $('import-' + importOptions[i] + '-with-label');
+        checkboxWithLabel.style.display = enable ? '' : 'none';
       }
     },
 
@@ -138,9 +144,9 @@
         var option = new Option(loadTimeData.getString('noProfileFound'), 0);
         browserSelect.appendChild(option);
 
-        this.setControlsSensitive_(false);
+        this.setAllControlsEnabled_(false);
       } else {
-        this.setControlsSensitive_(true);
+        this.setAllControlsEnabled_(true);
         for (var i = 0; i < browserCount; i++) {
           var browser = browsers[i];
           var option = new Option(browser.name, browser.index);
diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js
index 025eba0..67fbe2f 100644
--- a/chrome/browser/resources/options/options_page.js
+++ b/chrome/browser/resources/options/options_page.js
@@ -277,11 +277,15 @@
     this.setTitle_(overlay.title);
 
     // Change focus to the overlay if any other control was focused by keyboard
-    // before.
-    if (document.activeElement != document.body &&
-        document.documentElement.classList.contains(
-            cr.ui.FocusOutlineManager.CLASS_NAME))
-      overlay.focus();
+    // before. Otherwise, no one should have focus.
+    if (document.activeElement != document.body) {
+      if (document.documentElement.classList.contains(
+          cr.ui.FocusOutlineManager.CLASS_NAME)) {
+        overlay.focus();
+      } else {
+        document.activeElement.blur();
+      }
+    }
 
     $('searchBox').setAttribute('aria-hidden', true);
 
diff --git a/chrome/browser/signin/signin_promo.cc b/chrome/browser/signin/signin_promo.cc
index cf8c4ae..729d6aa 100644
--- a/chrome/browser/signin/signin_promo.cc
+++ b/chrome/browser/signin/signin_promo.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/sync/profile_sync_service.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/ui/webui/options/core_options_handler.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
 #include "chrome/browser/ui/webui/theme_source.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/net/url_util.h"
@@ -80,12 +79,12 @@
 
 // Returns true if a user has seen the sign in promo at startup previously.
 bool HasShownPromoAtStartup(Profile* profile) {
-  return profile->GetPrefs()->HasPrefPath(prefs::kSyncPromoStartupCount);
+  return profile->GetPrefs()->HasPrefPath(prefs::kSignInPromoStartupCount);
 }
 
 // Returns true if the user has previously skipped the sign in promo.
 bool HasUserSkippedPromo(Profile* profile) {
-  return profile->GetPrefs()->GetBoolean(prefs::kSyncPromoUserSkipped);
+  return profile->GetPrefs()->GetBoolean(prefs::kSignInPromoUserSkipped);
 }
 
 }  // namespace
@@ -138,14 +137,14 @@
     return false;
 
   PrefService* prefs = profile->GetPrefs();
-  int show_count = prefs->GetInteger(prefs::kSyncPromoStartupCount);
+  int show_count = prefs->GetInteger(prefs::kSignInPromoStartupCount);
   if (show_count >= kSignInPromoShowAtStartupMaximum)
     return false;
 
   // This pref can be set in the master preferences file to allow or disallow
   // showing the sign in promo at startup.
-  if (prefs->HasPrefPath(prefs::kSyncPromoShowOnFirstRunAllowed))
-    return prefs->GetBoolean(prefs::kSyncPromoShowOnFirstRunAllowed);
+  if (prefs->HasPrefPath(prefs::kSignInPromoShowOnFirstRunAllowed))
+    return prefs->GetBoolean(prefs::kSignInPromoShowOnFirstRunAllowed);
 
   // For now don't show the promo for some brands.
   if (!AllowPromoAtStartupForCurrentBrand())
@@ -161,13 +160,13 @@
 
 void DidShowPromoAtStartup(Profile* profile) {
   int show_count = profile->GetPrefs()->GetInteger(
-      prefs::kSyncPromoStartupCount);
+      prefs::kSignInPromoStartupCount);
   show_count++;
-  profile->GetPrefs()->SetInteger(prefs::kSyncPromoStartupCount, show_count);
+  profile->GetPrefs()->SetInteger(prefs::kSignInPromoStartupCount, show_count);
 }
 
 void SetUserSkippedPromo(Profile* profile) {
-  profile->GetPrefs()->SetBoolean(prefs::kSyncPromoUserSkipped, true);
+  profile->GetPrefs()->SetBoolean(prefs::kSignInPromoUserSkipped, true);
 }
 
 GURL GetLandingURL(const char* option, int value) {
@@ -255,28 +254,22 @@
 
 void RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
-  // TODO(fdoray): Rename these preferences to start with kSignInPromo.
-  // (crbug.com/264283)
   registry->RegisterIntegerPref(
-      prefs::kSyncPromoStartupCount,
+      prefs::kSignInPromoStartupCount,
       0,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
-      prefs::kSyncPromoUserSkipped,
+      prefs::kSignInPromoUserSkipped,
       false,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
-      prefs::kSyncPromoShowOnFirstRunAllowed,
+      prefs::kSignInPromoShowOnFirstRunAllowed,
       true,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
   registry->RegisterBooleanPref(
-      prefs::kSyncPromoShowNTPBubble,
+      prefs::kSignInPromoShowNTPBubble,
       false,
       user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
-  registry->RegisterStringPref(
-      prefs::kSyncPromoErrorMessage,
-      std::string(),
-      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
 }
 
 }  // namespace signin
diff --git a/chrome/browser/signin/signin_promo.h b/chrome/browser/signin/signin_promo.h
index 9005f42..164cbbc 100644
--- a/chrome/browser/signin/signin_promo.h
+++ b/chrome/browser/signin/signin_promo.h
@@ -19,7 +19,6 @@
 // Utility functions for sign in promos.
 namespace signin {
 
-// Please keep this in sync with enums in sync_promo_trial.cc.
 enum Source {
   SOURCE_START_PAGE = 0, // This must be first.
   SOURCE_NTP_LINK,
diff --git a/chrome/browser/spellchecker/feedback.cc b/chrome/browser/spellchecker/feedback.cc
index 4cbdd5e..42bebbc 100644
--- a/chrome/browser/spellchecker/feedback.cc
+++ b/chrome/browser/spellchecker/feedback.cc
@@ -1,6 +1,18 @@
 // 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.
+//
+// The |Feedback| object keeps track of each instance of user feedback in a map
+// |misspellings_|. This is a map from uint32 hashes to |Misspelling| objects.
+//
+// Each misspelling should be present in only one renderer process. The
+// |Feedback| objects keeps track of misspelling-renderer relationship in the
+// |renderers_| map of renderer process identifiers to a set of hashes.
+//
+// When the user adds a misspelling to their custom dictionary, all of the
+// |Misspelling| objects with the same misspelled string are updated. The
+// |Feedback| object facilitates efficient access to these misspellings through
+// a |text_| map of misspelled strings to a set of hashes.
 
 #include "chrome/browser/spellchecker/feedback.h"
 
@@ -16,76 +28,86 @@
 }
 
 Misspelling* Feedback::GetMisspelling(uint32 hash) {
-  HashMisspellingMap::iterator it = misspellings_.find(hash);
-  if (it == misspellings_.end())
+  HashMisspellingMap::iterator misspelling_it = misspellings_.find(hash);
+  if (misspelling_it == misspellings_.end())
     return NULL;
-  return &it->second;
+  return &misspelling_it->second;
 }
 
 void Feedback::FinalizeRemovedMisspellings(
     int renderer_process_id,
     const std::vector<uint32>& remaining_markers) {
-  RendererHashesMap::iterator i = renderers_.find(renderer_process_id);
-  if (i == renderers_.end() || i->second.empty())
+  RendererHashesMap::iterator renderer_it =
+      renderers_.find(renderer_process_id);
+  if (renderer_it == renderers_.end() || renderer_it->second.empty())
     return;
-  HashCollection remaining_set(remaining_markers.begin(),
-                               remaining_markers.end());
-  std::vector<uint32> removed_markers;
-  std::set_difference(i->second.begin(),
-                      i->second.end(),
-                      remaining_set.begin(),
-                      remaining_set.end(),
-                      std::back_inserter(removed_markers));
-  for (std::vector<uint32>::const_iterator j = removed_markers.begin();
-       j != removed_markers.end();
-       ++j) {
-    HashMisspellingMap::iterator k = misspellings_.find(*j);
-    if (k != misspellings_.end() && !k->second.action.IsFinal())
-      k->second.action.Finalize();
+  HashCollection& renderer_hashes = renderer_it->second;
+  HashCollection remaining_hashes(remaining_markers.begin(),
+                                  remaining_markers.end());
+  std::vector<uint32> removed_hashes;
+  std::set_difference(renderer_hashes.begin(),
+                      renderer_hashes.end(),
+                      remaining_hashes.begin(),
+                      remaining_hashes.end(),
+                      std::back_inserter(removed_hashes));
+  for (std::vector<uint32>::const_iterator hash_it = removed_hashes.begin();
+       hash_it != removed_hashes.end();
+       ++hash_it) {
+    HashMisspellingMap::iterator misspelling_it = misspellings_.find(*hash_it);
+    if (misspelling_it != misspellings_.end() &&
+        !misspelling_it->second.action.IsFinal()) {
+      misspelling_it->second.action.Finalize();
+    }
   }
 }
 
 bool Feedback::RendererHasMisspellings(int renderer_process_id) const {
-  RendererHashesMap::const_iterator it = renderers_.find(renderer_process_id);
-  return it != renderers_.end() && !it->second.empty();
+  RendererHashesMap::const_iterator renderer_it =
+      renderers_.find(renderer_process_id);
+  return renderer_it != renderers_.end() && !renderer_it->second.empty();
 }
 
 std::vector<Misspelling> Feedback::GetMisspellingsInRenderer(
     int renderer_process_id) const {
-  std::vector<Misspelling> result;
-  RendererHashesMap::const_iterator i = renderers_.find(renderer_process_id);
-  if (i == renderers_.end() || i->second.empty())
-    return result;
-  for (HashCollection::const_iterator j = i->second.begin();
-       j != i->second.end();
-       ++j) {
-    HashMisspellingMap::const_iterator k = misspellings_.find(*j);
-    if (k != misspellings_.end())
-      result.push_back(k->second);
+  std::vector<Misspelling> misspellings_in_renderer;
+  RendererHashesMap::const_iterator renderer_it =
+      renderers_.find(renderer_process_id);
+  if (renderer_it == renderers_.end() || renderer_it->second.empty())
+    return misspellings_in_renderer;
+  const HashCollection& renderer_hashes = renderer_it->second;
+  for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
+       hash_it != renderer_hashes.end();
+       ++hash_it) {
+    HashMisspellingMap::const_iterator misspelling_it =
+        misspellings_.find(*hash_it);
+    if (misspelling_it != misspellings_.end())
+      misspellings_in_renderer.push_back(misspelling_it->second);
   }
-  return result;
+  return misspellings_in_renderer;
 }
 
 void Feedback::EraseFinalizedMisspellings(int renderer_process_id) {
-  RendererHashesMap::iterator i = renderers_.find(renderer_process_id);
-  if (i == renderers_.end() || i->second.empty())
+  RendererHashesMap::iterator renderer_it =
+      renderers_.find(renderer_process_id);
+  if (renderer_it == renderers_.end())
     return;
-  HashCollection pending;
-  for (HashCollection::const_iterator j = i->second.begin();
-       j != i->second.end();
-       ++j) {
-    HashMisspellingMap::iterator k = misspellings_.find(*j);
-    if (k != misspellings_.end()) {
-      if (k->second.action.IsFinal()) {
-        text_[k->second.context.substr(k->second.location, k->second.length)]
-            .erase(k->first);
-        misspellings_.erase(k);
-      } else {
-        pending.insert(*j);
-      }
-    }
+  HashCollection& renderer_hashes = renderer_it->second;
+  for (HashCollection::const_iterator hash_it = renderer_hashes.begin();
+       hash_it != renderer_hashes.end();) {
+    HashMisspellingMap::iterator misspelling_it = misspellings_.find(*hash_it);
+    HashCollection::iterator erasable_hash_it = hash_it;
+    ++hash_it;
+    if (misspelling_it == misspellings_.end())
+      continue;
+    const Misspelling& misspelling = misspelling_it->second;
+    if (!misspelling.action.IsFinal())
+      continue;
+    renderer_hashes.erase(erasable_hash_it);
+    text_[misspelling.GetMisspelledString()].erase(misspelling.hash);
+    misspellings_.erase(misspelling_it);
   }
-  i->second.swap(pending);
+  if (renderer_hashes.empty())
+    renderers_.erase(renderer_it);
 }
 
 bool Feedback::HasMisspelling(uint32 hash) const {
@@ -94,10 +116,24 @@
 
 void Feedback::AddMisspelling(int renderer_process_id,
                               const Misspelling& misspelling) {
+  HashMisspellingMap::iterator misspelling_it =
+      misspellings_.find(misspelling.hash);
+  if (misspelling_it != misspellings_.end()) {
+    const Misspelling& existing_misspelling = misspelling_it->second;
+    text_[existing_misspelling.GetMisspelledString()].erase(misspelling.hash);
+    for (RendererHashesMap::iterator renderer_it = renderers_.begin();
+         renderer_it != renderers_.end();) {
+      HashCollection& renderer_hashes = renderer_it->second;
+      RendererHashesMap::iterator erasable_renderer_it = renderer_it;
+      ++renderer_it;
+      renderer_hashes.erase(misspelling.hash);
+      if (renderer_hashes.empty())
+        renderers_.erase(erasable_renderer_it);
+    }
+  }
   misspellings_[misspelling.hash] = misspelling;
+  text_[misspelling.GetMisspelledString()].insert(misspelling.hash);
   renderers_[renderer_process_id].insert(misspelling.hash);
-  text_[misspelling.context.substr(
-      misspelling.location, misspelling.length)].insert(misspelling.hash);
 }
 
 bool Feedback::Empty() const {
@@ -105,44 +141,46 @@
 }
 
 std::vector<int> Feedback::GetRendersWithMisspellings() const {
-  std::vector<int> result;
-  for (RendererHashesMap::const_iterator it = renderers_.begin();
-       it != renderers_.end();
-       ++it) {
-    if (!it->second.empty())
-      result.push_back(it->first);
+  std::vector<int> renderers_with_misspellings;
+  for (RendererHashesMap::const_iterator renderer_it = renderers_.begin();
+       renderer_it != renderers_.end();
+       ++renderer_it) {
+    if (!renderer_it->second.empty())
+      renderers_with_misspellings.push_back(renderer_it->first);
   }
-  return result;
+  return renderers_with_misspellings;
 }
 
 void Feedback::FinalizeAllMisspellings() {
-  for (HashMisspellingMap::iterator it = misspellings_.begin();
-       it != misspellings_.end();
-       ++it) {
-    if (!it->second.action.IsFinal())
-      it->second.action.Finalize();
+  for (HashMisspellingMap::iterator misspelling_it = misspellings_.begin();
+       misspelling_it != misspellings_.end();
+       ++misspelling_it) {
+    if (!misspelling_it->second.action.IsFinal())
+      misspelling_it->second.action.Finalize();
   }
 }
 
 std::vector<Misspelling> Feedback::GetAllMisspellings() const {
-  std::vector<Misspelling> result;
-  for (HashMisspellingMap::const_iterator it = misspellings_.begin();
-       it != misspellings_.end();
-       ++it) {
-    result.push_back(it->second);
+  std::vector<Misspelling> all_misspellings;
+  for (HashMisspellingMap::const_iterator misspelling_it =
+           misspellings_.begin();
+       misspelling_it != misspellings_.end();
+       ++misspelling_it) {
+    all_misspellings.push_back(misspelling_it->second);
   }
-  return result;
+  return all_misspellings;
 }
 
 void Feedback::Clear() {
   misspellings_.clear();
-  renderers_.clear();
   text_.clear();
+  renderers_.clear();
 }
 
 const std::set<uint32>& Feedback::FindMisspellings(
-    const string16& misspelled_text) {
-  return text_[misspelled_text];
+    const string16& misspelled_text) const {
+  const TextHashesMap::const_iterator text_it = text_.find(misspelled_text);
+  return text_it == text_.end() ? empty_hash_collection_ : text_it->second;
 }
 
 }  // namespace spellcheck
diff --git a/chrome/browser/spellchecker/feedback.h b/chrome/browser/spellchecker/feedback.h
index 01937df..ce4a3a7 100644
--- a/chrome/browser/spellchecker/feedback.h
+++ b/chrome/browser/spellchecker/feedback.h
@@ -1,6 +1,13 @@
 // 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.
+//
+// An object to store user feedback to spellcheck suggestions from spelling
+// service.
+//
+// Stores feedback for the spelling service in |Misspelling| objects. Each
+// |Misspelling| object is identified by a |hash| and corresponds to a document
+// marker with the same |hash| identifier in the renderer.
 
 #ifndef CHROME_BROWSER_SPELLCHECKER_FEEDBACK_H_
 #define CHROME_BROWSER_SPELLCHECKER_FEEDBACK_H_
@@ -13,9 +20,15 @@
 
 namespace spellcheck {
 
-// Stores feedback for the spelling service in |Misspelling| objects. Each
-// |Misspelling| object is identified by a |hash| and corresponds to a document
-// marker  with the same |hash| identifier in the renderer.
+// Stores user feedback to spellcheck suggestions. Sample usage:
+//    Feedback feedback;
+//    feedback.AddMisspelling(renderer_process_id, Misspelling(
+//        ASCIIToUTF16("Helllo world"), 0, 6, std::vector<string16>(),
+//        GenerateRandomHash()));
+//    feedback.FinalizeRemovedMisspellings(renderer_process_id,
+//                                         std::vector<uint32>());
+//    ProcessFeedback(feedback.GetMisspellingsInRenderer(renderer_process_id));
+//    feedback.EraseFinalizedMisspellings(renderer_process_id);
 class Feedback {
  public:
   Feedback();
@@ -33,7 +46,7 @@
       const std::vector<uint32>& remaining_markers);
 
   // Returns true if the renderer with process ID |renderer_process_id| has
-  // misspellings. Otherwise returns false.
+  // misspellings.
   bool RendererHasMisspellings(int renderer_process_id) const;
 
   // Returns a copy of the misspellings in renderer with process ID
@@ -45,15 +58,14 @@
   // process ID |renderer_process_id|.
   void EraseFinalizedMisspellings(int renderer_process_id);
 
-  // Returns true if there's a misspelling with |hash| identifier. Otherwise
-  // returns false.
+  // Returns true if there's a misspelling with |hash| identifier.
   bool HasMisspelling(uint32 hash) const;
 
   // Adds the |misspelling| to feedback data. If the |misspelling| has a
   // duplicate hash, then replaces the existing misspelling with the same hash.
   void AddMisspelling(int renderer_process_id, const Misspelling& misspelling);
 
-  // Returns true if there're no misspellings. Otherwise returns false.
+  // Returns true if there're no misspellings.
   bool Empty() const;
 
   // Returns a list of process identifiers for renderers that have misspellings.
@@ -69,21 +81,27 @@
   void Clear();
 
   // Returns a list of all misspelling identifiers for |misspelled_text|.
-  const std::set<uint32>& FindMisspellings(const string16& misspelled_text);
+  const std::set<uint32>& FindMisspellings(
+      const string16& misspelled_text) const;
 
  private:
+  typedef std::map<uint32, Misspelling> HashMisspellingMap;
+  typedef std::set<uint32> HashCollection;
+  typedef std::map<int, HashCollection> RendererHashesMap;
+  typedef std::map<string16, HashCollection> TextHashesMap;
+
+  // An empty hash collection to return when FindMisspellings() does not find
+  // misspellings.
+  const HashCollection empty_hash_collection_;
+
   // A map of hashes that identify document markers to feedback data to be sent
   // to spelling service.
-  typedef std::map<uint32, Misspelling> HashMisspellingMap;
   HashMisspellingMap misspellings_;
 
   // A map of renderer process ID to hashes that identify misspellings.
-  typedef std::set<uint32> HashCollection;
-  typedef std::map<int, HashCollection> RendererHashesMap;
   RendererHashesMap renderers_;
 
   // A map of misspelled text to hashes that identify misspellings.
-  typedef std::map<string16, HashCollection> TextHashesMap;
   TextHashesMap text_;
 
   DISALLOW_COPY_AND_ASSIGN(Feedback);
diff --git a/chrome/browser/spellchecker/feedback_sender.cc b/chrome/browser/spellchecker/feedback_sender.cc
index c250cf4..f8d4957 100644
--- a/chrome/browser/spellchecker/feedback_sender.cc
+++ b/chrome/browser/spellchecker/feedback_sender.cc
@@ -1,6 +1,31 @@
 // 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.
+//
+// The |FeedbackSender| object stores the user feedback to spellcheck
+// suggestions in a |Feedback| object.
+//
+// When spelling service returns spellcheck results, these results first arrive
+// in |FeedbackSender| to assign hash identifiers for each
+// misspelling-suggestion pair. If the spelling service identifies the same
+// misspelling as already displayed to the user, then |FeedbackSender| reuses
+// the same hash identifiers to avoid duplication. It detects the duplicates by
+// comparing misspelling offsets in text. Spelling service can return duplicates
+// because we request spellcheck for whole paragraphs, as context around a
+// misspelled word is important to the spellcheck algorithm.
+//
+// All feedback is initially pending. When a user acts upon a misspelling such
+// that the misspelling is no longer displayed (red squiggly line goes away),
+// then the feedback for this misspelling is finalized. All finalized feedback
+// is erased after being sent to the spelling service. Pending feedback is kept
+// around for |kSessionHours| hours and then finalized even if user did not act
+// on the misspellings.
+//
+// |FeedbackSender| periodically requests a list of hashes of all remaining
+// misspellings in renderers. When a renderer responds with a list of hashes,
+// |FeedbackSender| uses the list to determine which misspellings are no longer
+// displayed to the user and sends the current state of user feedback to the
+// spelling service.
 
 #include "chrome/browser/spellchecker/feedback_sender.h"
 
@@ -13,6 +38,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/browser/spellchecker/word_trimmer.h"
 #include "chrome/common/chrome_switches.h"
@@ -38,11 +64,11 @@
 // Returns a hash of |session_start|, the current timestamp, and
 // |suggestion_index|.
 uint32 BuildHash(const base::Time& session_start, size_t suggestion_index) {
-  std::stringstream hash_data;
-  hash_data << session_start.ToTimeT()
-            << base::Time::Now().ToTimeT()
-            << suggestion_index;
-  return base::Hash(hash_data.str());
+  return base::Hash(
+      base::StringPrintf("%" PRId64 "%" PRId64 "%" PRIuS,
+                         session_start.ToInternalValue(),
+                         base::Time::Now().ToInternalValue(),
+                         suggestion_index));
 }
 
 // Returns a pending feedback data structure for the spellcheck |result| and
@@ -66,10 +92,11 @@
     const std::vector<Misspelling>& suggestions,
     bool is_first_feedback_batch) {
   base::ListValue* list = new base::ListValue;
-  for (std::vector<Misspelling>::const_iterator it = suggestions.begin();
-       it != suggestions.end();
-       ++it) {
-    base::DictionaryValue* suggestion = it->Serialize();
+  for (std::vector<Misspelling>::const_iterator suggestion_it =
+           suggestions.begin();
+       suggestion_it != suggestions.end();
+       ++suggestion_it) {
+    base::DictionaryValue* suggestion = suggestion_it->Serialize();
     suggestion->SetBoolean("isFirstInSession", is_first_feedback_batch);
     suggestion->SetBoolean("isAutoCorrection", false);
     list->Append(suggestion);
@@ -101,6 +128,16 @@
   return result;
 }
 
+// Returns true if the misspelling location is within text bounds.
+bool IsInBounds(int misspelling_location,
+                int misspelling_length,
+                size_t text_length) {
+  return misspelling_location >= 0 && misspelling_length > 0 &&
+         static_cast<size_t>(misspelling_location) < text_length &&
+         static_cast<size_t>(misspelling_location + misspelling_length) <=
+             text_length;
+}
+
 }  // namespace
 
 FeedbackSender::FeedbackSender(net::URLRequestContextGetter* request_context,
@@ -172,16 +209,16 @@
     return;
   misspelling->action.type = SpellcheckAction::TYPE_ADD_TO_DICT;
   misspelling->timestamp = base::Time::Now();
-  const std::set<uint32>& misspellings = feedback_.FindMisspellings(
-      misspelling->context.substr(misspelling->location, misspelling->length));
-  for (std::set<uint32>::const_iterator it = misspellings.begin();
-       it != misspellings.end();
-       ++it) {
-    Misspelling* duplicate_misspelling = feedback_.GetMisspelling(*it);
-    if (duplicate_misspelling && !duplicate_misspelling->action.IsFinal()) {
-      duplicate_misspelling->action.type = SpellcheckAction::TYPE_ADD_TO_DICT;
-      duplicate_misspelling->timestamp = misspelling->timestamp;
-    }
+  const std::set<uint32>& hashes =
+      feedback_.FindMisspellings(misspelling->GetMisspelledString());
+  for (std::set<uint32>::const_iterator hash_it = hashes.begin();
+       hash_it != hashes.end();
+       ++hash_it) {
+    Misspelling* duplicate_misspelling = feedback_.GetMisspelling(*hash_it);
+    if (!duplicate_misspelling || duplicate_misspelling->action.IsFinal())
+      continue;
+    duplicate_misspelling->action.type = SpellcheckAction::TYPE_ADD_TO_DICT;
+    duplicate_misspelling->timestamp = misspelling->timestamp;
   }
 }
 
@@ -236,39 +273,41 @@
 }
 
 void FeedbackSender::OnSpellcheckResults(
-    std::vector<SpellCheckResult>* results,
     int renderer_process_id,
     const string16& text,
-    const std::vector<SpellCheckMarker>& markers) {
+    const std::vector<SpellCheckMarker>& markers,
+    std::vector<SpellCheckResult>* results) {
   // Don't collect feedback if not going to send it.
   if (!timer_.IsRunning())
     return;
 
   // Generate a map of marker offsets to marker hashes. This map helps to
   // efficiently lookup feedback data based on the position of the misspelling
-  // in text
+  // in text.
   typedef std::map<size_t, uint32> MarkerMap;
   MarkerMap marker_map;
   for (size_t i = 0; i < markers.size(); ++i)
     marker_map[markers[i].offset] = markers[i].hash;
 
-  for (std::vector<SpellCheckResult>::iterator result_iter = results->begin();
-       result_iter != results->end();
-       ++result_iter) {
-    MarkerMap::iterator marker_iter = marker_map.find(result_iter->location);
-    if (marker_iter != marker_map.end() &&
-        feedback_.HasMisspelling(marker_iter->second)) {
+  for (std::vector<SpellCheckResult>::iterator result_it = results->begin();
+       result_it != results->end();
+       ++result_it) {
+    if (!IsInBounds(result_it->location, result_it->length, text.length()))
+      continue;
+    MarkerMap::const_iterator marker_it = marker_map.find(result_it->location);
+    if (marker_it != marker_map.end() &&
+        feedback_.HasMisspelling(marker_it->second)) {
       // If the renderer already has a marker for this spellcheck result, then
       // set the hash of the spellcheck result to be the same as the marker.
-      result_iter->hash = marker_iter->second;
+      result_it->hash = marker_it->second;
     } else {
       // If the renderer does not yet have a marker for this spellcheck result,
       // then generate a new hash for the spellcheck result.
-      result_iter->hash = BuildHash(session_start_, ++misspelling_counter_);
+      result_it->hash = BuildHash(session_start_, ++misspelling_counter_);
     }
     // Save the feedback data for the spellcheck result.
     feedback_.AddMisspelling(renderer_process_id,
-                             BuildFeedback(*result_iter, text));
+                             BuildFeedback(*result_it, text));
   }
 }
 
@@ -280,31 +319,31 @@
 }
 
 void FeedbackSender::OnURLFetchComplete(const net::URLFetcher* source) {
-  for (ScopedVector<net::URLFetcher>::iterator it = senders_.begin();
-       it != senders_.end();
-       ++it) {
-    if (*it == source) {
-      senders_.erase(it);
-      break;
+  for (ScopedVector<net::URLFetcher>::iterator sender_it = senders_.begin();
+       sender_it != senders_.end();
+       ++sender_it) {
+    if (*sender_it == source) {
+      senders_.erase(sender_it);
+      return;
     }
   }
+  delete source;
 }
 
 void FeedbackSender::RequestDocumentMarkers() {
   // Request document markers from all the renderers that are still alive.
-  std::vector<int> alive_renderers;
+  std::set<int> alive_renderers;
   for (content::RenderProcessHost::iterator it(
            content::RenderProcessHost::AllHostsIterator());
        !it.IsAtEnd();
        it.Advance()) {
-    alive_renderers.push_back(it.GetCurrentValue()->GetID());
+    alive_renderers.insert(it.GetCurrentValue()->GetID());
     it.GetCurrentValue()->Send(new SpellCheckMsg_RequestDocumentMarkers());
   }
 
   // Asynchronously send out the feedback for all the renderers that are no
   // longer alive.
   std::vector<int> known_renderers = feedback_.GetRendersWithMisspellings();
-  std::sort(alive_renderers.begin(), alive_renderers.end());
   std::sort(known_renderers.begin(), known_renderers.end());
   std::vector<int> dead_renderers;
   std::set_difference(known_renderers.begin(),
diff --git a/chrome/browser/spellchecker/feedback_sender.h b/chrome/browser/spellchecker/feedback_sender.h
index 286008f..ea647ad 100644
--- a/chrome/browser/spellchecker/feedback_sender.h
+++ b/chrome/browser/spellchecker/feedback_sender.h
@@ -1,6 +1,13 @@
 // 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.
+//
+// An object to record and send user feedback to spelling service. The spelling
+// service uses the feedback to improve its suggestions.
+//
+// Assigns uint32 hash identifiers to spelling suggestions from spelling service
+// and stores these suggestions. Records user's actions on these suggestions.
+// Periodically sends batches of user feedback to the spelling service.
 
 #ifndef CHROME_BROWSER_SPELLCHECKER_FEEDBACK_SENDER_H_
 #define CHROME_BROWSER_SPELLCHECKER_FEEDBACK_SENDER_H_
@@ -27,14 +34,26 @@
 
 namespace spellcheck {
 
-// Constants for the feedback field trial.
-static const char kFeedbackFieldTrialName[] = "SpellingServiceFeedback";
-static const char kFeedbackFieldTrialEnabledGroupName[] = "Enabled";
+namespace {
 
-// Manages sending feedback to the spelling service.
+// Constants for the feedback field trial.
+const char kFeedbackFieldTrialName[] = "SpellingServiceFeedback";
+const char kFeedbackFieldTrialEnabledGroupName[] = "Enabled";
+
+}  // namespace
+
+// Stores and sends user feedback to the spelling service. Sample usage:
+//    FeedbackSender sender(profile.GetRequestContext(), language, country);
+//    sender.OnSpellcheckResults(spellcheck_results_from_spelling_service,
+//                               renderer_process_id,
+//                               spellchecked_text,
+//                               existing_hashes);
+//    sender.SelectedSuggestion(hash, suggestion_index);
 class FeedbackSender : public base::SupportsWeakPtr<FeedbackSender>,
                        public net::URLFetcherDelegate {
  public:
+  // Constructs a feedback sender. Keeps |request_context| in a scoped_refptr,
+  // because URLRequestContextGetter implements RefcountedThreadSafe.
   FeedbackSender(net::URLRequestContextGetter* request_context,
                  const std::string& language,
                  const std::string& country);
@@ -72,11 +91,12 @@
 
   // Generates feedback data based on spellcheck results. The new feedback data
   // is pending. Sets hash identifiers for |results|. Called when spelling
-  // service client receives results from the spelling service.
-  void OnSpellcheckResults(std::vector<SpellCheckResult>* results,
-                           int renderer_process_id,
+  // service client receives results from the spelling service. Does not take
+  // ownership of |results|.
+  void OnSpellcheckResults(int renderer_process_id,
                            const string16& text,
-                           const std::vector<SpellCheckMarker>& markers);
+                           const std::vector<SpellCheckMarker>& markers,
+                           std::vector<SpellCheckResult>* results);
 
   // Receives updated language and country code for feedback. Finalizes and
   // sends out all of the feedback data.
@@ -86,7 +106,7 @@
  private:
   friend class FeedbackSenderTest;
 
-  // net::URLFetcherDelegate implementation.
+  // net::URLFetcherDelegate implementation. Takes ownership of |source|.
   virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
 
   // Requests the document markers from all of the renderers to determine which
@@ -102,7 +122,7 @@
   void SendFeedback(const std::vector<Misspelling>& feedback_data,
                     bool is_first_feedback_batch);
 
-  // Request context for the feedback senders.
+  // URL request context for the feedback senders.
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
   // The language of text. The string is a BCP 47 language tag.
diff --git a/chrome/browser/spellchecker/feedback_sender_unittest.cc b/chrome/browser/spellchecker/feedback_sender_unittest.cc
index 3532334..5c0b1db 100644
--- a/chrome/browser/spellchecker/feedback_sender_unittest.cc
+++ b/chrome/browser/spellchecker/feedback_sender_unittest.cc
@@ -1,9 +1,10 @@
 // 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.
+//
+// Unit tests for |FeedbackSender| object.
 
-#include <string>
-#include <vector>
+#include "chrome/browser/spellchecker/feedback_sender.h"
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -13,7 +14,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/spellchecker/feedback_sender.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/metrics/entropy_provider.h"
 #include "chrome/common/spellcheck_common.h"
@@ -28,19 +28,20 @@
 
 namespace {
 
-static const int kMisspellingLength = 6;
-static const int kMisspellingStart = 0;
-static const int kRendererProcessId = 0;
-static const int kUrlFetcherId = 0;
-static const std::string kCountry = "USA";
-static const std::string kLanguage = "en";
-static const string16 kText = ASCIIToUTF16("Helllo world.");
+const char kCountry[] = "USA";
+const char kLanguage[] = "en";
+const char kText[] = "Helllo world.";
+const int kMisspellingLength = 6;
+const int kMisspellingStart = 0;
+const int kRendererProcessId = 0;
+const int kUrlFetcherId = 0;
 
+// Builds a simple spellcheck result.
 SpellCheckResult BuildSpellCheckResult() {
   return SpellCheckResult(SpellCheckResult::SPELLING,
                           kMisspellingStart,
                           kMisspellingLength,
-                          ASCIIToUTF16("Hello"));
+                          UTF8ToUTF16("Hello"));
 }
 
 // Returns the number of times that |needle| appears in |haystack| without
@@ -57,10 +58,10 @@
 
 }  // namespace
 
+// A test fixture to help keep tests simple.
 class FeedbackSenderTest : public testing::Test {
  public:
   FeedbackSenderTest() : ui_thread_(content::BrowserThread::UI, &loop_) {
-
     // The command-line switch and the field trial are temporary.
     // TODO(rouslan): Remove the command-line switch and the field trial.
     // http://crbug.com/247726
@@ -71,24 +72,17 @@
     field_trial_ = base::FieldTrialList::CreateFieldTrial(
         kFeedbackFieldTrialName, kFeedbackFieldTrialEnabledGroupName);
     field_trial_->group();
-
     feedback_.reset(new FeedbackSender(NULL, kLanguage, kCountry));
   }
   virtual ~FeedbackSenderTest() {}
 
- private:
-  TestingProfile profile_;
-  base::MessageLoop loop_;
-  content::TestBrowserThread ui_thread_;
-  scoped_ptr<base::FieldTrialList> field_trial_list_;
-  scoped_refptr<base::FieldTrial> field_trial_;
-  net::TestURLFetcherFactory fetchers_;
-
  protected:
   uint32 AddPendingFeedback() {
     std::vector<SpellCheckResult> results(1, BuildSpellCheckResult());
-    feedback_->OnSpellcheckResults(
-        &results, kRendererProcessId, kText, std::vector<SpellCheckMarker>());
+    feedback_->OnSpellcheckResults(kRendererProcessId,
+                                   UTF8ToUTF16(kText),
+                                   std::vector<SpellCheckMarker>(),
+                                   &results);
     return results[0].hash;
   }
 
@@ -112,8 +106,8 @@
                           number_of_occurrences;
   }
 
-  // Returns true if the feedback sender would be uploading data now. Otherwise
-  // returns false. The test does not open network connections.
+  // Returns true if the feedback sender would be uploading data now. The test
+  // does not open network connections.
   bool IsUploadingData() const {
     return !!fetchers_.GetFetcherByID(kUrlFetcherId);
   }
@@ -129,6 +123,14 @@
   }
 
   scoped_ptr<spellcheck::FeedbackSender> feedback_;
+
+ private:
+  TestingProfile profile_;
+  base::MessageLoop loop_;
+  content::TestBrowserThread ui_thread_;
+  scoped_ptr<base::FieldTrialList> field_trial_list_;
+  scoped_refptr<base::FieldTrial> field_trial_;
+  net::TestURLFetcherFactory fetchers_;
 };
 
 // Do not send data if there's no feedback.
@@ -244,8 +246,10 @@
                                      kSecondMisspellingStart,
                                      kSecondMisspellingLength,
                                      ASCIIToUTF16("world")));
-  feedback_->OnSpellcheckResults(
-      &results, kRendererProcessId, kText, std::vector<SpellCheckMarker>());
+  feedback_->OnSpellcheckResults(kRendererProcessId,
+                                 UTF8ToUTF16(kText),
+                                 std::vector<SpellCheckMarker>(),
+                                 &results);
   feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
                                       std::vector<uint32>());
   EXPECT_TRUE(UploadDataContains("\"actionType\":\"NO_ACTION\"", 2));
@@ -291,8 +295,10 @@
                        kMisspellingStart,
                        kMisspellingLength,
                        ASCIIToUTF16("Hello")));
-  feedback_->OnSpellcheckResults(
-      &results, kRendererProcessId, kText, std::vector<SpellCheckMarker>());
+  feedback_->OnSpellcheckResults(kRendererProcessId,
+                                 UTF8ToUTF16(kText),
+                                 std::vector<SpellCheckMarker>(),
+                                 &results);
   uint32 original_hash = results[0].hash;
   std::vector<uint32> remaining_markers(1, original_hash);
 
@@ -327,7 +333,7 @@
                                 kMisspellingLength,
                                 ASCIIToUTF16("Hello"));
   feedback_->OnSpellcheckResults(
-      &results, kRendererProcessId, kText, original_markers);
+      kRendererProcessId, UTF8ToUTF16(kText), original_markers, &results);
   uint32 updated_hash = results[0].hash;
   EXPECT_NE(updated_hash, original_hash);
   remaining_markers[0] = updated_hash;
@@ -433,13 +439,14 @@
   std::vector<SpellCheckResult> results(
       1,
       SpellCheckResult(SpellCheckResult::SPELLING,
-                       kMisspellingStart + 10,
+                       kMisspellingStart,
                        kMisspellingLength,
                        ASCIIToUTF16("Hello")));
   std::vector<SpellCheckMarker> markers(
       1, SpellCheckMarker(hash, results[0].location));
   EXPECT_EQ(static_cast<uint32>(0), results[0].hash);
-  feedback_->OnSpellcheckResults(&results, kRendererProcessId, kText, markers);
+  feedback_->OnSpellcheckResults(
+      kRendererProcessId, UTF8ToUTF16(kText), markers, &results);
   EXPECT_EQ(hash, results[0].hash);
 }
 
@@ -460,10 +467,10 @@
   static const int kNumberOfRenderers = 2;
   int last_renderer_process_id = -1;
   for (int i = 0; i < kNumberOfRenderers; ++i) {
-    feedback_->OnSpellcheckResults(&results,
-                                   kRendererProcessId + i,
+    feedback_->OnSpellcheckResults(kRendererProcessId + i,
                                    kTextWithDuplicates,
-                                   std::vector<SpellCheckMarker>());
+                                   std::vector<SpellCheckMarker>(),
+                                   &results);
     last_renderer_process_id = kRendererProcessId + i;
   }
   std::vector<uint32> remaining_markers;
@@ -495,4 +502,26 @@
   EXPECT_TRUE(UploadDataContains("ADD_TO_DICT", 2));
 }
 
+// Spellcheck results that are out-of-bounds are not added to feedback.
+TEST_F(FeedbackSenderTest, IgnoreOutOfBounds) {
+  std::vector<SpellCheckResult> results;
+  results.push_back(SpellCheckResult(
+      SpellCheckResult::SPELLING, 0, 100, UTF8ToUTF16("Hello")));
+  results.push_back(SpellCheckResult(
+      SpellCheckResult::SPELLING, 100, 3, UTF8ToUTF16("world")));
+  results.push_back(
+      SpellCheckResult(SpellCheckResult::SPELLING, -1, 3, UTF8ToUTF16("how")));
+  results.push_back(
+      SpellCheckResult(SpellCheckResult::SPELLING, 0, 0, UTF8ToUTF16("are")));
+  results.push_back(
+      SpellCheckResult(SpellCheckResult::SPELLING, 2, -1, UTF8ToUTF16("you")));
+  feedback_->OnSpellcheckResults(kRendererProcessId,
+                                 UTF8ToUTF16(kText),
+                                 std::vector<SpellCheckMarker>(),
+                                 &results);
+  feedback_->OnReceiveDocumentMarkers(kRendererProcessId,
+                                      std::vector<uint32>());
+  EXPECT_FALSE(IsUploadingData());
+}
+
 }  // namespace spellcheck
diff --git a/chrome/browser/spellchecker/feedback_unittest.cc b/chrome/browser/spellchecker/feedback_unittest.cc
index 6529fcd..dd7c727 100644
--- a/chrome/browser/spellchecker/feedback_unittest.cc
+++ b/chrome/browser/spellchecker/feedback_unittest.cc
@@ -1,9 +1,12 @@
 // 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.
+//
+// Unit tests for |Feedback| object.
+
+#include "chrome/browser/spellchecker/feedback.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/spellchecker/feedback.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace spellcheck {
@@ -11,13 +14,14 @@
 namespace {
 
 // Identifier for a renderer process.
-static const int kRendererProcessId = 7;
+const int kRendererProcessId = 7;
 
 // Hash identifier for a misspelling.
-static const uint32 kMisspellingHash = 42;
+const uint32 kMisspellingHash = 42;
 
 }  // namespace
 
+// A test fixture to help keep the tests simple.
 class FeedbackTest : public testing::Test {
  public:
   FeedbackTest() {}
@@ -225,9 +229,7 @@
     EXPECT_NE(static_cast<Misspelling*>(NULL), misspelling);
     EXPECT_TRUE(misspelling->hash >= kMisspellingHash &&
                 misspelling->hash <= hash);
-    EXPECT_EQ(kMisspelledWord,
-              misspelling->context.substr(misspelling->location,
-                                          misspelling->length));
+    EXPECT_EQ(kMisspelledWord, misspelling->GetMisspelledString());
   }
 }
 
diff --git a/chrome/browser/spellchecker/misspelling.cc b/chrome/browser/spellchecker/misspelling.cc
index 4afbaa7..89bcca4 100644
--- a/chrome/browser/spellchecker/misspelling.cc
+++ b/chrome/browser/spellchecker/misspelling.cc
@@ -1,6 +1,11 @@
 // 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.
+//
+// The |Misspelling| object stores the misspelling, a spellcheck suggestion for
+// it, and user's action on it. The misspelling is stored as |context|,
+// |location|, and |length| instead of only misspelled text, because the
+// spellcheck algorithm uses the context.
 
 #include "chrome/browser/spellchecker/misspelling.h"
 
@@ -59,3 +64,11 @@
   result->Set("userActions", BuildUserActionValue(action));
   return result;
 }
+
+string16 Misspelling::GetMisspelledString() const {
+  // Feedback sender does not create Misspelling objects for spellcheck results
+  // that are out-of-bounds of checked text length.
+  if (location > context.length())
+    return string16();
+  return context.substr(location, length);
+}
diff --git a/chrome/browser/spellchecker/misspelling.h b/chrome/browser/spellchecker/misspelling.h
index 7cd331b..36a9cdb 100644
--- a/chrome/browser/spellchecker/misspelling.h
+++ b/chrome/browser/spellchecker/misspelling.h
@@ -1,6 +1,13 @@
 // 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.
+//
+// An object to store user feedback to a single spellcheck suggestion.
+//
+// Stores the spellcheck suggestion, its uint32 hash identifier, and user's
+// feedback. The feedback is indirect, in the sense that we record user's
+// |action| instead of asking them how they feel about a spellcheck suggestion.
+// The object can serialize itself.
 
 #ifndef CHROME_BROWSER_SPELLCHECKER_MISSPELLING_H_
 #define CHROME_BROWSER_SPELLCHECKER_MISSPELLING_H_
@@ -10,7 +17,16 @@
 #include "base/time/time.h"
 #include "chrome/browser/spellchecker/spellcheck_action.h"
 
-// Spellcheck misspelling.
+// Stores user feedback to a spellcheck suggestion. Sample usage:
+//    Misspelling misspelling.
+//    misspelling.context = ASCIIToUTF16("Helllo world");
+//    misspelling.location = 0;
+//    misspelling.length = 6;
+//    misspelling.suggestions = std::vector<string16>(1, ASCIIToUTF16("Hello"));
+//    misspelling.hash = GenerateRandomHash();
+//    misspelling.action.type = SpellcheckAction::TYPE_SELECT;
+//    misspelling.action.index = 0;
+//    Process(misspelling.Serialize());
 class Misspelling {
  public:
   Misspelling();
@@ -25,6 +41,10 @@
   // the result.
   base::DictionaryValue* Serialize() const;
 
+  // Returns the substring of |context| that begins at |location| and contains
+  // |length| characters.
+  string16 GetMisspelledString() const;
+
   // A several-word text snippet that immediately surrounds the misspelling.
   string16 context;
 
diff --git a/chrome/browser/spellchecker/misspelling_unittest.cc b/chrome/browser/spellchecker/misspelling_unittest.cc
index 5437853..8f58ac8 100644
--- a/chrome/browser/spellchecker/misspelling_unittest.cc
+++ b/chrome/browser/spellchecker/misspelling_unittest.cc
@@ -1,11 +1,14 @@
 // 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.
+//
+// Unit tests for |Misspelling| object.
+
+#include "chrome/browser/spellchecker/misspelling.h"
 
 #include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
-#include "chrome/browser/spellchecker/misspelling.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 TEST(MisspellingTest, SerializeTest) {
@@ -29,3 +32,21 @@
   scoped_ptr<base::DictionaryValue> serialized(misspelling.Serialize());
   EXPECT_TRUE(serialized->Equals(expected.get()));
 }
+
+TEST(MisspellingTest, GetMisspelledStringTest) {
+  Misspelling misspelling;
+  misspelling.context = ASCIIToUTF16("How doe sit know");
+  misspelling.location = 4;
+  misspelling.length = 7;
+  EXPECT_EQ(ASCIIToUTF16("doe sit"), misspelling.GetMisspelledString());
+
+  misspelling.length = 0;
+  EXPECT_EQ(string16(), misspelling.GetMisspelledString());
+
+  misspelling.location = misspelling.context.length();
+  misspelling.length = 7;
+  EXPECT_EQ(string16(), misspelling.GetMisspelledString());
+
+  misspelling.location = misspelling.context.length() + 1;
+  EXPECT_EQ(string16(), misspelling.GetMisspelledString());
+}
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter.cc b/chrome/browser/spellchecker/spellcheck_message_filter.cc
index e58be59..80f012d 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter.cc
@@ -140,7 +140,7 @@
     return;
   std::vector<SpellCheckResult> results_copy = results;
   spellcheck->GetFeedbackSender()->OnSpellcheckResults(
-      &results_copy, render_process_id_, text, markers);
+      render_process_id_, text, markers, &results_copy);
 
   // Erase custom dictionary words from the spellcheck results and record
   // in-dictionary feedback.
diff --git a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
index 7648fb9..812c5ce 100644
--- a/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
+++ b/chrome/browser/spellchecker/spellcheck_message_filter_mac.cc
@@ -170,10 +170,10 @@
       SpellcheckServiceFactory::GetForRenderProcessId(render_process_id_);
   if (spellcheck_service) {
     spellcheck_service->GetFeedbackSender()->OnSpellcheckResults(
-        &remote_results_,
         render_process_id_,
         text,
-        markers_);
+        markers_,
+        &remote_results_);
   }
 
   OnCheckCompleted();
diff --git a/chrome/browser/ssl/ssl_error_info.cc b/chrome/browser/ssl/ssl_error_info.cc
index a6860dd..d11beb8 100644
--- a/chrome/browser/ssl/ssl_error_info.cc
+++ b/chrome/browser/ssl/ssl_error_info.cc
@@ -6,7 +6,6 @@
 
 #include "base/i18n/time_formatting.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/common/time_format.h"
 #include "content/public/browser/cert_store.h"
 #include "grit/chromium_strings.h"
 #include "grit/generated_resources.h"
diff --git a/chrome/browser/sync/profile_sync_service.cc b/chrome/browser/sync/profile_sync_service.cc
index 51f6c0d..40d198a 100644
--- a/chrome/browser/sync/profile_sync_service.cc
+++ b/chrome/browser/sync/profile_sync_service.cc
@@ -57,7 +57,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_version_info.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/notification_details.h"
@@ -76,6 +75,7 @@
 #include "sync/js/js_event_details.h"
 #include "sync/util/cryptographer.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 
 #if defined(ENABLE_MANAGED_USERS)
 #include "chrome/browser/managed_mode/managed_user_service.h"
@@ -1371,10 +1371,6 @@
 
 void ProfileSyncService::OnConfigureStart() {
   sync_configure_start_time_ = base::Time::Now();
-  content::NotificationService::current()->Notify(
-      chrome::NOTIFICATION_SYNC_CONFIGURE_START,
-      content::Source<ProfileSyncService>(this),
-      content::NotificationService::NoDetails());
   NotifyObservers();
 }
 
@@ -1478,7 +1474,7 @@
   if (last_synced < base::TimeDelta::FromMinutes(1))
     return l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW);
 
-  return TimeFormat::TimeElapsed(last_synced);
+  return ui::TimeFormat::TimeElapsed(last_synced);
 }
 
 void ProfileSyncService::UpdateSelectedTypesHistogram(
diff --git a/chrome/browser/sync/test/integration/autofill_helper.cc b/chrome/browser/sync/test/integration/autofill_helper.cc
index 54bb657..e4a7f61 100644
--- a/chrome/browser/sync/test/integration/autofill_helper.cc
+++ b/chrome/browser/sync/test/integration/autofill_helper.cc
@@ -284,7 +284,7 @@
   for (size_t i = 0; i < all_profiles.size(); ++i) {
     profiles.push_back(*all_profiles[i]);
     if (all_profiles[i]->guid() == guid)
-      profiles.back().SetRawInfo(type.server_type(), value);
+      profiles.back().SetRawInfo(type.GetStorableType(), value);
   }
   autofill_helper::SetProfiles(profile, &profiles);
 }
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
index 14afe7a..c0307d4 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.cc
@@ -35,13 +35,21 @@
 const int64 kCurrentDatabaseVersion = 3;
 const char kServiceMetadataKey[] = "SERVICE";
 const char kFileMetadataKeyPrefix[] = "FILE: ";
+const char kFileTrackerKeyPrefix[] = "TRACKER: ";
 
 struct DatabaseContents {
   scoped_ptr<ServiceMetadata> service_metadata;
+  ScopedVector<FileMetadata> file_metadata;
+  ScopedVector<FileTracker> file_trackers;
 };
 
 namespace {
 
+typedef MetadataDatabase::FileByID FileByID;
+typedef MetadataDatabase::TrackerByID TrackerByID;
+typedef MetadataDatabase::TrackersByParentAndTitle TrackersByParentAndTitle;
+typedef MetadataDatabase::TrackersByTitle TrackersByTitle;
+
 std::string RemovePrefix(const std::string& str, const std::string& prefix) {
   if (StartsWithASCII(str, prefix, true))
     return str.substr(prefix.size());
@@ -75,6 +83,44 @@
   callback.Run(LevelDBStatusToSyncStatusCode(status));
 }
 
+void PutServiceMetadataToBatch(const ServiceMetadata& service_metadata,
+                               leveldb::WriteBatch* batch) {
+  std::string value;
+  bool success = service_metadata.SerializeToString(&value);
+  DCHECK(success);
+  batch->Put(kServiceMetadataKey, value);
+}
+
+void PutFileToBatch(const FileMetadata& file, leveldb::WriteBatch* batch) {
+  std::string value;
+  bool success = file.SerializeToString(&value);
+  DCHECK(success);
+  batch->Put(kFileMetadataKeyPrefix + file.file_id(), value);
+}
+
+void PutTrackerToBatch(const FileTracker& tracker, leveldb::WriteBatch* batch) {
+  std::string value;
+  bool success = tracker.SerializeToString(&value);
+  DCHECK(success);
+  batch->Put(kFileTrackerKeyPrefix + base::Int64ToString(tracker.tracker_id()),
+             value);
+}
+
+void PutFileDeletionToBatch(const std::string& file_id,
+                            leveldb::WriteBatch* batch) {
+  batch->Delete(kFileMetadataKeyPrefix + file_id);
+}
+
+void PutTrackerDeletionToBatch(int64 tracker_id, leveldb::WriteBatch* batch) {
+  batch->Delete(kFileTrackerKeyPrefix + base::Int64ToString(tracker_id));
+}
+
+std::string GetTrackerTitle(const FileTracker& tracker) {
+  if (tracker.has_synced_details())
+    return tracker.synced_details().title();
+  return std::string();
+}
+
 // Returns true if |db| has no content.
 bool IsDatabaseEmpty(leveldb::DB* db) {
   DCHECK(db);
@@ -181,8 +227,38 @@
       continue;
     }
 
-    NOTIMPLEMENTED();
-    continue;
+    if (StartsWithASCII(key, kFileMetadataKeyPrefix, true)) {
+      std::string file_id = RemovePrefix(key, kFileMetadataKeyPrefix);
+
+      scoped_ptr<FileMetadata> file(new FileMetadata);
+      if (!file->ParseFromString(itr->value().ToString())) {
+        util::Log(logging::LOG_WARNING, FROM_HERE,
+                  "Failed to parse a FileMetadata");
+        continue;
+      }
+
+      contents->file_metadata.push_back(file.release());
+      continue;
+    }
+
+    if (StartsWithASCII(key, kFileTrackerKeyPrefix, true)) {
+      int64 tracker_id = 0;
+      if (!base::StringToInt64(RemovePrefix(key, kFileTrackerKeyPrefix),
+                               &tracker_id)) {
+        util::Log(logging::LOG_WARNING, FROM_HERE,
+                  "Failed to parse TrackerID");
+        continue;
+      }
+
+      scoped_ptr<FileTracker> tracker(new FileTracker);
+      if (!tracker->ParseFromString(itr->value().ToString())) {
+        util::Log(logging::LOG_WARNING, FROM_HERE,
+                  "Failed to parse a Tracker");
+        continue;
+      }
+      contents->file_trackers.push_back(tracker.release());
+      continue;
+    }
   }
 
   return SYNC_STATUS_OK;
@@ -193,6 +269,7 @@
 
   if (!contents->service_metadata) {
     contents->service_metadata.reset(new ServiceMetadata);
+    contents->service_metadata->set_next_tracker_id(1);
 
     std::string value;
     contents->service_metadata->SerializeToString(&value);
@@ -201,9 +278,106 @@
   return SYNC_STATUS_OK;
 }
 
-SyncStatusCode RemoveUnreachableFiles(DatabaseContents* contents,
+SyncStatusCode RemoveUnreachableItems(DatabaseContents* contents,
                                       leveldb::WriteBatch* batch) {
-  NOTIMPLEMENTED();
+  TrackerByID unvisited_trackers;
+  typedef std::map<int64, std::set<FileTracker*> > TrackersByParent;
+  TrackersByParent trackers_by_parent;
+
+  for (ScopedVector<FileTracker>::iterator itr =
+           contents->file_trackers.begin();
+       itr != contents->file_trackers.end();
+       ++itr) {
+    FileTracker* tracker = *itr;
+    DCHECK(!ContainsKey(unvisited_trackers, tracker->tracker_id()));
+    unvisited_trackers[tracker->tracker_id()] = tracker;
+    if (tracker->parent_tracker_id())
+      trackers_by_parent[tracker->parent_tracker_id()].insert(tracker);
+  }
+
+  // Traverse synced tracker tree. Take only active items, app-root and their
+  // children. Drop unreachable items.
+  ScopedVector<FileTracker> reachable_trackers;
+  std::stack<int64> pending;
+  if (contents->service_metadata->sync_root_tracker_id())
+    pending.push(contents->service_metadata->sync_root_tracker_id());
+
+  while (!pending.empty()) {
+    int64 tracker_id = pending.top();
+    pending.pop();
+
+    {
+      TrackerByID::iterator found = unvisited_trackers.find(tracker_id);
+      if (found == unvisited_trackers.end())
+        continue;
+
+      FileTracker* tracker = found->second;
+      unvisited_trackers.erase(found);
+      reachable_trackers.push_back(tracker);
+
+      if (!tracker->active() && !tracker->is_app_root())
+        continue;
+    }
+
+    TrackersByParent::iterator found = trackers_by_parent.find(tracker_id);
+    if (found == trackers_by_parent.end())
+      continue;
+
+    for (std::set<FileTracker*>::const_iterator itr =
+             found->second.begin();
+         itr != found->second.end();
+         ++itr)
+      pending.push((*itr)->tracker_id());
+  }
+
+  // Delete all unreachable trackers.
+  for (TrackerByID::iterator itr = unvisited_trackers.begin();
+       itr != unvisited_trackers.end(); ++itr) {
+    FileTracker* tracker = itr->second;
+    PutTrackerDeletionToBatch(tracker->tracker_id(), batch);
+    delete tracker;
+  }
+  unvisited_trackers.clear();
+
+  // |reachable_trackers| contains all files/folders reachable from sync-root
+  // folder via active folders and app-root folders.
+  // Update the tracker set in database contents with the reachable tracker set.
+  contents->file_trackers.weak_clear();
+  contents->file_trackers.swap(reachable_trackers);
+
+  // Do the similar traverse for FileMetadata and remove FileMetadata that don't
+  // have reachable trackers.
+  FileByID unreferred_files;
+  for (ScopedVector<FileMetadata>::const_iterator itr =
+           contents->file_metadata.begin();
+       itr != contents->file_metadata.end();
+       ++itr) {
+    unreferred_files.insert(std::make_pair((*itr)->file_id(), *itr));
+  }
+
+  ScopedVector<FileMetadata> referred_files;
+  for (ScopedVector<FileTracker>::const_iterator itr =
+           contents->file_trackers.begin();
+       itr != contents->file_trackers.end();
+       ++itr) {
+    FileByID::iterator found = unreferred_files.find((*itr)->file_id());
+    if (found != unreferred_files.end()) {
+      referred_files.push_back(found->second);
+      unreferred_files.erase(found);
+    }
+  }
+
+  for (FileByID::iterator itr = unreferred_files.begin();
+       itr != unreferred_files.end(); ++itr) {
+    FileMetadata* file = itr->second;
+    PutFileDeletionToBatch(file->file_id(), batch);
+    delete file;
+  }
+  unreferred_files.clear();
+
+  contents->file_metadata.weak_clear();
+  contents->file_metadata.swap(referred_files);
+
   return SYNC_STATUS_OK;
 }
 
@@ -224,6 +398,12 @@
 
 }  // namespace
 
+bool MetadataDatabase::DirtyTrackerComparator::operator()(
+    const FileTracker* left,
+    const FileTracker* right) const {
+  return left->tracker_id() < right->tracker_id();
+}
+
 // static
 void MetadataDatabase::Create(base::SequencedTaskRunner* task_runner,
                               const base::FilePath& database_path,
@@ -237,6 +417,10 @@
 
 MetadataDatabase::~MetadataDatabase() {
   task_runner_->DeleteSoon(FROM_HERE, db_.release());
+  STLDeleteContainerPairSecondPointers(
+      file_by_id_.begin(), file_by_id_.end());
+  STLDeleteContainerPairSecondPointers(
+      tracker_by_id_.begin(), tracker_by_id_.end());
 }
 
 int64 MetadataDatabase::GetLargestChangeID() const {
@@ -340,7 +524,7 @@
   if (status != SYNC_STATUS_OK)
     return status;
 
-  status = RemoveUnreachableFiles(&contents, &batch);
+  status = RemoveUnreachableItems(&contents, &batch);
   if (status != SYNC_STATUS_OK)
     return status;
 
@@ -354,7 +538,38 @@
 }
 
 void MetadataDatabase::BuildIndexes(DatabaseContents* contents) {
-  NOTIMPLEMENTED();
+  service_metadata_ = contents->service_metadata.Pass();
+
+  for (ScopedVector<FileMetadata>::const_iterator itr =
+           contents->file_metadata.begin();
+       itr != contents->file_metadata.end();
+       ++itr) {
+    file_by_id_[(*itr)->file_id()] = *itr;
+  }
+  contents->file_metadata.weak_clear();
+
+  for (ScopedVector<FileTracker>::const_iterator itr =
+           contents->file_trackers.begin();
+       itr != contents->file_trackers.end();
+       ++itr) {
+    FileTracker* tracker = *itr;
+    tracker_by_id_[tracker->tracker_id()] = tracker;
+    trackers_by_file_id_[tracker->file_id()].Insert(tracker);
+
+    if (tracker->is_app_root())
+      app_root_by_app_id_[tracker->app_id()] = tracker;
+
+    if (tracker->parent_tracker_id()) {
+      std::string title = GetTrackerTitle(*tracker);
+      TrackerSet* trackers =
+          &trackers_by_parent_and_title_[tracker->parent_tracker_id()][title];
+      trackers->Insert(tracker);
+    }
+
+    if (tracker->dirty())
+      dirty_trackers_.insert(tracker);
+  }
+  contents->file_trackers.weak_clear();
 }
 
 void MetadataDatabase::WriteToDatabase(scoped_ptr<leveldb::WriteBatch> batch,
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database.h b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
index ea326d0..d2cb9cd 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database.h
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database.h
@@ -6,12 +6,14 @@
 #define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_METADATA_DATABASE_H_
 
 #include <map>
+#include <set>
 #include <string>
 
 #include "base/callback_forward.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
+#include "chrome/browser/sync_file_system/drive_backend/tracker_set.h"
 #include "chrome/browser/sync_file_system/sync_callbacks.h"
 #include "chrome/browser/sync_file_system/sync_status_code.h"
 
@@ -35,6 +37,8 @@
 namespace sync_file_system {
 namespace drive_backend {
 
+class FileMetadata;
+class FileTracker;
 class ServiceMetadata;
 struct DatabaseContents;
 
@@ -73,6 +77,13 @@
 //
 class MetadataDatabase {
  public:
+  typedef std::map<std::string, FileMetadata*> FileByID;
+  typedef std::map<int64, FileTracker*> TrackerByID;
+  typedef std::map<std::string, TrackerSet> TrackersByFileID;
+  typedef std::map<std::string, TrackerSet> TrackersByTitle;
+  typedef std::map<int64, TrackersByTitle> TrackersByParentAndTitle;
+  typedef std::map<std::string, FileTracker*> TrackerByAppID;
+
   typedef base::Callback<
       void(SyncStatusCode status, scoped_ptr<MetadataDatabase> instance)>
       CreateCallback;
@@ -114,6 +125,13 @@
                           const SyncStatusCallback& callback);
 
  private:
+  struct DirtyTrackerComparator {
+    bool operator()(const FileTracker* left,
+                    const FileTracker* right) const;
+  };
+
+  typedef std::set<FileTracker*, DirtyTrackerComparator> DirtyTrackers;
+
   friend class MetadataDatabaseTest;
 
   explicit MetadataDatabase(base::SequencedTaskRunner* task_runner);
@@ -135,6 +153,30 @@
 
   scoped_ptr<ServiceMetadata> service_metadata_;
 
+  FileByID file_by_id_;  // Owned.
+  TrackerByID tracker_by_id_;  // Owned.
+
+  // Maps FileID to trackers.  The active tracker must be unique per FileID.
+  // This must be updated when updating |active| field of a tracker.
+  TrackersByFileID trackers_by_file_id_;  // Not owned.
+
+  // Maps AppID to the app-root tracker.
+  // This must be updated when a tracker is registered/unregistered as an
+  // app-root.
+  TrackerByAppID app_root_by_app_id_;  // Not owned.
+
+  // Maps |tracker_id| to its children grouped by their |title|.
+  // If the title is unknown for a tracker, treats its title as empty. Empty
+  // titled file must not be active.
+  // The active tracker must be unique per its parent_tracker and its title.
+  // This must be updated when updating |title|, |active| or
+  // |parent_tracker_id|.
+  TrackersByParentAndTitle trackers_by_parent_and_title_;
+
+  // Holds all trackers which marked as dirty.
+  // This must be updated when updating |dirty| field of a tracker.
+  DirtyTrackers dirty_trackers_;  // Not owned.
+
   base::WeakPtrFactory<MetadataDatabase> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(MetadataDatabase);
diff --git a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
index 6df81bb..608a180 100644
--- a/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
+++ b/chrome/browser/sync_file_system/drive_backend/metadata_database_unittest.cc
@@ -156,7 +156,6 @@
   }
 
  private:
-
   base::ScopedTempDir database_dir_;
   base::MessageLoop message_loop_;
 
@@ -169,5 +168,11 @@
   DISALLOW_COPY_AND_ASSIGN(MetadataDatabaseTest);
 };
 
+TEST_F(MetadataDatabaseTest, InitializationTest_Empty) {
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+  DropDatabase();
+  EXPECT_EQ(SYNC_STATUS_OK, InitializeMetadataDatabase());
+}
+
 }  // namespace drive_backend
 }  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/tracker_set.cc b/chrome/browser/sync_file_system/drive_backend/tracker_set.cc
new file mode 100644
index 0000000..a16c63f
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/tracker_set.cc
@@ -0,0 +1,51 @@
+// 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/sync_file_system/drive_backend/tracker_set.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "chrome/browser/sync_file_system/drive_backend/metadata_database.pb.h"
+
+namespace sync_file_system {
+namespace drive_backend {
+
+bool TrackerSet::TrackerComparator::operator()(const FileTracker* left,
+                                               const FileTracker* right) const {
+  return left->tracker_id() < right->tracker_id();
+}
+
+TrackerSet::TrackerSet()
+    : active_tracker_(NULL) {
+}
+
+TrackerSet::~TrackerSet() {}
+
+void TrackerSet::Insert(FileTracker* tracker) {
+  if (tracker_set_.insert(tracker).second && tracker->active()) {
+    DCHECK(!active_tracker_);
+    active_tracker_ = tracker;
+  }
+}
+
+void TrackerSet::Erase(FileTracker* tracker) {
+  if (tracker_set_.erase(tracker) == 1 && active_tracker_ == tracker)
+    active_tracker_ = NULL;
+}
+
+void TrackerSet::Activate(FileTracker* tracker) {
+  DCHECK(!active_tracker_);
+  DCHECK(ContainsKey(tracker_set_, tracker));
+  active_tracker_ = tracker;
+}
+
+void TrackerSet::Inactivate(FileTracker* tracker) {
+  DCHECK(tracker->active());
+  DCHECK_EQ(tracker, active_tracker_);
+  DCHECK(ContainsKey(tracker_set_, tracker));
+  active_tracker_ = NULL;
+}
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
diff --git a/chrome/browser/sync_file_system/drive_backend/tracker_set.h b/chrome/browser/sync_file_system/drive_backend/tracker_set.h
new file mode 100644
index 0000000..68353a9
--- /dev/null
+++ b/chrome/browser/sync_file_system/drive_backend/tracker_set.h
@@ -0,0 +1,51 @@
+// 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_SYNC_FILE_SYSTEM_DRIVE_BACKEND_TRACKER_SET_H_
+#define CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_TRACKER_SET_H_
+
+#include <set>
+
+namespace sync_file_system {
+namespace drive_backend {
+
+class FileTracker;
+
+class TrackerSet {
+ public:
+  struct TrackerComparator {
+    bool operator()(const FileTracker* left,
+                    const FileTracker* right) const;
+  };
+
+  typedef std::set<FileTracker*, TrackerComparator> RawTrackerSet;
+  typedef RawTrackerSet::iterator iterator;
+  typedef RawTrackerSet::const_iterator const_iterator;
+
+  TrackerSet();
+  ~TrackerSet();
+
+  bool has_active() const { return !!active_tracker_; }
+  void Insert(FileTracker* tracker);
+  void Erase(FileTracker* tracker);
+  void Activate(FileTracker* tracker);
+  void Inactivate(FileTracker* tracker);
+
+  const FileTracker* active_tracker() const { return active_tracker_; }
+  const RawTrackerSet& tracker_set() const { return tracker_set_; }
+
+  iterator begin() { return tracker_set_.begin(); }
+  iterator end() { return tracker_set_.end(); }
+  const_iterator begin() const { return tracker_set_.begin(); }
+  const_iterator end() const { return tracker_set_.end(); }
+
+ private:
+  FileTracker* active_tracker_;
+  RawTrackerSet tracker_set_;
+};
+
+}  // namespace drive_backend
+}  // namespace sync_file_system
+
+#endif  // CHROME_BROWSER_SYNC_FILE_SYSTEM_DRIVE_BACKEND_TRACKER_SET_H_
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc
index ce5843d..5038dff 100644
--- a/chrome/browser/themes/theme_service.cc
+++ b/chrome/browser/themes/theme_service.cc
@@ -6,7 +6,6 @@
 
 #include "base/bind.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/strings/string_util.h"
@@ -54,12 +53,6 @@
 // unpacked on the filesystem.)
 const char* kDefaultThemeGalleryID = "hkacjpbfdknhflllbcmjibkdeoafencn";
 
-// Wait this many seconds after startup to garbage collect unused themes.
-// Removing unused themes is done after a delay because there is no
-// reason to do it at startup.
-// ExtensionService::GarbageCollectExtensions() does something similar.
-const int kRemoveUnusedThemesStartupDelay = 30;
-
 SkColor TintForUnderline(SkColor input) {
   return SkColorSetA(input, SkColorGetA(input) / 3);
 }
@@ -81,12 +74,10 @@
 }  // namespace
 
 ThemeService::ThemeService()
-    : rb_(ResourceBundle::GetSharedInstance()),
+    : ready_(false),
+      rb_(ResourceBundle::GetSharedInstance()),
       profile_(NULL),
-      ready_(false),
-      installed_pending_load_id_(kDefaultThemeID),
-      number_of_infobars_(0),
-      weak_ptr_factory_(this) {
+      number_of_infobars_(0) {
 }
 
 ThemeService::~ThemeService() {
@@ -99,9 +90,11 @@
 
   LoadThemePrefs();
 
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSIONS_READY,
-                 content::Source<Profile>(profile_));
+  if (!ready_) {
+    registrar_.Add(this,
+                   chrome::NOTIFICATION_EXTENSIONS_READY,
+                   content::Source<Profile>(profile_));
+  }
 
   theme_syncable_service_.reset(new ThemeSyncableService(profile_, this));
 }
@@ -207,83 +200,36 @@
 void ThemeService::Observe(int type,
                            const content::NotificationSource& source,
                            const content::NotificationDetails& details) {
-  using content::Details;
-  switch (type) {
-    case chrome::NOTIFICATION_EXTENSIONS_READY:
-      registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
-          content::Source<Profile>(profile_));
-      OnExtensionServiceReady();
-      break;
-    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
-    {
-      // The theme may be initially disabled. Wait till it is loaded (if ever).
-      Details<const extensions::InstalledExtensionInfo> installed_details(
-          details);
-      if (installed_details->extension->is_theme())
-        installed_pending_load_id_ = installed_details->extension->id();
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_LOADED:
-    {
-      const Extension* extension = Details<const Extension>(details).ptr();
-      if (extension->is_theme() &&
-          installed_pending_load_id_ != kDefaultThemeID &&
-          installed_pending_load_id_ == extension->id()) {
-        SetTheme(extension);
-      }
-      installed_pending_load_id_ = kDefaultThemeID;
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_ENABLED:
-    {
-      const Extension* extension = Details<const Extension>(details).ptr();
-      if (extension->is_theme())
-        SetTheme(extension);
-      break;
-    }
-    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
-    {
-      Details<const extensions::UnloadedExtensionInfo> unloaded_details(
-          details);
-      if (unloaded_details->reason != extension_misc::UNLOAD_REASON_UPDATE &&
-          unloaded_details->extension->is_theme() &&
-          unloaded_details->extension->id() == GetThemeID()) {
-        UseDefaultTheme();
-      }
-      break;
-    }
-  }
+  DCHECK(type == chrome::NOTIFICATION_EXTENSIONS_READY);
+  registrar_.Remove(this, chrome::NOTIFICATION_EXTENSIONS_READY,
+      content::Source<Profile>(profile_));
+
+  MigrateTheme();
+  set_ready();
+
+  // Send notification in case anyone requested data and cached it when the
+  // theme service was not ready yet.
+  NotifyThemeChanged();
 }
 
 void ThemeService::SetTheme(const Extension* extension) {
-  DCHECK(extension->is_theme());
-  ExtensionService* service =
-      extensions::ExtensionSystem::Get(profile_)->extension_service();
-  if (!service->IsExtensionEnabled(extension->id())) {
-    // |extension| is disabled when reverting to the previous theme via an
-    // infobar.
-    service->EnableExtension(extension->id());
-    // Enabling the extension will call back to SetTheme().
-    return;
-  }
-
-  std::string previous_theme_id = GetThemeID();
-
   // Clear our image cache.
   FreePlatformCaches();
 
+  DCHECK(extension);
+  DCHECK(extension->is_theme());
+  if (DCHECK_IS_ON()) {
+    ExtensionService* service =
+        extensions::ExtensionSystem::Get(profile_)->extension_service();
+    DCHECK(service);
+    DCHECK(service->GetExtensionById(extension->id(), false));
+  }
+
   BuildFromExtension(extension);
   SaveThemeID(extension->id());
 
   NotifyThemeChanged();
   content::RecordAction(UserMetricsAction("Themes_Installed"));
-
-  if (previous_theme_id != kDefaultThemeID &&
-      previous_theme_id != extension->id()) {
-    // Disable the old theme.
-    service->DisableExtension(previous_theme_id,
-                              extensions::Extension::DISABLE_USER_ACTION);
-  }
 }
 
 void ThemeService::SetCustomDefaultTheme(
@@ -297,41 +243,25 @@
   return false;
 }
 
-void ThemeService::RemoveUnusedThemes(bool ignore_infobars) {
+void ThemeService::RemoveUnusedThemes() {
   // We do not want to garbage collect themes on startup (|ready_| is false).
-  // Themes will get garbage collected after |kRemoveUnusedThemesStartupDelay|.
+  // Themes will get garbage collected once
+  // ExtensionService::GarbageCollectExtensions() runs.
   if (!profile_ || !ready_)
     return;
-  if (!ignore_infobars && number_of_infobars_ != 0)
-    return;
 
   ExtensionService* service = profile_->GetExtensionService();
   if (!service)
     return;
   std::string current_theme = GetThemeID();
   std::vector<std::string> remove_list;
-  scoped_ptr<const ExtensionSet> extensions(
-      service->GenerateInstalledExtensionsSet());
-  extensions::ExtensionPrefs* prefs = service->extension_prefs();
+  const ExtensionSet* extensions = service->extensions();
   for (ExtensionSet::const_iterator it = extensions->begin();
        it != extensions->end(); ++it) {
-    const extensions::Extension* extension = *it;
-    if (extension->is_theme() &&
-        extension->id() != current_theme) {
-      // Only uninstall themes which are not disabled or are disabled with
-      // reason DISABLE_USER_ACTION. We cannot blanket uninstall all disabled
-      // themes because externally installed themes are initially disabled.
-      int disable_reason = prefs->GetDisableReasons(extension->id());
-      if (!prefs->IsExtensionDisabled(extension->id()) ||
-          disable_reason == Extension::DISABLE_USER_ACTION) {
-        remove_list.push_back((*it)->id());
-      }
+    if ((*it)->is_theme() && (*it)->id() != current_theme) {
+      remove_list.push_back((*it)->id());
     }
   }
-  // TODO: Garbage collect all unused themes. This method misses themes which
-  // are installed but not loaded because they are blacklisted by a management
-  // policy provider.
-
   for (size_t i = 0; i < remove_list.size(); ++i)
     service->UninstallExtension(remove_list[i], false, NULL);
 }
@@ -343,10 +273,8 @@
     SetManagedUserTheme();
     return;
   }
-  if (ready_) {
-    ClearAllThemeData();
-    NotifyThemeChanged();
-  }
+  ClearAllThemeData();
+  NotifyThemeChanged();
 }
 
 void ThemeService::SetNativeTheme() {
@@ -378,6 +306,9 @@
 }
 
 void ThemeService::ClearAllThemeData() {
+  if (!ready_)
+    return;
+
   SwapThemeSupplier(NULL);
 
   // Clear our image cache.
@@ -386,14 +317,7 @@
   profile_->GetPrefs()->ClearPref(prefs::kCurrentThemePackFilename);
   SaveThemeID(kDefaultThemeID);
 
-  // There should be no more infobars. This may not be the case because of
-  // http://crbug.com/62154
-  // RemoveUnusedThemes is called on a task because ClearAllThemeData() may
-  // be called as a result of NOTIFICATION_EXTENSION_UNLOADED.
-  base::MessageLoop::current()->PostTask(FROM_HERE,
-      base::Bind(&ThemeService::RemoveUnusedThemes,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 true));
+  RemoveUnusedThemes();
 }
 
 void ThemeService::LoadThemePrefs() {
@@ -424,9 +348,16 @@
   if (loaded_pack) {
     content::RecordAction(UserMetricsAction("Themes.Loaded"));
     set_ready();
+  } else {
+    // TODO(erg): We need to pop up a dialog informing the user that their
+    // theme is being migrated.
+    ExtensionService* service =
+        extensions::ExtensionSystem::Get(profile_)->extension_service();
+    if (service && service->is_ready()) {
+      MigrateTheme();
+      set_ready();
+    }
   }
-  // Else: wait for the extension service to be ready so that the theme pack
-  // can be recreated from the extension.
 }
 
 void ThemeService::NotifyThemeChanged() {
@@ -456,41 +387,16 @@
 }
 #endif
 
-void ThemeService::OnExtensionServiceReady() {
-  if (!ready_) {
-    // If the ThemeService is not ready yet, the custom theme data pack needs to
-    // be recreated from the extension.
-    MigrateTheme();
-    set_ready();
-
-    // Send notification in case anyone requested data and cached it when the
-    // theme service was not ready yet.
-    NotifyThemeChanged();
-  }
-
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_INSTALLED,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_LOADED,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_ENABLED,
-                 content::Source<Profile>(profile_));
-  registrar_.Add(this,
-                 chrome::NOTIFICATION_EXTENSION_UNLOADED,
-                 content::Source<Profile>(profile_));
-
-  base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
-      base::Bind(&ThemeService::RemoveUnusedThemes,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 false),
-      base::TimeDelta::FromSeconds(kRemoveUnusedThemesStartupDelay));
+void ThemeService::SwapThemeSupplier(
+    scoped_refptr<CustomThemeSupplier> theme_supplier) {
+  if (theme_supplier_.get())
+    theme_supplier_->StopUsingTheme();
+  theme_supplier_ = theme_supplier;
+  if (theme_supplier_.get())
+    theme_supplier_->StartUsingTheme();
 }
 
 void ThemeService::MigrateTheme() {
-  // TODO(erg): We need to pop up a dialog informing the user that their
-  // theme is being migrated.
   ExtensionService* service =
       extensions::ExtensionSystem::Get(profile_)->extension_service();
   const Extension* extension = service ?
@@ -506,15 +412,6 @@
   }
 }
 
-void ThemeService::SwapThemeSupplier(
-    scoped_refptr<CustomThemeSupplier> theme_supplier) {
-  if (theme_supplier_.get())
-    theme_supplier_->StopUsingTheme();
-  theme_supplier_ = theme_supplier;
-  if (theme_supplier_.get())
-    theme_supplier_->StartUsingTheme();
-}
-
 void ThemeService::SavePackName(const base::FilePath& pack_path) {
   profile_->GetPrefs()->SetFilePath(
       prefs::kCurrentThemePackFilename, pack_path);
@@ -566,7 +463,7 @@
   number_of_infobars_--;
 
   if (number_of_infobars_ == 0)
-    RemoveUnusedThemes(false);
+    RemoveUnusedThemes();
 }
 
 ThemeSyncableService* ThemeService::GetThemeSyncableService() const {
diff --git a/chrome/browser/themes/theme_service.h b/chrome/browser/themes/theme_service.h
index 37e951f..b573d2e 100644
--- a/chrome/browser/themes/theme_service.h
+++ b/chrome/browser/themes/theme_service.h
@@ -13,7 +13,6 @@
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
 #include "base/threading/non_thread_safe.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 #include "content/public/browser/notification_observer.h"
@@ -85,11 +84,10 @@
       int id,
       ui::ScaleFactor scale_factor) const OVERRIDE;
 #if defined(OS_MACOSX)
-  virtual NSImage* GetNSImageNamed(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSImageColorNamed(int id,
-                                        bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColor(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColorTint(int id, bool allow_default) const OVERRIDE;
+  virtual NSImage* GetNSImageNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSImageColorNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSColor(int id) const OVERRIDE;
+  virtual NSColor* GetNSColorTint(int id) const OVERRIDE;
   virtual NSGradient* GetNSGradient(int id) const OVERRIDE;
 #elif defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)
   // This mismatch between what this class defines and whether or not it
@@ -136,10 +134,8 @@
   // destroyed, uninstalls all themes that aren't the currently selected.
   void OnInfobarDestroyed();
 
-  // Uninstall theme extensions which are no longer in use. |ignore_infobars| is
-  // whether unused themes should be removed despite a theme infobar being
-  // visible.
-  void RemoveUnusedThemes(bool ignore_infobars);
+  // Remove preference values for themes that are no longer in use.
+  void RemoveUnusedThemes();
 
   // Returns the syncable service for syncing theme. The returned service is
   // owned by |this| object.
@@ -174,7 +170,7 @@
 #endif  // OS_MACOSX
 
   // Clears the platform-specific caches. Do not call directly; it's called
-  // from ClearCaches().
+  // from ClearAllThemeData().
   virtual void FreePlatformCaches();
 
   Profile* profile() const { return profile_; }
@@ -185,20 +181,22 @@
     return theme_supplier_.get();
   }
 
+  // True if the theme service is ready to be used.
+  // TODO(pkotwicz): Add DCHECKS to the theme service's getters once
+  // ThemeSource no longer uses the ThemeService when it is not ready.
+  bool ready_;
+
  private:
   friend class theme_service_internal::ThemeServiceTest;
 
-  // Called when the extension service is ready.
-  void OnExtensionServiceReady();
-
-  // Migrate the theme to the new theme pack schema by recreating the data pack
-  // from the extension.
-  void MigrateTheme();
-
   // Replaces the current theme supplier with a new one and calls
   // StopUsingTheme() or StartUsingTheme() as appropriate.
   void SwapThemeSupplier(scoped_refptr<CustomThemeSupplier> theme_supplier);
 
+  // Migrate the theme to the new theme pack schema by recreating the data pack
+  // from the extension.
+  void MigrateTheme();
+
   // Saves the filename of the cached theme pack.
   void SavePackName(const base::FilePath& pack_path);
 
@@ -225,11 +223,12 @@
   typedef std::map<int, GdkPixbuf*> GdkPixbufMap;
   mutable GdkPixbufMap gdk_pixbufs_;
 #elif defined(OS_MACOSX)
+  // |nsimage_cache_| retains the images it has cached.
   typedef std::map<int, NSImage*> NSImageMap;
   mutable NSImageMap nsimage_cache_;
 
-  // The bool member of the pair is whether the color is a default color.
-  typedef std::map<int, std::pair<NSColor*, bool> > NSColorMap;
+  // |nscolor_cache_| retains the colors it has cached.
+  typedef std::map<int, NSColor*> NSColorMap;
   mutable NSColorMap nscolor_cache_;
 
   typedef std::map<int, NSGradient*> NSGradientMap;
@@ -239,20 +238,8 @@
   ui::ResourceBundle& rb_;
   Profile* profile_;
 
-  // True if the theme service is ready to be used.
-  // TODO(pkotwicz): Add DCHECKS to the theme service's getters once
-  // ThemeSource no longer uses the ThemeService when it is not ready.
-  bool ready_;
-
   scoped_refptr<CustomThemeSupplier> theme_supplier_;
 
-  // The id of the theme extension which has just been installed but has not
-  // been loaded yet. The theme extension with |installed_pending_load_id_| may
-  // never be loaded if the install is due to updating a disabled theme.
-  // |pending_install_id_| should be set to |kDefaultThemeID| if there are no
-  // recently installed theme extensions
-  std::string installed_pending_load_id_;
-
   // The number of infobars currently displayed.
   int number_of_infobars_;
 
@@ -260,8 +247,6 @@
 
   scoped_ptr<ThemeSyncableService> theme_syncable_service_;
 
-  base::WeakPtrFactory<ThemeService> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(ThemeService);
 };
 
diff --git a/chrome/browser/themes/theme_service_mac.mm b/chrome/browser/themes/theme_service_mac.mm
index c39944c..3644f1f 100644
--- a/chrome/browser/themes/theme_service_mac.mm
+++ b/chrome/browser/themes/theme_service_mac.mm
@@ -35,12 +35,9 @@
 
 }  // namespace
 
-NSImage* ThemeService::GetNSImageNamed(int id, bool allow_default) const {
+NSImage* ThemeService::GetNSImageNamed(int id) const {
   DCHECK(CalledOnValidThread());
 
-  if (!allow_default && !HasCustomImage(id))
-    return nil;
-
   // Check to see if we already have the image in the cache.
   NSImageMap::const_iterator nsimage_iter = nsimage_cache_.find(id);
   if (nsimage_iter != nsimage_cache_.end())
@@ -88,86 +85,53 @@
   return empty_image;
 }
 
-NSColor* ThemeService::GetNSImageColorNamed(int id, bool allow_default) const {
+NSColor* ThemeService::GetNSImageColorNamed(int id) const {
   DCHECK(CalledOnValidThread());
 
   // Check to see if we already have the color in the cache.
   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
-  if (nscolor_iter != nscolor_cache_.end()) {
-    bool cached_is_default = nscolor_iter->second.second;
-    if (!cached_is_default || allow_default)
-      return nscolor_iter->second.first;
-  }
+  if (nscolor_iter != nscolor_cache_.end())
+    return nscolor_iter->second;
 
-  NSImage* image = GetNSImageNamed(id, allow_default);
+  NSImage* image = GetNSImageNamed(id);
   if (!image)
     return nil;
   NSColor* image_color = [NSColor colorWithPatternImage:image];
 
   // We loaded successfully.  Cache the color.
-  if (image_color) {
-    nscolor_cache_[id] = std::make_pair([image_color retain],
-                                        !HasCustomImage(id));
-  }
+  if (image_color)
+    nscolor_cache_[id] = [image_color retain];
 
   return image_color;
 }
 
-NSColor* ThemeService::GetNSColor(int id, bool allow_default) const {
+NSColor* ThemeService::GetNSColor(int id) const {
   DCHECK(CalledOnValidThread());
 
   // Check to see if we already have the color in the cache.
   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
-  if (nscolor_iter != nscolor_cache_.end()) {
-    bool cached_is_default = nscolor_iter->second.second;
-    if (!cached_is_default || allow_default)
-      return nscolor_iter->second.first;
-  }
+  if (nscolor_iter != nscolor_cache_.end())
+    return nscolor_iter->second;
 
-  bool is_default = false;
-  SkColor sk_color;
-  if (theme_supplier_.get() && theme_supplier_->GetColor(id, &sk_color)) {
-    is_default = false;
-  } else {
-    is_default = true;
-    sk_color = ThemeProperties::GetDefaultColor(id);
-  }
-
-  if (is_default && !allow_default)
-    return nil;
-
+  SkColor sk_color = GetColor(id);
   NSColor* color = gfx::SkColorToCalibratedNSColor(sk_color);
 
   // We loaded successfully.  Cache the color.
   if (color)
-    nscolor_cache_[id] = std::make_pair([color retain], is_default);
+    nscolor_cache_[id] = [color retain];
 
   return color;
 }
 
-NSColor* ThemeService::GetNSColorTint(int id, bool allow_default) const {
+NSColor* ThemeService::GetNSColorTint(int id) const {
   DCHECK(CalledOnValidThread());
 
   // Check to see if we already have the color in the cache.
   NSColorMap::const_iterator nscolor_iter = nscolor_cache_.find(id);
-  if (nscolor_iter != nscolor_cache_.end()) {
-    bool cached_is_default = nscolor_iter->second.second;
-    if (!cached_is_default || allow_default)
-      return nscolor_iter->second.first;
-  }
+  if (nscolor_iter != nscolor_cache_.end())
+    return nscolor_iter->second;
 
-  bool is_default = false;
-  color_utils::HSL tint;
-  if (theme_supplier_.get() && theme_supplier_->GetTint(id, &tint)) {
-    is_default = false;
-  } else {
-    is_default = true;
-    tint = ThemeProperties::GetDefaultTint(id);
-  }
-
-  if (is_default && !allow_default)
-    return nil;
-
+  color_utils::HSL tint = GetTint(id);
   NSColor* tint_color = nil;
   if (tint.h == -1 && tint.s == -1 && tint.l == -1) {
     tint_color = [NSColor blackColor];
@@ -183,7 +147,7 @@
 
   // We loaded successfully.  Cache the color.
   if (tint_color)
-    nscolor_cache_[id] = std::make_pair([tint_color retain], is_default);
+    nscolor_cache_[id] = [tint_color retain];
 
   return tint_color;
 }
@@ -312,7 +276,7 @@
   // Free colors.
   for (NSColorMap::iterator i = nscolor_cache_.begin();
        i != nscolor_cache_.end(); i++) {
-    [i->second.first release];
+    [i->second release];
   }
   nscolor_cache_.clear();
 
diff --git a/chrome/browser/themes/theme_service_unittest.cc b/chrome/browser/themes/theme_service_unittest.cc
index 499b2ee..4168f96 100644
--- a/chrome/browser/themes/theme_service_unittest.cc
+++ b/chrome/browser/themes/theme_service_unittest.cc
@@ -4,19 +4,14 @@
 
 #include "chrome/browser/themes/theme_service.h"
 
-#include "base/file_util.h"
-#include "base/path_service.h"
-#include "chrome/browser/chrome_notification_types.h"
+#include "base/json/json_reader.h"
 #include "chrome/browser/extensions/extension_service_unittest.h"
-#include "chrome/browser/extensions/unpacked_installer.h"
 #include "chrome/browser/themes/custom_theme_supplier.h"
 #include "chrome/browser/themes/theme_service_factory.h"
-#include "chrome/common/chrome_paths.h"
 #include "chrome/common/extensions/extension.h"
 #include "chrome/common/extensions/extension_manifest_constants.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
-#include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace theme_service_internal {
@@ -26,57 +21,25 @@
   ThemeServiceTest() {}
   virtual ~ThemeServiceTest() {}
 
-  // Moves a minimal theme to |temp_dir_path| and unpacks it from that
-  // directory.
-  std::string LoadUnpackedThemeAt(const base::FilePath& temp_dir) {
-    base::FilePath dst_manifest_path = temp_dir.AppendASCII("manifest.json");
-    base::FilePath test_data_dir;
-    EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
-    base::FilePath src_manifest_path =
-        test_data_dir.AppendASCII("extensions/theme_minimal/manifest.json");
-    EXPECT_TRUE(base::CopyFile(src_manifest_path, dst_manifest_path));
-
-    scoped_refptr<extensions::UnpackedInstaller> installer(
-        extensions::UnpackedInstaller::Create(service_));
-    content::WindowedNotificationObserver observer(
-        chrome::NOTIFICATION_EXTENSION_LOADED,
-        content::Source<Profile>(profile_.get()));
-    installer->Load(temp_dir);
-    observer.Wait();
-
-    std::string extension_id =
-        content::Details<extensions::Extension>(observer.details())->id();
-
-    // Let the ThemeService finish creating the theme pack.
-    base::MessageLoop::current()->RunUntilIdle();
-
-    return extension_id;
-  }
-
-  // Update the theme with |extension_id|.
-  void UpdateUnpackedTheme(const std::string& extension_id) {
-    int updated_notification = service_->IsExtensionEnabled(extension_id) ?
-        chrome::NOTIFICATION_EXTENSION_LOADED :
-        chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED;
-
-    const base::FilePath& path =
-        service_->GetInstalledExtension(extension_id)->path();
-
-    scoped_refptr<extensions::UnpackedInstaller> installer(
-        extensions::UnpackedInstaller::Create(service_));
-    content::WindowedNotificationObserver observer(updated_notification,
-        content::Source<Profile>(profile_.get()));
-    installer->Load(path);
-    observer.Wait();
-
-    // Let the ThemeService finish creating the theme pack.
-    base::MessageLoop::current()->RunUntilIdle();
+  scoped_refptr<extensions::Extension> MakeThemeExtension(base::FilePath path) {
+    DictionaryValue source;
+    source.SetString(extension_manifest_keys::kName, "theme");
+    source.Set(extension_manifest_keys::kTheme, new DictionaryValue());
+    source.SetString(extension_manifest_keys::kUpdateURL, "http://foo.com");
+    source.SetString(extension_manifest_keys::kVersion, "0.0.0.0");
+    std::string error;
+    scoped_refptr<extensions::Extension> extension =
+        extensions::Extension::Create(
+            path, extensions::Manifest::EXTERNAL_PREF_DOWNLOAD,
+            source, extensions::Extension::NO_FLAGS, &error);
+    EXPECT_TRUE(extension.get());
+    EXPECT_EQ("", error);
+    return extension;
   }
 
   virtual void SetUp() {
     ExtensionServiceTestBase::SetUp();
     InitializeEmptyExtensionService();
-    service_->Init();
   }
 
   const CustomThemeSupplier* get_theme_supplier(ThemeService* theme_service) {
@@ -87,128 +50,45 @@
 // Installs then uninstalls a theme and makes sure that the ThemeService
 // reverts to the default theme after the uninstall.
 TEST_F(ThemeServiceTest, ThemeInstallUninstall) {
-  ThemeService* theme_service =
-      ThemeServiceFactory::GetForProfile(profile_.get());
-  theme_service->UseDefaultTheme();
-  // Let the ThemeService uninstall unused themes.
-  base::MessageLoop::current()->RunUntilIdle();
-
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  const std::string& extension_id = LoadUnpackedThemeAt(temp_dir.path());
-  EXPECT_FALSE(theme_service->UsingDefaultTheme());
-  EXPECT_EQ(extension_id, theme_service->GetThemeID());
-
-  // Now uninstall the extension, should revert to the default theme.
-  service_->UninstallExtension(extension_id, false, NULL);
-  EXPECT_TRUE(theme_service->UsingDefaultTheme());
-}
-
-// Test that a theme extension is disabled when not in use. A theme may be
-// installed but not in use if it there is an infobar to revert to the previous
-// theme.
-TEST_F(ThemeServiceTest, DisableUnusedTheme) {
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
-  // Let the ThemeService uninstall unused themes.
+  scoped_refptr<extensions::Extension> extension =
+      MakeThemeExtension(temp_dir.path());
+  service_->FinishInstallationForTest(extension.get());
+  // Let ThemeService finish creating the theme pack.
   base::MessageLoop::current()->RunUntilIdle();
-
-  base::ScopedTempDir temp_dir1;
-  ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
-  base::ScopedTempDir temp_dir2;
-  ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
-
-  // 1) Installing a theme should disable the previously active theme.
-  const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
   EXPECT_FALSE(theme_service->UsingDefaultTheme());
-  EXPECT_EQ(extension1_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
+  EXPECT_EQ(extension->id(), theme_service->GetThemeID());
 
-  // Show an infobar to prevent the current theme from being uninstalled.
-  theme_service->OnInfobarDisplayed();
-
-  const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
-  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
-  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
-      ExtensionService::INCLUDE_DISABLED));
-
-  // 2) Enabling a disabled theme extension should swap the current theme.
-  service_->EnableExtension(extension1_id);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(extension1_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->IsExtensionEnabled(extension1_id));
-  EXPECT_TRUE(service_->GetExtensionById(extension2_id,
-      ExtensionService::INCLUDE_DISABLED));
-
-  // 3) Using SetTheme() with a disabled theme should enable and set the
-  // theme. This is the case when the user reverts to the previous theme
-  // via an infobar.
-  const extensions::Extension* extension2 =
-      service_->GetInstalledExtension(extension2_id);
-  theme_service->SetTheme(extension2);
-  base::MessageLoop::current()->RunUntilIdle();
-  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->IsExtensionEnabled(extension2_id));
-  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
-      ExtensionService::INCLUDE_DISABLED));
-
-  // 4) Disabling the current theme extension should revert to the default theme
-  // and uninstall any installed theme extensions.
-  theme_service->OnInfobarDestroyed();
-  EXPECT_FALSE(theme_service->UsingDefaultTheme());
-  service_->DisableExtension(extension2_id,
-      extensions::Extension::DISABLE_USER_ACTION);
-  base::MessageLoop::current()->RunUntilIdle();
+  // Now unload the extension, should revert to the default theme.
+  service_->UnloadExtension(extension->id(),
+                            extension_misc::UNLOAD_REASON_UNINSTALL);
   EXPECT_TRUE(theme_service->UsingDefaultTheme());
-  EXPECT_FALSE(service_->GetInstalledExtension(extension1_id));
-  EXPECT_FALSE(service_->GetInstalledExtension(extension2_id));
 }
 
-// Test the ThemeService's behavior when a theme is upgraded.
+// Upgrades a theme and ensures that the ThemeService does not revert to the
+// default theme.
 TEST_F(ThemeServiceTest, ThemeUpgrade) {
-  // Setup.
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   ThemeService* theme_service =
       ThemeServiceFactory::GetForProfile(profile_.get());
   theme_service->UseDefaultTheme();
-  // Let the ThemeService uninstall unused themes.
+  scoped_refptr<extensions::Extension> extension =
+      MakeThemeExtension(temp_dir.path());
+  service_->FinishInstallationForTest(extension.get());
+  // Let ThemeService finish creating the theme pack.
   base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_FALSE(theme_service->UsingDefaultTheme());
+  EXPECT_EQ(extension->id(), theme_service->GetThemeID());
 
-  theme_service->OnInfobarDisplayed();
-
-  base::ScopedTempDir temp_dir1;
-  ASSERT_TRUE(temp_dir1.CreateUniqueTempDir());
-  base::ScopedTempDir temp_dir2;
-  ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
-
-  const std::string& extension1_id = LoadUnpackedThemeAt(temp_dir1.path());
-  const std::string& extension2_id = LoadUnpackedThemeAt(temp_dir2.path());
-
-  // Test the initial state.
-  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
-      ExtensionService::INCLUDE_DISABLED));
-  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
-
-  // 1) Upgrading the current theme should not revert to the default theme.
-  content::WindowedNotificationObserver theme_change_observer(
-      chrome::NOTIFICATION_BROWSER_THEME_CHANGED,
-      content::Source<ThemeService>(theme_service));
-  UpdateUnpackedTheme(extension2_id);
-
-  // The ThemeService should have sent an theme change notification even though
-  // the id of the current theme did not change.
-  theme_change_observer.Wait();
-
-  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
-      ExtensionService::INCLUDE_DISABLED));
-
-  // 2) Upgrading a disabled theme should not change the current theme.
-  UpdateUnpackedTheme(extension1_id);
-  EXPECT_EQ(extension2_id, theme_service->GetThemeID());
-  EXPECT_TRUE(service_->GetExtensionById(extension1_id,
-      ExtensionService::INCLUDE_DISABLED));
+  // Now unload the extension, should revert to the default theme.
+  service_->UnloadExtension(extension->id(),
+                            extension_misc::UNLOAD_REASON_UPDATE);
+  EXPECT_FALSE(theme_service->UsingDefaultTheme());
 }
 
 // Checks that managed users have their own default theme.
diff --git a/chrome/browser/themes/theme_syncable_service.cc b/chrome/browser/themes/theme_syncable_service.cc
index 55d3f74..3389443 100644
--- a/chrome/browser/themes/theme_syncable_service.cc
+++ b/chrome/browser/themes/theme_syncable_service.cc
@@ -208,7 +208,7 @@
     string id(theme_specifics.custom_theme_id());
     GURL update_url(theme_specifics.custom_theme_update_url());
     DVLOG(1) << "Applying theme " << id << " with update_url " << update_url;
-    ExtensionService* extensions_service =
+    ExtensionServiceInterface* extensions_service =
         extensions::ExtensionSystem::Get(profile_)->extension_service();
     CHECK(extensions_service);
     const extensions::Extension* extension =
@@ -218,12 +218,8 @@
         DVLOG(1) << "Extension " << id << " is not a theme; aborting";
         return;
       }
-      int disabled_reasons =
-          extensions_service->extension_prefs()->GetDisableReasons(id);
-      if (!extensions_service->IsExtensionEnabled(id) &&
-          disabled_reasons != extensions::Extension::DISABLE_USER_ACTION) {
-        DVLOG(1) << "Theme " << id << " is disabled with reason "
-                 << disabled_reasons << "; aborting";
+      if (!extensions_service->IsExtensionEnabled(id)) {
+        DVLOG(1) << "Theme " << id << " is not enabled; aborting";
         return;
       }
       // An enabled theme extension with the given id was found, so
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index 77b7101..1d0d4f6 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/time_format.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/user_metrics.h"
 #include "grit/chromium_strings.h"
@@ -417,14 +416,6 @@
   }
 }
 
-string16 ChromeShellDelegate::GetTimeRemainingString(base::TimeDelta delta) {
-  return TimeFormat::TimeRemainingLong(delta);
-}
-
-string16 ChromeShellDelegate::GetTimeDurationLongString(base::TimeDelta delta) {
-  return TimeFormat::TimeDurationLong(delta);
-}
-
 ui::MenuModel* ChromeShellDelegate::CreateContextMenu(aura::RootWindow* root) {
   DCHECK(launcher_delegate_);
   // Don't show context menu for exclusive app runtime mode.
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index c6e41db..ef8ea0f 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -88,8 +88,6 @@
   virtual void HandleMediaNextTrack() OVERRIDE;
   virtual void HandleMediaPlayPause() OVERRIDE;
   virtual void HandleMediaPrevTrack() OVERRIDE;
-  virtual string16 GetTimeRemainingString(base::TimeDelta delta) OVERRIDE;
-  virtual string16 GetTimeDurationLongString(base::TimeDelta delta) OVERRIDE;
   virtual void SaveScreenMagnifierScale(double scale) OVERRIDE;
   virtual double GetSavedScreenMagnifierScale() OVERRIDE;
   virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root) OVERRIDE;
diff --git a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
index 4fa26a4..f32790d 100644
--- a/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/app_shortcut_launcher_item_controller.cc
@@ -231,6 +231,19 @@
         return web_contents;
     }
   }
+  // Coming here our application was not in the LRU list. This could have
+  // happened because it did never get activated yet. So check the browser list
+  // as well.
+  for (BrowserList::const_iterator it = ash_browser_list->begin();
+       it != ash_browser_list->end(); ++it) {
+    Browser* browser = *it;
+    TabStripModel* tab_strip = browser->tab_strip_model();
+    for (int index = 0; index < tab_strip->count(); index++) {
+      content::WebContents* web_contents = tab_strip->GetWebContentsAt(index);
+      if (WebContentMatchesApp(extension, refocus_pattern, web_contents))
+        return web_contents;
+    }
+  }
   return NULL;
 }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc
index 8a16e16..8c0cfba 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_per_app_browsertest.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/browser/ui/host_desktop.h"
@@ -1344,6 +1345,66 @@
   EXPECT_EQ(window1, ash::wm::GetActiveWindow());
 }
 
+// Checks that after a session restore, we do not start applications on an
+// activation.
+IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest,
+    ActivateAfterSessionRestore) {
+  EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+
+  // Create a known application.
+  ChromeLauncherController* controller =
+      static_cast<ChromeLauncherController*>(launcher_->delegate());
+  ash::LauncherID shortcut_id = CreateShortcut("app1");
+
+  // Create a new browser - without activating it - and load an "app" into it.
+  Browser::CreateParams params =
+      Browser::CreateParams(profile(), chrome::GetActiveDesktop());
+  params.initial_show_state = ui::SHOW_STATE_INACTIVE;
+  Browser* browser2 = new Browser(params);
+  controller->SetRefocusURLPatternForTest(
+      shortcut_id, GURL("http://www.example.com/path/*"));
+  std::string url = "http://www.example.com/path/bla";
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser2,
+      GURL(url),
+      NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // Remember the number of tabs for each browser.
+  TabStripModel* tab_strip = browser()->tab_strip_model();
+  int tab_count1 = tab_strip->count();
+  TabStripModel* tab_strip2 = browser2->tab_strip_model();
+  int tab_count2 = tab_strip2->count();
+
+  // Check that we have two browsers and the inactive browser remained inactive.
+  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
+            browser());
+  // Check that the LRU browser list does only contain the original browser.
+  BrowserList* ash_browser_list =
+      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
+  BrowserList::const_reverse_iterator it =
+      ash_browser_list->begin_last_active();
+  EXPECT_EQ(*it, browser());
+  ++it;
+  EXPECT_EQ(it, ash_browser_list->end_last_active());
+
+  // Now request to either activate an existing app or create a new one.
+  controller->ItemSelected(*model_->ItemByID(shortcut_id),
+                           ui::KeyEvent(ui::ET_KEY_RELEASED,
+                                        ui::VKEY_RETURN,
+                                        0,
+                                        false));
+
+  // Check that we have set focus on the existing application and nothing new
+  // was created.
+  EXPECT_EQ(2u, chrome::GetTotalBrowserCount());
+  EXPECT_EQ(tab_count1, tab_strip->count());
+  EXPECT_EQ(tab_count2, tab_strip2->count());
+  EXPECT_EQ(chrome::FindBrowserWithWindow(ash::wm::GetActiveWindow()),
+            browser2);
+}
+
 // Do various drag and drop interaction tests between the application list and
 // the launcher.
 IN_PROC_BROWSER_TEST_F(LauncherPerAppAppBrowserTest, DragAndDrop) {
diff --git a/chrome/browser/ui/ash/screenshot_taker_unittest.cc b/chrome/browser/ui/ash/screenshot_taker_unittest.cc
index 439a6a1..a35339a 100644
--- a/chrome/browser/ui/ash/screenshot_taker_unittest.cc
+++ b/chrome/browser/ui/ash/screenshot_taker_unittest.cc
@@ -14,9 +14,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/scoped_testing_local_state.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "chrome/test/base/testing_profile_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_utils.h"
 #include "ui/aura/root_window.h"
@@ -36,13 +36,10 @@
 
   virtual void SetUp() {
     AshTestBase::SetUp();
-    local_state_.reset(
-        new ScopedTestingLocalState(TestingBrowserProcess::GetGlobal()));
   }
 
   virtual void TearDown() {
     RunAllPendingInMessageLoop();
-    local_state_.reset();
     AshTestBase::TearDown();
   }
 
@@ -87,7 +84,6 @@
     EXPECT_TRUE(screenshot_complete_);
   }
 
-  scoped_ptr<ScopedTestingLocalState> local_state_;
   bool running_;
   bool screenshot_complete_;
   ScreenshotTakerObserver::Result screenshot_result_;
@@ -98,14 +94,18 @@
 };
 
 TEST_F(ScreenshotTakerTest, TakeScreenshot) {
-  TestingProfile profile;
+  scoped_ptr<TestingProfileManager> profile_manager(
+      new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
+  ASSERT_TRUE(profile_manager->SetUp());
+  TestingProfile* profile =
+      profile_manager->CreateTestingProfile("test_profile");
   ScreenshotTaker screenshot_taker;
   screenshot_taker.AddObserver(this);
   base::ScopedTempDir directory;
   ASSERT_TRUE(directory.CreateUniqueTempDir());
   SetScreenshotDirectoryForTest(&screenshot_taker, directory.path());
   SetScreenshotBasenameForTest(&screenshot_taker, "Screenshot");
-  SetScreenshotProfileForTest(&screenshot_taker, &profile);
+  SetScreenshotProfileForTest(&screenshot_taker, profile);
 
   EXPECT_TRUE(screenshot_taker.CanTakeScreenshot());
 
diff --git a/chrome/browser/ui/autofill/autofill_credit_card_bubble.h b/chrome/browser/ui/autofill/autofill_credit_card_bubble.h
index ba91afe..2ef632a 100644
--- a/chrome/browser/ui/autofill/autofill_credit_card_bubble.h
+++ b/chrome/browser/ui/autofill/autofill_credit_card_bubble.h
@@ -28,16 +28,16 @@
 
   virtual ~AutofillCreditCardBubble();
 
-  // Visually reveal the dialog bubble.
+  // Visually reveals the dialog bubble.
   virtual void Show() = 0;
 
-  // Hide the bubble from view.
+  // Hides the bubble from view.
   virtual void Hide() = 0;
 
-  // Whether the bubble is currently in the process of hiding itself.
+  // Returns whether the bubble is currently in the process of hiding itself.
   virtual bool IsHiding() const = 0;
 
-  // Create a bubble view that's operated by |controller| and owned by the
+  // Creates a bubble view that's operated by |controller| and owned by the
   // platform's widget or view management framework. |controller| is invalid
   // while the bubble is closing.
   static base::WeakPtr<AutofillCreditCardBubble> Create(
diff --git a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.cc b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.cc
index 70d0978..5d79a69 100644
--- a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.cc
+++ b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.cc
@@ -7,9 +7,6 @@
 #include <climits>
 #include <string>
 
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
@@ -44,6 +41,7 @@
 // TODO(dbeam): add back a sensible limit once it's decided or remove
 // kMaxGeneratedCardTimesToShow if this behavior is finalized.
 static const int kMaxGeneratedCardTimesToShow = INT_MAX;
+static const base::char16 kRangeSeparator = '|';
 static const char kWalletGeneratedCardLearnMoreLink[] =
     "http://support.google.com/wallet/bin/answer.py?hl=en&answer=2740044";
 
@@ -62,6 +60,8 @@
       weak_ptr_factory_(this) {}
 
 AutofillCreditCardBubbleController::~AutofillCreditCardBubbleController() {
+  // In the case that the tab is closed, the controller can be deleted while the
+  // bubble is showing. Always calling |Hide()| ensures the bubble is closed.
   Hide();
 }
 
@@ -115,25 +115,27 @@
 }
 
 base::string16 AutofillCreditCardBubbleController::BubbleTitle() const {
-  return !IsGeneratedCardBubble() ? ASCIIToUTF16("Lorem ipsum, savum cardum") :
+  return !IsGeneratedCardBubble() ?
+      ASCIIToUTF16("Lorem ipsum, savum cardum") :
       l10n_util::GetStringUTF16(
           IDS_AUTOFILL_CREDIT_CARD_BUBBLE_GENERATED_TITLE);
 }
 
 base::string16 AutofillCreditCardBubbleController::BubbleText() const {
-  DCHECK(IsSetup());
+  DCHECK(IsSetUp());
   return bubble_text_;
 }
 
 const std::vector<ui::Range>& AutofillCreditCardBubbleController::
     BubbleTextRanges() const {
-  DCHECK(IsSetup());
+  DCHECK(IsSetUp());
   return bubble_text_ranges_;
 }
 
 base::string16 AutofillCreditCardBubbleController::LinkText() const {
-  return l10n_util::GetStringUTF16(IsGeneratedCardBubble() ?
-      IDS_LEARN_MORE : IDS_AUTOFILL_CREDIT_CARD_BUBBLE_MANAGE_CARDS);
+  return l10n_util::GetStringUTF16(
+      IsGeneratedCardBubble() ? IDS_LEARN_MORE :
+                                IDS_AUTOFILL_CREDIT_CARD_BUBBLE_MANAGE_CARDS);
 }
 
 void AutofillCreditCardBubbleController::OnAnchorClicked() {
@@ -143,6 +145,7 @@
 void AutofillCreditCardBubbleController::OnLinkClicked() {
   if (IsGeneratedCardBubble()) {
 #if !defined(OS_ANDROID)
+    // Open a new tab to the Online Wallet help link.
     chrome::NavigateParams params(
         chrome::FindBrowserWithWebContents(web_contents()),
         GURL(kWalletGeneratedCardLearnMoreLink),
@@ -221,13 +224,14 @@
 void AutofillCreditCardBubbleController::Reset() {
   Hide();
 
+  // Clear any generated state or stored |ShowAs*()| arguments.
   fronting_card_name_.clear();
   backing_card_name_.clear();
   new_card_name_.clear();
   bubble_text_.clear();
   bubble_text_ranges_.clear();
 
-  DCHECK(!IsSetup());
+  DCHECK(!IsSetUp());
 }
 
 void AutofillCreditCardBubbleController::SetUp() {
@@ -244,30 +248,43 @@
         NULL);
   }
 
-  base::char16 separator('|');
+  // Split the full text on '|' to highlight certain parts. For example, "sly"
+  // and "jumped" would be bolded in "The |sly| fox |jumped| over the lazy dog".
   std::vector<base::string16> pieces;
-  base::SplitStringDontTrim(full_text, separator, &pieces);
+  base::SplitStringDontTrim(full_text, kRangeSeparator, &pieces);
 
   while (!pieces.empty()) {
     base::string16 piece = pieces.front();
+
+    // Every second piece should be bolded. Because |base::SplitString*()|
+    // leaves an empty "" even if '|' is the first character, this is guaranteed
+    // to work for "|highlighting| starts here". Ignore empty pieces because
+    // there's nothing to highlight.
     if (!piece.empty() && pieces.size() % 2 == 0) {
       const size_t start = bubble_text_.size();
       bubble_text_ranges_.push_back(ui::Range(start, start + piece.size()));
     }
+
+    // Append the piece whether it's bolded or not and move on to the next one.
     bubble_text_.append(piece);
     pieces.erase(pieces.begin(), pieces.begin() + 1);
   }
 
   UpdateAnchor();
-  DCHECK(IsSetup());
+  DCHECK(IsSetUp());
 }
 
-bool AutofillCreditCardBubbleController::IsSetup() const {
+bool AutofillCreditCardBubbleController::IsSetUp() const {
+  // Because |bubble_text_| should never be empty after |SetUp()|, and all
+  // translations should have some text highlighting (i.e. "some |pipes|"),
+  // if there is text there should be text ranges as well. Sanity check this.
   DCHECK_EQ(bubble_text_.empty(), bubble_text_ranges_.empty());
   return !bubble_text_.empty();
 }
 
 bool AutofillCreditCardBubbleController::IsGeneratedCardBubble() const {
+  // Do a quick sanity check to ensure that the bubble isn't partially set up as
+  // the other type (i.e. a fronting card and a new card doesn't make sense).
   DCHECK_EQ(fronting_card_name_.empty(), backing_card_name_.empty());
   DCHECK_NE(backing_card_name_.empty(), new_card_name_.empty());
   return !fronting_card_name_.empty();
diff --git a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.h b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.h
index e6d8885..dfe5b55 100644
--- a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.h
+++ b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller.h
@@ -74,11 +74,10 @@
       const content::LoadCommittedDetails& details,
       const content::FrameNavigateParams& params) OVERRIDE;
 
-  // Whether |bubble_| is currently in the process of hiding.
+  // Returns whether |bubble_| is currently in the process of hiding.
   bool IsHiding() const;
 
-  // An image that should be shown as an icon in the omnibox and pointed to by
-  // the bubble.
+  // The image that should be shown as an icon in the omnibox.
   gfx::Image AnchorIcon() const;
 
   // The title of the bubble. May be empty.
@@ -93,10 +92,11 @@
   // The text of the link shown at the bubble of the bubble.
   base::string16 LinkText() const;
 
-  // Called when the anchor for this bubble is clicked.
+  // Called when the anchor for this bubble is clicked. Shows a new bubble.
   void OnAnchorClicked();
 
-  // Called when the link at the bottom of the bubble is clicked.
+  // Called when the link at the bottom of the bubble is clicked. Opens and
+  // navigates a new tab to an informational page and hides the bubble.
   void OnLinkClicked();
 
   // The web contents that successfully submitted the Autofill dialog (causing
@@ -105,8 +105,8 @@
   const content::WebContents* web_contents() const { return web_contents_; }
 
  protected:
-  // Create a bubble connected to |web_contents|. Its content will be based on
-  // which |SetupAs*()| method is called.
+  // Creates a bubble connected to |web_contents|. Its content will be based on
+  // which |ShowAs*()| method is called.
   explicit AutofillCreditCardBubbleController(content::WebContents* contents);
 
   // Returns a base::WeakPtr that references |this|. Exposed for testing.
@@ -118,7 +118,7 @@
   // Returns a weak reference to |bubble_|. May be invalid/NULL.
   virtual base::WeakPtr<AutofillCreditCardBubble> bubble();
 
-  // Whether the bubble can show currently.
+  // Returns whether the bubble can currently show itself.
   virtual bool CanShow() const;
 
   // Whether the generated card bubble should be shown initially when showing
@@ -132,7 +132,7 @@
       const base::string16& backing_card_name,
       const base::string16& fronting_card_name);
 
-  // Show a bubble notifying the user that new credit card data has been saved.
+  // Shows a bubble notifying the user that new credit card data has been saved.
   // Exposed for testing.
   virtual void ShowAsNewCardSavedBubble(const base::string16& new_card_name);
 
@@ -142,21 +142,21 @@
   // Nukes the state of this controller and hides |bubble_| (if it exists).
   void Reset();
 
-  // Generate bubble text and ranges now that this class knows which type of
-  // bubble it should be shown as. Called from |ShowAs*()| methods.
+  // Generates the correct bubble text and text highlighting ranges for the
+  // types of bubble being shown. Must be called before showing the bubble.
   void SetUp();
 
-  // Whether the controller has been setup as a certain type of bubble.
-  bool IsSetup() const;
+  // Returns whether the controller has been setup as a certain type of bubble.
+  bool IsSetUp() const;
 
-  // Whether the bubble is an educational bubble about generated cards.
+  // Returns whether the bubble is an educational bubble about generated cards.
   bool IsGeneratedCardBubble() const;
 
-  // An internal helper to show the bubble in response to successful Autofill
-  // dialog submission or anchor click.
+  // Hides any existing bubbles and creates and shows a new one. Called in
+  // response to successful Autofill dialog submission or anchor click.
   void Show(bool was_anchor_click);
 
-  // Update the omnibox icon that |bubble_| will be anchored to.
+  // Updates the omnibox icon that |bubble_| will be anchored to.
   void UpdateAnchor();
 
   // Hides |bubble_| (if it exists and isn't already hiding).
diff --git a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller_unittest.cc
index 942afa5..63efafe 100644
--- a/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_credit_card_bubble_controller_unittest.cc
@@ -31,10 +31,10 @@
   return ASCIIToUTF16("Visa - 1111");
 }
 base::string16 FrontingCard() {
-  return ASCIIToUTF16("Mastercard - 5888");
+  return ASCIIToUTF16("Mastercard - 4444");
 }
 base::string16 NewCard() {
-  return ASCIIToUTF16("Discover - 7582");
+  return ASCIIToUTF16("Discover - 7777");
 }
 
 base::string16 RangeOfString(const base::string16& string,
@@ -49,8 +49,8 @@
       content::WebContents* contents)
       : AutofillCreditCardBubbleController(contents) {
     contents->SetUserData(UserDataKey(), this);
-    EXPECT_TRUE(IsInstalled());
   }
+
   virtual ~TestAutofillCreditCardBubbleController() {}
 
   bool IsInstalled() const {
@@ -86,6 +86,7 @@
     // Attaches immediately to |test_web_contents_| so a test version will exist
     // before a non-test version can be created.
     new TestAutofillCreditCardBubbleController(test_web_contents_.get());
+    ASSERT_TRUE(controller()->IsInstalled());
   }
 
  protected:
@@ -113,7 +114,7 @@
   }
 
   void ShowNewCardSavedBubble() {
-    EXPECT_TRUE(controller()->IsInstalled());
+    ASSERT_TRUE(controller()->IsInstalled());
     TestAutofillCreditCardBubbleController::ShowNewCardSavedBubble(
         test_web_contents_.get(), NewCard());
   }
@@ -146,6 +147,7 @@
 TEST_F(AutofillCreditCardBubbleControllerTest, GeneratedCardBubbleTimesShown) {
   ASSERT_EQ(0, GeneratedCardBubbleTimesShown());
 
+  // Ensure that showing the generated card UI bumps the persistent count.
   ShowGeneratedCardUI();
   EXPECT_EQ(1, GeneratedCardBubbleTimesShown());
   EXPECT_TRUE(controller()->GetTestingBubble()->showing());
@@ -157,19 +159,24 @@
 }
 
 TEST_F(AutofillCreditCardBubbleControllerTest, BubbleText) {
+  // Ensure that while showing the generated card UI that the bubble's text
+  // contains "Visa - 1111" and "Mastercard - 4444".
   ShowGeneratedCardUI();
   base::string16 generated_text = controller()->BubbleText();
-  EXPECT_NE(generated_text.find(BackingCard()), base::string16::npos);
-  EXPECT_NE(generated_text.find(FrontingCard()), base::string16::npos);
-  EXPECT_EQ(generated_text.find(NewCard()), base::string16::npos);
+  EXPECT_NE(base::string16::npos, generated_text.find(BackingCard()));
+  EXPECT_NE(base::string16::npos, generated_text.find(FrontingCard()));
+  EXPECT_EQ(base::string16::npos, generated_text.find(NewCard()));
 
+  // Ensure that while showing the new card bubble that "Discover - 7777" is in
+  // the bubble text.
   ShowNewCardSavedBubble();
   base::string16 new_text = controller()->BubbleText();
   EXPECT_NE(new_text, generated_text);
-  EXPECT_EQ(new_text.find(BackingCard()), base::string16::npos);
-  EXPECT_EQ(new_text.find(FrontingCard()), base::string16::npos);
-  EXPECT_NE(new_text.find(NewCard()), base::string16::npos);
+  EXPECT_EQ(base::string16::npos, new_text.find(BackingCard()));
+  EXPECT_EQ(base::string16::npos, new_text.find(FrontingCard()));
+  EXPECT_NE(base::string16::npos, new_text.find(NewCard()));
 
+  // Make sure that |bubble_text_| is regenerated the same way in |Setup()|.
   ShowGeneratedCardUI();
   EXPECT_EQ(generated_text, controller()->BubbleText());
 
@@ -178,11 +185,12 @@
 }
 
 TEST_F(AutofillCreditCardBubbleControllerTest, BubbleTextRanges) {
+  // Check that the highlighted ranges in the bubble's text are correct.
   ShowGeneratedCardUI();
   base::string16 text = controller()->BubbleText();
   std::vector<ui::Range> ranges = controller()->BubbleTextRanges();
 
-  ASSERT_EQ(ranges.size(), 2U);
+  ASSERT_EQ(2U, ranges.size());
   EXPECT_EQ(BackingCard(), RangeOfString(text, ranges[0]));
   EXPECT_EQ(FrontingCard(), RangeOfString(text, ranges[1]));
 
@@ -190,11 +198,13 @@
   text = controller()->BubbleText();
   ranges = controller()->BubbleTextRanges();
 
-  ASSERT_EQ(ranges.size(), 1U);
+  ASSERT_EQ(1U, ranges.size());
   EXPECT_EQ(NewCard(), RangeOfString(text, ranges[0]));
 }
 
 TEST_F(AutofillCreditCardBubbleControllerTest, HideOnNavigate) {
+  // When a user navigates away from a page (or refreshes) normally, the bubbles
+  // should be hidden.
   EXPECT_FALSE(controller()->GetTestingBubble());
   ShowGeneratedCardUI();
   EXPECT_TRUE(controller()->GetTestingBubble()->showing());
@@ -213,6 +223,7 @@
 }
 
 TEST_F(AutofillCreditCardBubbleControllerTest, StayOnRedirect) {
+  // If a page redirects right after submitting, the bubble should remain.
   EXPECT_FALSE(controller()->GetTestingBubble());
   ShowGeneratedCardUI();
   EXPECT_TRUE(controller()->GetTestingBubble()->showing());
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
index 2e0ea7f..3a42603 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.cc
@@ -115,19 +115,23 @@
                                const AutofillType& field_type) {
   // If any credit card expiration info is asked for, show both month and year
   // inputs.
-  if (field_type.server_type() == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
-      field_type.server_type() == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
-      field_type.server_type() == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR ||
-      field_type.server_type() == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
-      field_type.server_type() == CREDIT_CARD_EXP_MONTH) {
+  ServerFieldType server_type = field_type.GetStorableType();
+  if (server_type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
+      server_type == CREDIT_CARD_EXP_2_DIGIT_YEAR ||
+      server_type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR ||
+      server_type == CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR ||
+      server_type == CREDIT_CARD_EXP_MONTH) {
     return input.type == CREDIT_CARD_EXP_4_DIGIT_YEAR ||
            input.type == CREDIT_CARD_EXP_MONTH;
   }
 
-  if (field_type.server_type() == CREDIT_CARD_TYPE)
+  if (server_type == CREDIT_CARD_TYPE)
     return input.type == CREDIT_CARD_NUMBER;
 
-  return input.type == field_type.server_type();
+  // Check the groups to distinguish billing types from shipping ones.
+  AutofillType input_type = AutofillType(input.type);
+  return input_type.GetStorableType() == server_type &&
+         input_type.group() == field_type.group();
 }
 
 // Returns true if |input| in the given |section| should be used for a
@@ -138,7 +142,7 @@
   AutofillType field_type = field.Type();
 
   // The credit card name is filled from the billing section's data.
-  if (field_type.server_type() == CREDIT_CARD_NAME &&
+  if (field_type.GetStorableType() == CREDIT_CARD_NAME &&
       (section == SECTION_BILLING || section == SECTION_CC_BILLING)) {
     return input.type == NAME_BILLING_FULL;
   }
@@ -158,7 +162,8 @@
   // Equivalent billing field type is used to support UseBillingAsShipping
   // usecase.
   ServerFieldType field_type =
-      AutofillType::GetEquivalentBillingFieldType(field.Type().server_type());
+      AutofillType::GetEquivalentBillingFieldType(
+          field.Type().GetStorableType());
 
   return InputTypeMatchesFieldType(input, AutofillType(field_type));
 }
@@ -458,7 +463,7 @@
   GetMetricLogger().LogDialogInitialUserState(
       GetDialogType(), initial_user_state_);
 
-  if (deemphasized_render_view_) {
+  if (deemphasized_render_view_ && web_contents()) {
     web_contents()->GetRenderViewHost()->Send(
         new ChromeViewMsg_SetVisuallyDeemphasized(
             web_contents()->GetRenderViewHost()->GetRoutingID(), false));
@@ -509,8 +514,9 @@
 void AutofillDialogControllerImpl::Show() {
   dialog_shown_timestamp_ = base::Time::Now();
 
-  content::NavigationEntry* entry = contents_->GetController().GetActiveEntry();
-  const GURL& active_url = entry ? entry->GetURL() : contents_->GetURL();
+  content::NavigationEntry* entry =
+      web_contents()->GetController().GetActiveEntry();
+  const GURL& active_url = entry ? entry->GetURL() : web_contents()->GetURL();
   invoked_from_same_origin_ = active_url.GetOrigin() == source_url_.GetOrigin();
 
   // Log any relevant UI metrics and security exceptions.
@@ -536,7 +542,7 @@
   bool has_types = false;
   bool has_sections = false;
   form_structure_.ParseFieldTypesFromAutocompleteAttributes(
-      FormStructure::PARSE_FOR_AUTOFILL_DIALOG, &has_types, &has_sections);
+      &has_types, &has_sections);
 
   // Fail if the author didn't specify autocomplete types.
   if (!has_types) {
@@ -748,6 +754,10 @@
   return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_CHECKBOX);
 }
 
+string16 AutofillDialogControllerImpl::SaveLocallyTooltip() const {
+  return l10n_util::GetStringUTF16(IDS_AUTOFILL_DIALOG_SAVE_LOCALLY_TOOLTIP);
+}
+
 string16 AutofillDialogControllerImpl::LegalDocumentsText() {
   if (!IsPayingWithWallet() || autocheckout_state_ != AUTOCHECKOUT_NOT_STARTED)
     return string16();
@@ -1200,7 +1210,7 @@
 
 ui::ComboboxModel* AutofillDialogControllerImpl::ComboboxModelForAutofillType(
     ServerFieldType type) {
-  switch (AutofillType::GetEquivalentFieldType(type)) {
+  switch (type) {
     case CREDIT_CARD_EXP_MONTH:
       return &cc_exp_month_combobox_model_;
 
@@ -1208,6 +1218,7 @@
       return &cc_exp_year_combobox_model_;
 
     case ADDRESS_HOME_COUNTRY:
+    case ADDRESS_BILLING_COUNTRY:
       return &country_combobox_model_;
 
     default:
@@ -1573,7 +1584,7 @@
     }
   }
 
-  switch (AutofillType::GetEquivalentFieldType(type)) {
+  switch (AutofillType(type).GetStorableType()) {
     case EMAIL_ADDRESS:
       if (!value.empty() && !IsValidEmailAddress(value)) {
         return l10n_util::GetStringUTF16(
@@ -2027,8 +2038,8 @@
   return profile_;
 }
 
-content::WebContents* AutofillDialogControllerImpl::web_contents() {
-  return contents_;
+content::WebContents* AutofillDialogControllerImpl::GetWebContents() {
+  return web_contents();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -2326,7 +2337,8 @@
   DCHECK_GT(form_structure_.field_count(), 0U);
 
   for (size_t i = 0; i < form_structure_.field_count(); ++i) {
-    if (IsCreditCardType(form_structure_.field(i)->Type().server_type()))
+    AutofillType type = form_structure_.field(i)->Type();
+    if (IsCreditCardType(type.GetStorableType()))
       return true;
   }
 
@@ -2344,8 +2356,8 @@
     const DialogType dialog_type,
     const base::Callback<void(const FormStructure*,
                               const std::string&)>& callback)
-    : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
-      contents_(contents),
+    : WebContentsObserver(contents),
+      profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
       initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),
       dialog_type_(dialog_type),
       form_structure_(form_structure, std::string()),
@@ -2786,7 +2798,7 @@
 void AutofillDialogControllerImpl::SetCvcResult(const string16& cvc) {
   for (size_t i = 0; i < form_structure_.field_count(); ++i) {
     AutofillField* field = form_structure_.field(i);
-    if (field->Type().server_type() == CREDIT_CARD_VERIFICATION_CODE) {
+    if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
       field->value = cvc;
       break;
     }
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
index fcc664d..6aa4ae1 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_impl.h
@@ -33,6 +33,7 @@
 #include "components/autofill/core/browser/personal_data_manager_observer.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/ssl_status.h"
 #include "ui/base/models/simple_menu_model.h"
 #include "ui/base/ui_base_types.h"
@@ -69,6 +70,7 @@
 class AutofillDialogControllerImpl : public AutofillDialogViewDelegate,
                                      public AutofillPopupDelegate,
                                      public content::NotificationObserver,
+                                     public content::WebContentsObserver,
                                      public SuggestionsMenuModelDelegate,
                                      public wallet::WalletClientDelegate,
                                      public wallet::WalletSigninHelperDelegate,
@@ -119,6 +121,7 @@
   virtual string16 CancelButtonText() const OVERRIDE;
   virtual string16 ConfirmButtonText() const OVERRIDE;
   virtual string16 SaveLocallyText() const OVERRIDE;
+  virtual string16 SaveLocallyTooltip() const OVERRIDE;
   virtual string16 LegalDocumentsText() OVERRIDE;
   virtual DialogSignedInState SignedInState() const OVERRIDE;
   virtual bool ShouldShowSpinner() const OVERRIDE;
@@ -174,7 +177,7 @@
   virtual bool OnCancel() OVERRIDE;
   virtual bool OnAccept() OVERRIDE;
   virtual Profile* profile() OVERRIDE;
-  virtual content::WebContents* web_contents() OVERRIDE;
+  virtual content::WebContents* GetWebContents() OVERRIDE;
 
   // AutofillPopupDelegate implementation.
   virtual void OnPopupShown(content::KeyboardListener* listener) OVERRIDE;
@@ -549,9 +552,6 @@
   // The |profile| for |contents_|.
   Profile* const profile_;
 
-  // The WebContents where the Autofill action originated.
-  content::WebContents* const contents_;
-
   // For logging UMA metrics.
   const AutofillMetrics metric_logger_;
   base::Time dialog_shown_timestamp_;
diff --git a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
index a510a96..7d16140 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
+++ b/chrome/browser/ui/autofill/autofill_dialog_controller_unittest.cc
@@ -1011,22 +1011,26 @@
 
   controller()->OnAccept();
   ASSERT_EQ(20U, form_structure()->field_count());
-  EXPECT_EQ(ADDRESS_BILLING_STATE,
-            form_structure()->field(9)->Type().server_type());
   EXPECT_EQ(ADDRESS_HOME_STATE,
-            form_structure()->field(16)->Type().server_type());
+            form_structure()->field(9)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(9)->Type().group());
+  EXPECT_EQ(ADDRESS_HOME_STATE,
+            form_structure()->field(16)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_HOME, form_structure()->field(16)->Type().group());
   string16 billing_state = form_structure()->field(9)->value;
   string16 shipping_state = form_structure()->field(16)->value;
   EXPECT_FALSE(billing_state.empty());
   EXPECT_FALSE(shipping_state.empty());
   EXPECT_NE(billing_state, shipping_state);
 
-  EXPECT_EQ(CREDIT_CARD_NAME, form_structure()->field(1)->Type().server_type());
+  EXPECT_EQ(CREDIT_CARD_NAME,
+            form_structure()->field(1)->Type().GetStorableType());
   string16 cc_name = form_structure()->field(1)->value;
-  EXPECT_EQ(NAME_BILLING_FULL,
-            form_structure()->field(6)->Type().server_type());
+  EXPECT_EQ(NAME_FULL, form_structure()->field(6)->Type().GetStorableType());
+  EXPECT_EQ(NAME_BILLING, form_structure()->field(6)->Type().group());
   string16 billing_name = form_structure()->field(6)->value;
-  EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().server_type());
+  EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().GetStorableType());
+  EXPECT_EQ(NAME, form_structure()->field(13)->Type().group());
   string16 shipping_name = form_structure()->field(13)->value;
 
   EXPECT_FALSE(cc_name.empty());
@@ -1051,10 +1055,12 @@
 
   controller()->OnAccept();
   ASSERT_EQ(20U, form_structure()->field_count());
-  EXPECT_EQ(ADDRESS_BILLING_STATE,
-            form_structure()->field(9)->Type().server_type());
   EXPECT_EQ(ADDRESS_HOME_STATE,
-            form_structure()->field(16)->Type().server_type());
+            form_structure()->field(9)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(9)->Type().group());
+  EXPECT_EQ(ADDRESS_HOME_STATE,
+            form_structure()->field(16)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_HOME, form_structure()->field(16)->Type().group());
   string16 billing_state = form_structure()->field(9)->value;
   string16 shipping_state = form_structure()->field(16)->value;
   EXPECT_FALSE(billing_state.empty());
@@ -1062,12 +1068,13 @@
   EXPECT_EQ(billing_state, shipping_state);
 
   EXPECT_EQ(CREDIT_CARD_NAME,
-            form_structure()->field(1)->Type().server_type());
+            form_structure()->field(1)->Type().GetStorableType());
   string16 cc_name = form_structure()->field(1)->value;
-  EXPECT_EQ(NAME_BILLING_FULL,
-            form_structure()->field(6)->Type().server_type());
+  EXPECT_EQ(NAME_FULL, form_structure()->field(6)->Type().GetStorableType());
+  EXPECT_EQ(NAME_BILLING, form_structure()->field(6)->Type().group());
   string16 billing_name = form_structure()->field(6)->value;
-  EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().server_type());
+  EXPECT_EQ(NAME_FULL, form_structure()->field(13)->Type().GetStorableType());
+  EXPECT_EQ(NAME, form_structure()->field(13)->Type().group());
   string16 shipping_name = form_structure()->field(13)->value;
 
   EXPECT_FALSE(cc_name.empty());
@@ -1105,9 +1112,11 @@
   controller()->OnAccept();
   ASSERT_EQ(2U, form_structure()->field_count());
   EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
-            form_structure()->field(0)->Type().server_type());
-  EXPECT_EQ(PHONE_BILLING_WHOLE_NUMBER,
-            form_structure()->field(1)->Type().server_type());
+            form_structure()->field(0)->Type().GetStorableType());
+  EXPECT_EQ(PHONE_HOME, form_structure()->field(0)->Type().group());
+  EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER,
+            form_structure()->field(1)->Type().GetStorableType());
+  EXPECT_EQ(PHONE_BILLING, form_structure()->field(1)->Type().group());
   EXPECT_EQ(shipping_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER),
             form_structure()->field(0)->value);
   EXPECT_EQ(billing_profile.GetRawInfo(PHONE_BILLING_WHOLE_NUMBER),
@@ -2041,7 +2050,7 @@
 
   size_t i = 0;
   for (; i < form_structure()->field_count(); ++i) {
-    if (form_structure()->field(i)->Type().server_type() == EMAIL_ADDRESS) {
+    if (form_structure()->field(i)->Type().GetStorableType() == EMAIL_ADDRESS) {
       EXPECT_EQ(ASCIIToUTF16(kFakeEmail), form_structure()->field(i)->value);
       break;
     }
@@ -2056,13 +2065,16 @@
   controller()->OnAccept();
   controller()->OnDidGetFullWallet(wallet::GetTestFullWallet());
   ASSERT_EQ(20U, form_structure()->field_count());
-  EXPECT_EQ(EMAIL_ADDRESS, form_structure()->field(0)->Type().server_type());
+  EXPECT_EQ(EMAIL_ADDRESS,
+            form_structure()->field(0)->Type().GetStorableType());
   EXPECT_EQ(CREDIT_CARD_NUMBER,
-            form_structure()->field(2)->Type().server_type());
-  EXPECT_EQ(ADDRESS_BILLING_STATE,
-            form_structure()->field(9)->Type().server_type());
+            form_structure()->field(2)->Type().GetStorableType());
   EXPECT_EQ(ADDRESS_HOME_STATE,
-            form_structure()->field(16)->Type().server_type());
+            form_structure()->field(9)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_BILLING, form_structure()->field(9)->Type().group());
+  EXPECT_EQ(ADDRESS_HOME_STATE,
+            form_structure()->field(16)->Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_HOME, form_structure()->field(16)->Type().group());
 }
 
 TEST_F(AutofillDialogControllerTest, SaveDetailsInChrome) {
diff --git a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
index d67f9d7..5ecae0f 100644
--- a/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/autofill_dialog_view_delegate.h
@@ -46,6 +46,7 @@
   virtual string16 CancelButtonText() const = 0;
   virtual string16 ConfirmButtonText() const = 0;
   virtual string16 SaveLocallyText() const = 0;
+  virtual string16 SaveLocallyTooltip() const = 0;
   virtual string16 LegalDocumentsText() = 0;
 
   // State ---------------------------------------------------------------------
@@ -205,7 +206,7 @@
   virtual Profile* profile() = 0;
 
   // The web contents that prompted the dialog.
-  virtual content::WebContents* web_contents() = 0;
+  virtual content::WebContents* GetWebContents() = 0;
 
  protected:
   virtual ~AutofillDialogViewDelegate();
diff --git a/chrome/browser/ui/autofill/data_model_wrapper.cc b/chrome/browser/ui/autofill/data_model_wrapper.cc
index ac1af54..1992c90 100644
--- a/chrome/browser/ui/autofill/data_model_wrapper.cc
+++ b/chrome/browser/ui/autofill/data_model_wrapper.cc
@@ -123,18 +123,21 @@
 }
 
 void AutofillProfileWrapper::FillFormField(AutofillField* field) const {
-  AutofillType field_type = field->Type();
+  if (field->Type().GetStorableType() == CREDIT_CARD_NAME) {
+    // Cache the field's true type.
+    HtmlFieldType original_type = field->html_type();
 
-  if (field_type.server_type() == CREDIT_CARD_NAME) {
     // Requests for the user's credit card are filled from the billing address,
     // but the AutofillProfile class doesn't know how to fill credit card
     // fields. So, temporarily set the type to the corresponding profile type.
-    field->set_heuristic_type(NAME_FULL);
+    field->SetHtmlType(HTML_TYPE_NAME, field->html_mode());
+    AutofillDataModelWrapper::FillFormField(field);
+
+    // Restore the field's true type.
+    field->SetHtmlType(original_type, field->html_mode());
+  } else {
+    AutofillDataModelWrapper::FillFormField(field);
   }
-
-  AutofillDataModelWrapper::FillFormField(field);
-
-  field->set_heuristic_type(field_type.server_type());
 }
 
 // AutofillCreditCardWrapper
@@ -146,7 +149,7 @@
 AutofillCreditCardWrapper::~AutofillCreditCardWrapper() {}
 
 string16 AutofillCreditCardWrapper::GetInfo(const AutofillType& type) const {
-  if (type.server_type() == CREDIT_CARD_EXP_MONTH)
+  if (type.GetStorableType() == CREDIT_CARD_EXP_MONTH)
     return MonthComboboxModel::FormatMonth(card_->expiration_month());
 
   return AutofillDataModelWrapper::GetInfo(type);
@@ -193,7 +196,7 @@
 WalletInstrumentWrapper::~WalletInstrumentWrapper() {}
 
 string16 WalletInstrumentWrapper::GetInfo(const AutofillType& type) const {
-  if (type.server_type() == CREDIT_CARD_EXP_MONTH)
+  if (type.GetStorableType() == CREDIT_CARD_EXP_MONTH)
     return MonthComboboxModel::FormatMonth(instrument_->expiration_month());
 
   return instrument_->GetInfo(type, g_browser_process->GetApplicationLocale());
@@ -228,7 +231,7 @@
 FullWalletBillingWrapper::~FullWalletBillingWrapper() {}
 
 string16 FullWalletBillingWrapper::GetInfo(const AutofillType& type) const {
-  if (type.server_type() == CREDIT_CARD_EXP_MONTH)
+  if (type.GetStorableType() == CREDIT_CARD_EXP_MONTH)
     return MonthComboboxModel::FormatMonth(full_wallet_->expiration_month());
 
   if (type.group() == CREDIT_CARD)
@@ -267,9 +270,10 @@
 DetailOutputWrapper::~DetailOutputWrapper() {}
 
 base::string16 DetailOutputWrapper::GetInfo(const AutofillType& type) const {
+  ServerFieldType storable_type = type.GetStorableType();
   for (DetailOutputMap::const_iterator it = outputs_.begin();
        it != outputs_.end(); ++it) {
-    if (type.server_type() == it->first->type)
+    if (storable_type == AutofillType(it->first->type).GetStorableType())
       return it->second;
   }
   return base::string16();
diff --git a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
index a02c32c..414b4c7 100644
--- a/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
+++ b/chrome/browser/ui/autofill/mock_autofill_dialog_view_delegate.h
@@ -22,6 +22,7 @@
   MOCK_CONST_METHOD0(CancelButtonText, string16());
   MOCK_CONST_METHOD0(ConfirmButtonText, string16());
   MOCK_CONST_METHOD0(SaveLocallyText, string16());
+  MOCK_CONST_METHOD0(SaveLocallyTooltip, string16());
   MOCK_METHOD0(LegalDocumentsText, string16());
   MOCK_CONST_METHOD0(SignedInState, DialogSignedInState());
   MOCK_CONST_METHOD0(ShouldShowSpinner, bool());
@@ -74,7 +75,7 @@
   MOCK_METHOD0(OnCancel, bool());
   MOCK_METHOD0(OnAccept, bool());
   MOCK_METHOD0(profile, Profile*());
-  MOCK_METHOD0(web_contents, content::WebContents*());
+  MOCK_METHOD0(GetWebContents, content::WebContents*());
  private:
   DetailInputs default_inputs_;
   DetailInputs cc_default_inputs_;  // Default inputs for SECTION_CC.
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
index 53c6a90..cf4ab39 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.cc
@@ -22,9 +22,11 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/common/url_constants.h"
 #include "components/autofill/content/browser/autofill_driver_impl.h"
+#include "components/autofill/core/common/autofill_messages.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "content/public/browser/navigation_details.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents_view.h"
 #include "ui/gfx/rect.h"
 
@@ -105,13 +107,14 @@
       infobar_service, &metric_logger, save_card_callback);
 }
 
-void TabAutofillManagerDelegate::ShowAutocheckoutBubble(
+bool TabAutofillManagerDelegate::ShowAutocheckoutBubble(
     const gfx::RectF& bounding_box,
     bool is_google_user,
     const base::Callback<void(AutocheckoutBubbleState)>& callback) {
 #if !defined(TOOLKIT_VIEWS)
   callback.Run(AUTOCHECKOUT_BUBBLE_CANCELED);
   NOTIMPLEMENTED();
+  return false;
 #else
   HideAutocheckoutBubble();
 
@@ -127,7 +130,12 @@
               web_contents_->GetView()->GetTopLevelNativeWindow(),
               is_google_user,
               callback)));
+
+  if (!autocheckout_bubble_)
+    return false;
+
   autocheckout_bubble_->ShowBubble();
+  return true;
 #endif  // #if !defined(TOOLKIT_VIEWS)
 }
 
@@ -215,6 +223,13 @@
     dialog_controller_->Hide();
 }
 
+void TabAutofillManagerDelegate::WasShown() {
+  content::RenderViewHost* host = web_contents()->GetRenderViewHost();
+  if (!host)
+    return;
+  host->Send(new AutofillMsg_PageShown(host->GetRoutingID()));
+}
+
 void TabAutofillManagerDelegate::DidNavigateMainFrame(
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
diff --git a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
index 004a0bb..40588b5 100644
--- a/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
+++ b/chrome/browser/ui/autofill/tab_autofill_manager_delegate.h
@@ -53,7 +53,7 @@
       const AutofillMetrics& metric_logger,
       const CreditCard& credit_card,
       const base::Closure& save_card_callback) OVERRIDE;
-  virtual void ShowAutocheckoutBubble(
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounds,
       bool is_google_user,
       const base::Callback<void(AutocheckoutBubbleState)>& callback) OVERRIDE;
@@ -89,6 +89,7 @@
       const content::FrameNavigateParams& params) OVERRIDE;
   virtual void WebContentsDestroyed(
       content::WebContents* web_contents) OVERRIDE;
+  virtual void WasShown() OVERRIDE;
 
   // Exposed for testing.
   AutofillDialogControllerImpl* GetDialogControllerForTesting() {
diff --git a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
index 33584f7..292af78 100644
--- a/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/autofill/autofill_dialog_cocoa.mm
@@ -54,13 +54,13 @@
   // This should only be called once.
   DCHECK(!sheet_delegate_.get());
   sheet_delegate_.reset([[AutofillDialogWindowController alloc]
-       initWithWebContents:delegate_->web_contents()
+       initWithWebContents:delegate_->GetWebContents()
             autofillDialog:this]);
   base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
       [[CustomConstrainedWindowSheet alloc]
           initWithCustomWindow:[sheet_delegate_ window]]);
   constrained_window_.reset(
-      new ConstrainedWindowMac(this, delegate_->web_contents(), sheet));
+      new ConstrainedWindowMac(this, delegate_->GetWebContents(), sheet));
 }
 
 void AutofillDialogCocoa::Hide() {
diff --git a/chrome/browser/ui/cocoa/background_gradient_view.mm b/chrome/browser/ui/cocoa/background_gradient_view.mm
index 26a904f..1ed5113 100644
--- a/chrome/browser/ui/cocoa/background_gradient_view.mm
+++ b/chrome/browser/ui/cocoa/background_gradient_view.mm
@@ -93,7 +93,7 @@
     return [NSColor blackColor];
   return themeProvider->GetNSColor(
       isActive ? ThemeProperties::COLOR_TOOLBAR_STROKE :
-                 ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE, true);
+                 ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE);
 }
 
 - (NSColor*)backgroundImageColor {
@@ -106,12 +106,12 @@
   // theme.
   if (![[self window] isMainWindow] && themeProvider->UsingDefaultTheme()) {
     NSColor* color = themeProvider->GetNSImageColorNamed(
-        IDR_THEME_TOOLBAR_INACTIVE, true);
+        IDR_THEME_TOOLBAR_INACTIVE);
     if (color)
       return color;
   }
 
-  return themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR, true);
+  return themeProvider->GetNSImageColorNamed(IDR_THEME_TOOLBAR);
 }
 
 - (void)windowFocusDidChange:(NSNotification*)notification {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
index 3851b48..f86c61b 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller.mm
@@ -1091,8 +1091,7 @@
   ui::ThemeProvider* themeProvider = [[[self view] window] themeProvider];
   if (themeProvider) {
     NSColor* color =
-        themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT,
-                                  true);
+        themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
     [cell setTextColor:color];
   }
 
@@ -1703,8 +1702,7 @@
   if (!themeProvider)
     return;
   NSColor* color =
-      themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT,
-                                true);
+      themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
   for (BookmarkButton* button in buttons_.get()) {
     BookmarkButtonCell* cell = [button cell];
     [cell setTextColor:color];
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
index 9ae2499..8a9b7f8 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm
@@ -220,18 +220,16 @@
       ui::ScaleFactor scale_factor) const OVERRIDE {
     return NULL;
   }
-  virtual NSImage* GetNSImageNamed(int id, bool allow_default) const OVERRIDE {
+  virtual NSImage* GetNSImageNamed(int id) const OVERRIDE {
     return nil;
   }
-  virtual NSColor* GetNSImageColorNamed(
-      int id,
-      bool allow_default) const OVERRIDE {
+  virtual NSColor* GetNSImageColorNamed(int id) const OVERRIDE {
     return nil;
   }
-  virtual NSColor* GetNSColor(int id, bool allow_default) const OVERRIDE {
+  virtual NSColor* GetNSColor(int id) const OVERRIDE {
     return color_.get();
   }
-  virtual NSColor* GetNSColorTint(int id, bool allow_default) const OVERRIDE {
+  virtual NSColor* GetNSColorTint(int id) const OVERRIDE {
     return nil;
   }
   virtual NSGradient* GetNSGradient(int id) const OVERRIDE {
diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
index b468c6f..617f44a 100644
--- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
+++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_view.mm
@@ -88,8 +88,7 @@
     return;
 
   NSColor* color =
-      themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT,
-                                true);
+      themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
   [noItemTextfield_ setTextColor:color];
 }
 
diff --git a/chrome/browser/ui/cocoa/bubble_view.mm b/chrome/browser/ui/cocoa/bubble_view.mm
index b9b8648..fd5d14b 100644
--- a/chrome/browser/ui/cocoa/bubble_view.mm
+++ b/chrome/browser/ui/cocoa/bubble_view.mm
@@ -92,7 +92,7 @@
                         bottomRightCornerRadius:bottomRightRadius];
 
   if (themeProvider)
-    [themeProvider->GetNSColor(ThemeProperties::COLOR_TOOLBAR, true) set];
+    [themeProvider->GetNSColor(ThemeProperties::COLOR_TOOLBAR) set];
   [border fill];
 
   [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set];
@@ -101,8 +101,7 @@
   // Text
   NSColor* textColor = [NSColor blackColor];
   if (themeProvider)
-    textColor = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT,
-                                          true);
+    textColor = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
   NSFont* textFont = [self font];
   base::scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
   [textShadow setShadowBlurRadius:0.0f];
diff --git a/chrome/browser/ui/cocoa/download/background_theme.h b/chrome/browser/ui/cocoa/download/background_theme.h
index d044fe1..201b52e 100644
--- a/chrome/browser/ui/cocoa/download/background_theme.h
+++ b/chrome/browser/ui/cocoa/download/background_theme.h
@@ -24,11 +24,10 @@
   virtual base::RefCountedMemory* GetRawData(
       int id,
       ui::ScaleFactor scale_factor) const OVERRIDE;
-  virtual NSImage* GetNSImageNamed(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSImageColorNamed(int id,
-                                        bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColor(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColorTint(int id, bool allow_default) const OVERRIDE;
+  virtual NSImage* GetNSImageNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSImageColorNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSColor(int id) const OVERRIDE;
+  virtual NSColor* GetNSColorTint(int id) const OVERRIDE;
   virtual NSGradient* GetNSGradient(int id) const OVERRIDE;
 
  private:
diff --git a/chrome/browser/ui/cocoa/download/background_theme.mm b/chrome/browser/ui/cocoa/download/background_theme.mm
index 9ee1d29..eb7ffcf 100644
--- a/chrome/browser/ui/cocoa/download/background_theme.mm
+++ b/chrome/browser/ui/cocoa/download/background_theme.mm
@@ -53,24 +53,23 @@
   return NULL;
 }
 
-NSImage* BackgroundTheme::GetNSImageNamed(int id, bool allow_default) const {
+NSImage* BackgroundTheme::GetNSImageNamed(int id) const {
   return nil;
 }
 
-NSColor* BackgroundTheme::GetNSImageColorNamed(int id,
-                                               bool allow_default) const {
+NSColor* BackgroundTheme::GetNSImageColorNamed(int id) const {
   return nil;
 }
 
-NSColor* BackgroundTheme::GetNSColor(int id, bool allow_default) const {
-  return provider_->GetNSColor(id, allow_default);
+NSColor* BackgroundTheme::GetNSColor(int id) const {
+  return provider_->GetNSColor(id);
 }
 
-NSColor* BackgroundTheme::GetNSColorTint(int id, bool allow_default) const {
+NSColor* BackgroundTheme::GetNSColorTint(int id) const {
   if (id == ThemeProperties::TINT_BUTTONS)
     return borderColor_.get();
 
-  return provider_->GetNSColorTint(id, allow_default);
+  return provider_->GetNSColorTint(id);
 }
 
 NSGradient* BackgroundTheme::GetNSGradient(int id) const {
diff --git a/chrome/browser/ui/cocoa/download/download_item_cell.mm b/chrome/browser/ui/cocoa/download/download_item_cell.mm
index 4da8b9b..96c30a0 100644
--- a/chrome/browser/ui/cocoa/download/download_item_cell.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_cell.mm
@@ -414,7 +414,7 @@
       [[[self controlView] window] themeProvider];
   if ([self pressedWithDefaultThemeOnPart:part] || !themeProvider)
     return [NSColor alternateSelectedControlTextColor];
-  return themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT, true);
+  return themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
 }
 
 - (void)drawSecondaryTitleInRect:(NSRect)innerFrame {
diff --git a/chrome/browser/ui/cocoa/download/download_item_controller.mm b/chrome/browser/ui/cocoa/download/download_item_controller.mm
index c5f3ada..eeadce3 100644
--- a/chrome/browser/ui/cocoa/download/download_item_controller.mm
+++ b/chrome/browser/ui/cocoa/download/download_item_controller.mm
@@ -285,8 +285,7 @@
   if (!themeProvider)
     return;
 
-  NSColor* color =
-      themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT, true);
+  NSColor* color = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
   [dangerousDownloadLabel_ setTextColor:color];
 }
 
diff --git a/chrome/browser/ui/cocoa/download/download_shelf_view.mm b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
index a80420e..84be11e 100644
--- a/chrome/browser/ui/cocoa/download/download_shelf_view.mm
+++ b/chrome/browser/ui/cocoa/download/download_shelf_view.mm
@@ -37,7 +37,7 @@
   ui::ThemeProvider* themeProvider = [[self window] themeProvider];
   return themeProvider ? themeProvider->GetNSColor(
       isActive ? ThemeProperties::COLOR_TOOLBAR_STROKE :
-                 ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE, true) :
+                 ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE) :
       [NSColor blackColor];
 }
 
@@ -65,7 +65,7 @@
   if (themeProvider) {
     int resourceName = themeProvider->UsingDefaultTheme() ?
         ThemeProperties::COLOR_TOOLBAR_BEZEL : ThemeProperties::COLOR_TOOLBAR;
-    NSColor* highlightColor = themeProvider->GetNSColor(resourceName, true);
+    NSColor* highlightColor = themeProvider->GetNSColor(resourceName);
     if (highlightColor) {
       [highlightColor set];
       borderRect.origin.y -= [self cr_lineWidth];
diff --git a/chrome/browser/ui/cocoa/download/download_show_all_cell.mm b/chrome/browser/ui/cocoa/download/download_show_all_cell.mm
index d7f6d6b..879477e 100644
--- a/chrome/browser/ui/cocoa/download/download_show_all_cell.mm
+++ b/chrome/browser/ui/cocoa/download/download_show_all_cell.mm
@@ -96,7 +96,7 @@
       [[[self controlView] window] themeProvider];
   if (!themeProvider || [self pressedWithDefaultTheme])
     return [NSColor alternateSelectedControlTextColor];
-  return themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT, true);
+  return themeProvider->GetNSColor(ThemeProperties::COLOR_BOOKMARK_TEXT);
 }
 
 - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm
index d53bd30..acf4ca4 100644
--- a/chrome/browser/ui/cocoa/framed_browser_window.mm
+++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -423,7 +423,7 @@
     else
       themeImageID = IDR_THEME_FRAME_INACTIVE;
     if (themeProvider->HasCustomImage(IDR_THEME_FRAME))
-      themeImageColor = themeProvider->GetNSImageColorNamed(themeImageID, true);
+      themeImageColor = themeProvider->GetNSImageColorNamed(themeImageID);
   }
 
   // If no theme image, use a gradient if incognito.
@@ -487,8 +487,7 @@
       !popup) {
     overlayImage = themeProvider->
         GetNSImageNamed(active ? IDR_THEME_FRAME_OVERLAY :
-                                 IDR_THEME_FRAME_OVERLAY_INACTIVE,
-                        true);
+                                 IDR_THEME_FRAME_OVERLAY_INACTIVE);
   }
 
   if (overlayImage) {
diff --git a/chrome/browser/ui/cocoa/gradient_button_cell.mm b/chrome/browser/ui/cocoa/gradient_button_cell.mm
index 959e0d3..1935761 100644
--- a/chrome/browser/ui/cocoa/gradient_button_cell.mm
+++ b/chrome/browser/ui/cocoa/gradient_button_cell.mm
@@ -362,11 +362,12 @@
     if (!showClickedGradient)
       hoverAlpha *= 0.6;
   } else {
-    backgroundImageColor =
-        themeProvider ?
-          themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND,
-                                              false) :
-          nil;
+    backgroundImageColor = nil;
+    if (themeProvider &&
+        themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)) {
+      backgroundImageColor =
+          themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND);
+    }
     useThemeGradient = backgroundImageColor ? YES : NO;
   }
 
@@ -444,9 +445,9 @@
   } else {
     strokeColor = themeProvider ? themeProvider->GetNSColor(
         active ? ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE :
-                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
-        true) : [NSColor colorWithCalibratedWhite:0.0
-                                            alpha:0.3 * outerStrokeAlphaMult_];
+                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE) :
+        [NSColor colorWithCalibratedWhite:0.0
+                                    alpha:0.3 * outerStrokeAlphaMult_];
   }
   [strokeColor setStroke];
 
@@ -559,8 +560,8 @@
     NSDivideRect(cellFrame, &borderRect, &contentRect, lineWidth, NSMaxXEdge);
     NSColor* stroke = themeProvider ? themeProvider->GetNSColor(
         active ? ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE :
-                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
-        true) : [NSColor blackColor];
+                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE) :
+        [NSColor blackColor];
 
     [[stroke colorWithAlphaComponent:0.2] set];
     NSRectFillUsingOperation(NSInsetRect(borderRect, 0, 2),
@@ -600,13 +601,13 @@
     ThemeService* themeProvider = static_cast<ThemeService*>(
         [[controlView window] themeProvider]);
     NSColor* color = themeProvider ?
-        themeProvider->GetNSColorTint(ThemeProperties::TINT_BUTTONS, true) :
+        themeProvider->GetNSColorTint(ThemeProperties::TINT_BUTTONS) :
         [NSColor blackColor];
 
     if (isTemplate && themeProvider && themeProvider->UsingDefaultTheme()) {
       base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
       [shadow.get() setShadowColor:themeProvider->GetNSColor(
-          ThemeProperties::COLOR_TOOLBAR_BEZEL, true)];
+          ThemeProperties::COLOR_TOOLBAR_BEZEL)];
       [shadow.get() setShadowOffset:NSMakeSize(0.0, -lineWidth)];
       [shadow setShadowBlurRadius:lineWidth];
       [shadow set];
diff --git a/chrome/browser/ui/cocoa/image_button_cell.mm b/chrome/browser/ui/cocoa/image_button_cell.mm
index 13dc59d..773c91d 100644
--- a/chrome/browser/ui/cocoa/image_button_cell.mm
+++ b/chrome/browser/ui/cocoa/image_button_cell.mm
@@ -165,7 +165,7 @@
   if (!themeProvider)
     return nil;
 
-  return themeProvider->GetNSImageNamed(imageID, true);
+  return themeProvider->GetNSImageNamed(imageID);
 }
 
 - (void)setIsMouseInside:(BOOL)isMouseInside {
diff --git a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
index 51fdb17..c86f463 100644
--- a/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
+++ b/chrome/browser/ui/cocoa/infobars/infobar_gradient_view.mm
@@ -56,8 +56,7 @@
   BOOL active = [[self window] isMainWindow];
   return themeProvider->GetNSColor(
       active ? ThemeProperties::COLOR_TOOLBAR_STROKE :
-               ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE,
-      true);
+               ThemeProperties::COLOR_TOOLBAR_STROKE_INACTIVE);
 }
 
 - (void)drawRect:(NSRect)rect {
diff --git a/chrome/browser/ui/cocoa/notifications/OWNERS b/chrome/browser/ui/cocoa/notifications/OWNERS
index 967c65c..14fce2a 100644
--- a/chrome/browser/ui/cocoa/notifications/OWNERS
+++ b/chrome/browser/ui/cocoa/notifications/OWNERS
@@ -1 +1 @@
-johnnyg@chromium.org
+rsesek@chromium.org
diff --git a/chrome/browser/ui/cocoa/styled_text_field_cell.mm b/chrome/browser/ui/cocoa/styled_text_field_cell.mm
index fedd3fc..c1f53b2 100644
--- a/chrome/browser/ui/cocoa/styled_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/styled_text_field_cell.mm
@@ -93,8 +93,11 @@
   ThemeService* themeProvider =
       static_cast<ThemeService*>([[controlView window] themeProvider]);
   if (themeProvider) {
-    NSColor* backgroundImageColor =
-        themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND, false);
+    NSColor* backgroundImageColor = nil;
+    if (themeProvider->HasCustomImage(IDR_THEME_BUTTON_BACKGROUND)) {
+      backgroundImageColor =
+          themeProvider->GetNSImageColorNamed(IDR_THEME_BUTTON_BACKGROUND);
+    }
     if (backgroundImageColor) {
       // Set the phase to match window.
       NSRect trueRect = [controlView convertRect:cellFrame toView:nil];
@@ -114,8 +117,7 @@
     BOOL active = [[controlView window] isMainWindow];
     NSColor* strokeColor = themeProvider->GetNSColor(
         active ? ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE :
-                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE,
-        true);
+                 ThemeProperties::COLOR_TOOLBAR_BUTTON_STROKE_INACTIVE);
     rect_path_utils::FrameRectWithInset(roundedCornerFlags, frame, 0.0, 0.0,
                                         radius, lineWidth, strokeColor);
   }
@@ -149,7 +151,7 @@
       themeProvider->UsingDefaultTheme()) {
 
     NSColor* bezelColor = themeProvider->GetNSColor(
-        ThemeProperties::COLOR_TOOLBAR_BEZEL, true);
+        ThemeProperties::COLOR_TOOLBAR_BEZEL);
     [[bezelColor colorWithAlphaComponent:0.5 / lineWidth] set];
     NSRect bezelRect = NSMakeRect(cellFrame.origin.x,
                                   NSMaxY(cellFrame) - lineWidth,
diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
index 1006ef0..5f9bb2f 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_controller.mm
@@ -359,16 +359,11 @@
 - (void)updateTitleColor {
   NSColor* titleColor = nil;
   ui::ThemeProvider* theme = [[[self view] window] themeProvider];
-  if (theme && ![self selected]) {
-    titleColor =
-        theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT,
-                          true);
-  }
+  if (theme && ![self selected])
+    titleColor = theme->GetNSColor(ThemeProperties::COLOR_BACKGROUND_TAB_TEXT);
   // Default to the selected text color unless told otherwise.
-  if (theme && !titleColor) {
-    titleColor = theme->GetNSColor(ThemeProperties::COLOR_TAB_TEXT,
-                                   true);
-  }
+  if (theme && !titleColor)
+    titleColor = theme->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
   [titleView_ setTextColor:titleColor ? titleColor : [NSColor textColor]];
 }
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
index 55ce2eb..c99c63f 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_controller.mm
@@ -1622,8 +1622,8 @@
         ui::ThemeProvider* theme = [[tabStripView_ window] themeProvider];
         if (theme && [tabController projecting]) {
           NSImage* projectorGlow =
-              theme->GetNSImageNamed(IDR_TAB_CAPTURE_GLOW, true);
-          NSImage* projector = theme->GetNSImageNamed(IDR_TAB_CAPTURE, true);
+              theme->GetNSImageNamed(IDR_TAB_CAPTURE_GLOW);
+          NSImage* projector = theme->GetNSImageNamed(IDR_TAB_CAPTURE);
 
           NSRect frame = NSMakeRect(0,
                                     0,
@@ -1641,8 +1641,8 @@
           iconView = projectingView;
         } else if (theme && chrome::ShouldShowRecordingIndicator(contents)) {
           // Create a masked favicon.
-          NSImage* mask = theme->GetNSImageNamed(IDR_TAB_RECORDING_MASK, true);
-          NSImage* recording = theme->GetNSImageNamed(IDR_TAB_RECORDING, true);
+          NSImage* mask = theme->GetNSImageNamed(IDR_TAB_RECORDING_MASK);
+          NSImage* recording = theme->GetNSImageNamed(IDR_TAB_RECORDING);
           NSImage* favIconMasked = CreateMaskedFaviconForRecording(
                                        [imageView image], mask, recording);
 
@@ -2270,7 +2270,7 @@
   NSImage* pressed = rb.GetNativeImageNamed(IDR_NEWTAB_BUTTON_P).ToNSImage();
 
   NSImage* foreground = ApplyMask(
-      theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND, true), mask);
+      theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND), mask);
 
   [[newTabButton_ cell] setImage:Overlay(foreground, normal, 1.0)
                   forButtonState:image_button_cell::kDefaultState];
@@ -2283,7 +2283,7 @@
   if (theme->UsingDefaultTheme()) {
     const CGFloat alpha = tabs::kImageNoFocusAlpha;
     NSImage* background = ApplyMask(
-        theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND_INACTIVE, true), mask);
+        theme->GetNSImageNamed(IDR_THEME_TAB_BACKGROUND_INACTIVE), mask);
     [[newTabButton_ cell] setImage:Overlay(background, normal, alpha)
                     forButtonState:image_button_cell::kDefaultStateBackground];
     [[newTabButton_ cell] setImage:Overlay(background, hover, alpha)
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
index e62eb67..1ac010a 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_view.mm
@@ -65,13 +65,13 @@
     bool active = [[self window] isKeyWindow] || [[self window] isMainWindow] ||
                   !themeProvider->UsingDefaultTheme();
     int resource_id = active ? IDR_THEME_TOOLBAR : IDR_THEME_TOOLBAR_INACTIVE;
-    [themeProvider->GetNSImageColorNamed(resource_id, true) set];
+    [themeProvider->GetNSImageColorNamed(resource_id) set];
     NSRectFill(
         NSMakeRect(NSMinX(dirtyRect), 0, NSWidth(dirtyRect), backgroundHeight));
   }
 
   // Draw the border bitmap, which is partially transparent.
-  NSImage* image = themeProvider->GetNSImageNamed(IDR_TOOLBAR_SHADE_TOP, true);
+  NSImage* image = themeProvider->GetNSImageNamed(IDR_TOOLBAR_SHADE_TOP);
   if (NSMinY(dirtyRect) >= [image size].height)
     return;
 
diff --git a/chrome/browser/ui/cocoa/tabs/tab_view.mm b/chrome/browser/ui/cocoa/tabs/tab_view.mm
index 99985d9..57c46a5 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_view.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_view.mm
@@ -297,8 +297,7 @@
   // theme.
   bool active = [[self window] isKeyWindow] || [[self window] isMainWindow] ||
                 !themeProvider->UsingDefaultTheme();
-  return themeProvider->GetNSImageColorNamed(
-      bitmapResources[active][selected], true);
+  return themeProvider->GetNSImageColorNamed(bitmapResources[active][selected]);
 }
 
 // Draws the active tab background.
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index 72b1c95..02112d1 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -6,13 +6,13 @@
 
 #include <string>
 
+#include "apps/launcher.h"
 #include "base/command_line.h"
 #include "base/metrics/histogram.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/extensions/extension_prefs.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_system.h"
-#include "chrome/browser/extensions/platform_app_launcher.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -20,6 +20,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/app_metro_infobar_delegate_win.h"
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/web_applications/web_app.h"
@@ -342,7 +343,18 @@
   UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunchContainer", container, 100);
 
   if (extension->is_platform_app()) {
-    extensions::LaunchPlatformAppWithCommandLine(
+#if defined(OS_WIN)
+    // On Windows 8's single window Metro mode we can not launch platform apps.
+    // Offer to switch Chrome to desktop mode.
+    if (win8::IsSingleWindowMetroMode()) {
+      AppMetroInfoBarDelegateWin::Create(
+          profile, AppMetroInfoBarDelegateWin::LAUNCH_PACKAGED_APP,
+          extension->id());
+      return NULL;
+    }
+#endif
+
+    apps::LaunchPlatformAppWithCommandLine(
         profile, extension, params.command_line, params.current_directory);
     return NULL;
   }
diff --git a/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc b/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc
index 5ab07d3..c58ed62 100644
--- a/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc
+++ b/chrome/browser/ui/gtk/constrained_web_dialog_delegate_gtk.cc
@@ -34,7 +34,8 @@
       WebDialogDelegate* delegate,
       WebDialogWebContentsDelegate* tab_delegate)
       : ConstrainedWebDialogDelegateBase(
-            browser_context, delegate, tab_delegate) {}
+            browser_context, delegate, tab_delegate),
+        window_(NULL) {}
 
   // WebDialogWebContentsDelegate interface.
   virtual void CloseContents(WebContents* source) OVERRIDE {
diff --git a/chrome/browser/ui/gtk/gtk_theme_service.cc b/chrome/browser/ui/gtk/gtk_theme_service.cc
index e2272c4..76befd6 100644
--- a/chrome/browser/ui/gtk/gtk_theme_service.cc
+++ b/chrome/browser/ui/gtk/gtk_theme_service.cc
@@ -630,13 +630,6 @@
   return false;
 }
 
-void GtkThemeService::ClearAllThemeData() {
-  colors_.clear();
-  tints_.clear();
-
-  ThemeService::ClearAllThemeData();
-}
-
 void GtkThemeService::LoadThemePrefs() {
   // Initialize the values sent to webkit with the default values.
   // ThemeService::LoadThemePrefs() will replace them with values for the native
@@ -651,6 +644,9 @@
 }
 
 void GtkThemeService::NotifyThemeChanged() {
+  if (!ready_)
+    return;
+
   ThemeService::NotifyThemeChanged();
 
   // Notify all GtkChromeButtons of their new rendering mode:
@@ -683,6 +679,8 @@
 }
 
 void GtkThemeService::FreePlatformCaches() {
+  colors_.clear();
+  tints_.clear();
   ThemeService::FreePlatformCaches();
   STLDeleteValues(&gtk_images_);
 }
diff --git a/chrome/browser/ui/gtk/gtk_theme_service.h b/chrome/browser/ui/gtk/gtk_theme_service.h
index a7e3f90..18a840e 100644
--- a/chrome/browser/ui/gtk/gtk_theme_service.h
+++ b/chrome/browser/ui/gtk/gtk_theme_service.h
@@ -159,9 +159,6 @@
   typedef std::map<int, color_utils::HSL> TintMap;
   typedef std::map<int, gfx::Image*> ImageCache;
 
-  // Clears all the GTK color overrides.
-  virtual void ClearAllThemeData() OVERRIDE;
-
   // Load theme data from preferences, possibly picking colors from GTK.
   virtual void LoadThemePrefs() OVERRIDE;
 
diff --git a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
index 4f5757b..9518620 100644
--- a/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
+++ b/chrome/browser/ui/search/instant_extended_interactive_uitest.cc
@@ -312,21 +312,14 @@
 
   void InstallThemeAndVerify(const std::string& theme_dir,
                              const std::string& theme_name) {
+    const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir);
+    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
+        theme_path, 1, ExtensionBrowserTest::browser()));
     const extensions::Extension* theme =
         ThemeServiceFactory::GetThemeForProfile(
             ExtensionBrowserTest::browser()->profile());
-    // If there is already a theme installed, the current theme should be
-    // disabled and the new one installed + enabled.
-    int expected_change = theme ? 0 : 1;
-
-    const base::FilePath theme_path = test_data_dir_.AppendASCII(theme_dir);
-    ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
-        theme_path, expected_change, ExtensionBrowserTest::browser()));
-    const extensions::Extension* new_theme =
-        ThemeServiceFactory::GetThemeForProfile(
-            ExtensionBrowserTest::browser()->profile());
-    ASSERT_NE(static_cast<extensions::Extension*>(NULL), new_theme);
-    ASSERT_EQ(new_theme->name(), theme_name);
+    ASSERT_NE(static_cast<extensions::Extension*>(NULL), theme);
+    ASSERT_EQ(theme->name(), theme_name);
   }
 
  private:
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 481b780..d76ca8d 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -1047,7 +1047,7 @@
   // }
   StartupBrowserCreator browser_creator;
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, false);
+      prefs::kSignInPromoShowOnFirstRunAllowed, false);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1081,7 +1081,7 @@
   // }
   StartupBrowserCreator browser_creator;
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, true);
+      prefs::kSignInPromoShowOnFirstRunAllowed, true);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1117,7 +1117,7 @@
   StartupBrowserCreator browser_creator;
   browser_creator.AddFirstRunTab(test_server()->GetURL("files/title1.html"));
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, true);
+      prefs::kSignInPromoShowOnFirstRunAllowed, true);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1156,7 +1156,7 @@
   browser_creator.AddFirstRunTab(signin::GetPromoURL(signin::SOURCE_START_PAGE,
                                                      false));
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, true);
+      prefs::kSignInPromoShowOnFirstRunAllowed, true);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1195,7 +1195,7 @@
   browser_creator.AddFirstRunTab(GURL("new_tab_page"));
   browser_creator.AddFirstRunTab(test_server()->GetURL("files/title1.html"));
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, true);
+      prefs::kSignInPromoShowOnFirstRunAllowed, true);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1234,7 +1234,7 @@
   browser_creator.AddFirstRunTab(GURL("new_tab_page"));
   browser_creator.AddFirstRunTab(test_server()->GetURL("files/title1.html"));
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, false);
+      prefs::kSignInPromoShowOnFirstRunAllowed, false);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1271,7 +1271,7 @@
   StartupBrowserCreator browser_creator;
   browser_creator.AddFirstRunTab(test_server()->GetURL("files/title1.html"));
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, false);
+      prefs::kSignInPromoShowOnFirstRunAllowed, false);
 
   // Do a process-startup browser launch.
   CommandLine dummy(CommandLine::NO_PROGRAM);
@@ -1302,7 +1302,7 @@
   // }
   StartupBrowserCreator browser_creator;
   browser()->profile()->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowOnFirstRunAllowed, true);
+      prefs::kSignInPromoShowOnFirstRunAllowed, true);
 
   // Set the following user policies:
   // * RestoreOnStartup = RestoreOnStartupIsURLs
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 1ec9507..cea4329 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -69,7 +69,6 @@
 #include "chrome/browser/ui/tabs/pinned_tab_codec.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
-#include "chrome/browser/ui/webui/sync_promo/sync_promo_trial.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_result_codes.h"
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
index f58ba89..0ab3291 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/favicon/favicon_types.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "grit/theme_resources.h"
diff --git a/chrome/browser/ui/views/autofill/autocheckout_bubble_views.cc b/chrome/browser/ui/views/autofill/autocheckout_bubble_views.cc
index 27451aa..3496ec6 100644
--- a/chrome/browser/ui/views/autofill/autocheckout_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/autocheckout_bubble_views.cc
@@ -16,6 +16,10 @@
 #include "ui/views/layout/layout_constants.h"
 #include "ui/views/widget/widget.h"
 
+#if defined(USE_AURA)
+#include "ui/aura/window.h"
+#endif
+
 namespace autofill {
 
 AutocheckoutBubbleViews::AutocheckoutBubbleViews(
@@ -136,6 +140,13 @@
 // static
 base::WeakPtr<AutocheckoutBubble> AutocheckoutBubble::Create(
     scoped_ptr<AutocheckoutBubbleController> controller) {
+#if defined(USE_AURA)
+  // If the page hasn't yet been attached to a RootWindow,
+  // Aura code for creating the bubble will fail.
+  if (!controller->native_window()->GetRootWindow())
+    return base::WeakPtr<AutocheckoutBubble>();
+#endif // defined(USE_AURA)
+
   views::Widget* widget = views::Widget::GetTopLevelWidgetForNativeView(
       controller->native_window());
   // The bubble owns itself.
diff --git a/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc b/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
index fb2f238..48f7167 100644
--- a/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_credit_card_bubble_views.cc
@@ -22,6 +22,19 @@
 
 namespace autofill {
 
+namespace {
+
+// Get the view this bubble will be anchored to via |controller|.
+views::View* GetAnchor(
+    const base::WeakPtr<AutofillCreditCardBubbleController>& controller) {
+  Browser* browser =
+      chrome::FindBrowserWithWebContents(controller->web_contents());
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser);
+  return browser_view->GetLocationBarView()->autofill_credit_card_view();
+}
+
+}  // namespace
+
 AutofillCreditCardBubbleViews::~AutofillCreditCardBubbleViews() {}
 
 void AutofillCreditCardBubbleViews::Show() {
@@ -29,6 +42,9 @@
   views::BubbleDelegateView::CreateBubble(this);
 
   GetWidget()->Show();
+
+  // This bubble doesn't render correctly on Windows without calling
+  // |SizeToContents()|. This must be called after showing the widget.
   SizeToContents();
 }
 
@@ -88,10 +104,7 @@
 
 AutofillCreditCardBubbleViews::AutofillCreditCardBubbleViews(
     const base::WeakPtr<AutofillCreditCardBubbleController>& controller)
-    : BubbleDelegateView(BrowserView::GetBrowserViewForBrowser(
-          chrome::FindBrowserWithWebContents(controller->web_contents()))->
-              GetLocationBarView()->autofill_credit_card_view(),
-        views::BubbleBorder::TOP_RIGHT),
+    : BubbleDelegateView(GetAnchor(controller), views::BubbleBorder::TOP_RIGHT),
       controller_(controller),
       weak_ptr_factory_(this) {
   // Match bookmarks bubble view's anchor view insets and margins.
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
index 85c46de..40db3e6 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.cc
@@ -1115,6 +1115,7 @@
       overlay_view_(NULL),
       button_strip_extra_view_(NULL),
       save_in_chrome_checkbox_(NULL),
+      save_in_chrome_checkbox_container_(NULL),
       button_strip_image_(NULL),
       autocheckout_steps_area_(NULL),
       autocheckout_progress_bar_view_(NULL),
@@ -1150,10 +1151,10 @@
   // care of deleting itself after calling DeleteDelegate().
   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
       WebContentsModalDialogManager::FromWebContents(
-          delegate_->web_contents());
+          delegate_->GetWebContents());
   window_ = CreateWebContentsModalDialogViews(
       this,
-      delegate_->web_contents()->GetView()->GetNativeView(),
+      delegate_->GetWebContents()->GetView()->GetNativeView(),
       web_contents_modal_dialog_manager->delegate()->
           GetWebContentsModalDialogHost());
   web_contents_modal_dialog_manager->ShowDialog(window_->GetNativeView());
@@ -1163,7 +1164,7 @@
   // Listen for size changes on the browser.
   views::Widget* browser_widget =
       views::Widget::GetTopLevelWidgetForNativeView(
-          delegate_->web_contents()->GetView()->GetNativeView());
+          delegate_->GetWebContents()->GetView()->GetNativeView());
   observer_.Add(browser_widget);
 
   gfx::Image splash_image = delegate_->SplashPageImage();
@@ -1432,7 +1433,7 @@
     // bottom of the browser window.
     views::Widget* widget =
         views::Widget::GetTopLevelWidgetForNativeView(
-            delegate_->web_contents()->GetView()->GetNativeView());
+            delegate_->GetWebContents()->GetView()->GetNativeView());
     int browser_window_height =
         widget ? widget->GetContentsView()->bounds().height() : INT_MAX;
     const int kWindowDecorationHeight = 200;
@@ -1588,7 +1589,7 @@
     views::Widget* widget) {
   return CreateConstrainedStyleNonClientFrameView(
       widget,
-      delegate_->web_contents()->GetBrowserContext());
+      delegate_->GetWebContents()->GetBrowserContext());
 }
 
 void AutofillDialogViews::ButtonPressed(views::Button* sender,
@@ -1697,10 +1698,18 @@
   button_strip_extra_view_->SetLayoutManager(
       new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
 
+  save_in_chrome_checkbox_container_ = new views::View();
+  save_in_chrome_checkbox_container_->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 7));
+  button_strip_extra_view_->AddChildView(save_in_chrome_checkbox_container_);
+
   save_in_chrome_checkbox_ =
       new views::Checkbox(delegate_->SaveLocallyText());
   save_in_chrome_checkbox_->SetChecked(true);
-  button_strip_extra_view_->AddChildView(save_in_chrome_checkbox_);
+  save_in_chrome_checkbox_container_->AddChildView(save_in_chrome_checkbox_);
+
+  save_in_chrome_checkbox_container_->AddChildView(
+      new TooltipIcon(delegate_->SaveLocallyTooltip()));
 
   button_strip_image_ = new views::ImageView();
   button_strip_extra_view_->AddChildView(button_strip_image_);
@@ -2188,7 +2197,7 @@
 }
 
 void AutofillDialogViews::UpdateButtonStripExtraView() {
-  save_in_chrome_checkbox_->SetVisible(
+  save_in_chrome_checkbox_container_->SetVisible(
       delegate_->ShouldOfferToSaveInChrome());
 
   gfx::Image image = delegate_->ButtonStripImage();
diff --git a/chrome/browser/ui/views/autofill/autofill_dialog_views.h b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
index 31c9ae9..7afc8f5 100644
--- a/chrome/browser/ui/views/autofill/autofill_dialog_views.h
+++ b/chrome/browser/ui/views/autofill/autofill_dialog_views.h
@@ -596,6 +596,9 @@
   // database. It lives in |extra_view_|.
   views::Checkbox* save_in_chrome_checkbox_;
 
+  // Holds the above checkbox and an associated tooltip icon.
+  views::View* save_in_chrome_checkbox_container_;
+
   // Used to display an image in the button strip extra view.
   views::ImageView* button_strip_image_;
 
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 917d28c..da98e43 100644
--- a/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
+++ b/chrome/browser/ui/views/constrained_web_dialog_delegate_views.cc
@@ -39,7 +39,8 @@
       views::WebView* view)
       : ConstrainedWebDialogDelegateBase(
             browser_context, delegate, tab_delegate),
-        view_(view) {}
+        view_(view),
+        window_(NULL) {}
 
   virtual ~ConstrainedWebDialogDelegateViews() {}
 
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
index 9fd4fac..e469a3c 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.cc
@@ -58,6 +58,19 @@
 // of just more vertical then horizontal.
 const int kSwipeVerticalThresholdMultiplier = 3;
 
+// The height in pixels of the region above the top edge of the display which
+// hosts the immersive fullscreen window in which mouse events are ignored
+// (cannot reveal or unreveal the top-of-window views).
+// See ShouldIgnoreMouseEventAtLocation() for more details.
+const int kHeightOfDeadRegionAboveTopContainer = 10;
+
+// The height in pixels of the region below the top edge of the display in which
+// the mouse can trigger revealing the top-of-window views. The height must be
+// greater than 1px because the top pixel is used to trigger moving the cursor
+// between displays if the user has a vertical display layout (primary display
+// above/below secondary display).
+const int kMouseRevealBoundsHeight = 3;
+
 // If |hovered| is true, moves the mouse above |view|. Moves it outside of
 // |view| otherwise.
 // Should not be called outside of tests.
@@ -255,7 +268,7 @@
       reveal_state_(CLOSED),
       revealed_lock_count_(0),
       tab_indicator_visibility_(TAB_INDICATORS_HIDE),
-      mouse_x_when_hit_top_(-1),
+      mouse_x_when_hit_top_in_screen_(-1),
       gesture_begun_(false),
       native_window_(NULL),
       animation_(new ui::SlideAnimation(this)),
@@ -695,30 +708,33 @@
   }
 
   gfx::Point location_in_screen = GetEventLocationInScreen(*event);
-  gfx::Rect top_container_bounds_in_screen =
-      top_container_->GetBoundsInScreen();
+  if (ShouldIgnoreMouseEventAtLocation(location_in_screen))
+    return;
 
   // Stop the timer if the cursor left the top edge or is on a different
-  // display.
-  if (location_in_screen.y() != top_container_bounds_in_screen.y() ||
-      location_in_screen.x() < top_container_bounds_in_screen.x() ||
-      location_in_screen.x() >= top_container_bounds_in_screen.right()) {
+  // display. The bounds of |top_container_|'s parent are used to infer the hit
+  // bounds because |top_container_| will be partially offscreen if it is
+  // animating closed.
+  gfx::Rect hit_bounds_in_screen =
+      top_container_->parent()->GetBoundsInScreen();
+  hit_bounds_in_screen.set_height(kMouseRevealBoundsHeight);
+  if (!hit_bounds_in_screen.Contains(location_in_screen)) {
     top_edge_hover_timer_.Stop();
     return;
   }
 
   // The cursor is now at the top of the screen. Consider the cursor "not
-  // moving" even if it moves a little bit in x, because users don't have
-  // perfect pointing precision.
-  int mouse_x = location_in_screen.x() - top_container_bounds_in_screen.x();
+  // moving" even if it moves a little bit because users don't have perfect
+  // pointing precision. (The y position is not tested because
+  // |hit_bounds_in_screen| is short.)
   if (top_edge_hover_timer_.IsRunning() &&
-      abs(mouse_x - mouse_x_when_hit_top_) <=
+      abs(location_in_screen.x() - mouse_x_when_hit_top_in_screen_) <=
           ImmersiveFullscreenConfiguration::
               immersive_mode_reveal_x_threshold_pixels())
     return;
 
   // Start the reveal if the cursor doesn't move for some amount of time.
-  mouse_x_when_hit_top_ = mouse_x;
+  mouse_x_when_hit_top_in_screen_ = location_in_screen.x();
   top_edge_hover_timer_.Stop();
   // Timer is stopped when |this| is destroyed, hence Unretained() is safe.
   top_edge_hover_timer_.Start(
@@ -769,7 +785,19 @@
     location_in_screen = aura::Env::GetInstance()->last_mouse_location();
   }
 
-  gfx::Rect hit_bounds_in_screen = top_container_->GetBoundsInScreen();
+  if ((!event || event->IsMouseEvent()) &&
+      ShouldIgnoreMouseEventAtLocation(location_in_screen)) {
+    return;
+  }
+
+  gfx::Rect hit_bounds_in_top_container = top_container_->GetVisibleBounds();
+  // TODO(tdanderson): Implement View::ConvertRectToScreen();
+  gfx::Point hit_bounds_in_screen_origin = hit_bounds_in_top_container.origin();
+  views::View::ConvertPointToScreen(top_container_,
+      &hit_bounds_in_screen_origin);
+  gfx::Rect hit_bounds_in_screen(hit_bounds_in_screen_origin,
+      hit_bounds_in_top_container.size());
+
   gfx::Rect find_bar_hit_bounds_in_screen = find_bar_visible_bounds_in_screen_;
 
   // Allow the cursor to move slightly off the top-of-window views before
@@ -1072,6 +1100,27 @@
   return SWIPE_NONE;
 }
 
+bool ImmersiveModeControllerAsh::ShouldIgnoreMouseEventAtLocation(
+    const gfx::Point& location) const {
+  // Ignore mouse events in the region immediately above the top edge of the
+  // display. This is to handle the case of a user with a vertical display
+  // layout (primary display above/below secondary display) and the immersive
+  // fullscreen window on the bottom display. It is really hard to trigger a
+  // reveal in this case because:
+  // - It is hard to stop the cursor in the top |kMouseRevealBoundsHeight|
+  //   pixels of the bottom display.
+  // - The cursor is warped to the top display if the cursor gets to the top
+  //   edge of the bottom display.
+  // Mouse events are ignored in the bottom few pixels of the top display
+  // (Mouse events in this region cannot start or end a reveal). This allows a
+  // user to overshoot the top of the bottom display and still reveal the
+  // top-of-window views.
+  gfx::Rect dead_region = top_container_->parent()->GetBoundsInScreen();
+  dead_region.set_y(dead_region.y() - kHeightOfDeadRegionAboveTopContainer);
+  dead_region.set_height(kHeightOfDeadRegionAboveTopContainer);
+  return dead_region.Contains(location);
+}
+
 bool ImmersiveModeControllerAsh::ShouldHandleGestureEvent(
     const gfx::Point& location) const {
   // All of the gestures that are of interest start in a region with left &
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
index 8ba1f2a..482c5b2 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash.h
@@ -211,6 +211,12 @@
   // Returns the type of swipe given |event|.
   SwipeType GetSwipeType(ui::GestureEvent* event) const;
 
+  // Returns true if a mouse event at |location_in_screen| should be ignored.
+  // Ignored mouse events should not contribute to revealing or unrevealing the
+  // top-of-window views.
+  bool ShouldIgnoreMouseEventAtLocation(
+      const gfx::Point& location_in_screen) const;
+
   // True when |location| is "near" to the top container. When the top container
   // is not closed "near" means within the displayed bounds or above it. When
   // the top container is closed "near" means either within the displayed
@@ -253,9 +259,9 @@
   // Timer to track cursor being held at the top edge of the screen.
   base::OneShotTimer<ImmersiveModeController> top_edge_hover_timer_;
 
-  // The cursor x position in root coordinates when the cursor first hit
-  // the top edge of the screen.
-  int mouse_x_when_hit_top_;
+  // The cursor x position in screen coordinates when the cursor first hit the
+  // top edge of the screen.
+  int mouse_x_when_hit_top_in_screen_;
 
   // Tracks if the controller has seen a ET_GESTURE_SCROLL_BEGIN, without the
   // following events.
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index 3a206ab..d91bbd8 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -4,9 +4,12 @@
 
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 
+#include "ash/display/display_controller.h"
+#include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "chrome/browser/ui/immersive_fullscreen_configuration.h"
 #include "ui/aura/client/cursor_client.h"
+#include "ui/aura/env.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/test/event_generator.h"
 #include "ui/aura/window.h"
@@ -61,16 +64,12 @@
   views::View* top_container() { return top_container_; }
   MockImmersiveModeControllerDelegate* delegate() { return delegate_.get(); }
 
-  aura::test::EventGenerator* event_generator() {
-    return event_generator_.get();
-  }
-
   // Access to private data from the controller.
   bool top_edge_hover_timer_running() const {
     return controller_->top_edge_hover_timer_.IsRunning();
   }
   int mouse_x_when_hit_top() const {
-    return controller_->mouse_x_when_hit_top_;
+    return controller_->mouse_x_when_hit_top_in_screen_;
   }
 
   // ash::test::AshTestBase overrides:
@@ -83,8 +82,6 @@
     controller_.reset(new ImmersiveModeControllerAsh);
     delegate_.reset(new MockImmersiveModeControllerDelegate);
 
-    event_generator_.reset(new aura::test::EventGenerator(CurrentContext()));
-
     widget_ = new views::Widget();
     views::Widget::InitParams params;
     params.context = CurrentContext();
@@ -125,9 +122,9 @@
   // Move the mouse to the given coordinates. The coordinates should be in
   // |top_container_| coordinates.
   void MoveMouse(int x, int y) {
-    // Luckily, |top_container_| is at the top left of the root window so the
-    // provided coordinates are already in the coordinates of the root window.
-    event_generator_->MoveMouseTo(x, y);
+    gfx::Point screen_position(x, y);
+    views::View::ConvertPointToScreen(top_container_, &screen_position);
+    GetEventGenerator().MoveMouseTo(screen_position.x(), screen_position.y());
 
     // If the top edge timer started running as a result of the mouse move, run
     // the task which occurs after the timer delay. This reveals the
@@ -150,11 +147,13 @@
         break;
       }
       case MODALITY_TOUCH: {
-        // Luckily, |top_container_| is at the top left of the root window so
-        // |event_position| is already in the coordinates of the root window.
-        event_generator_->MoveTouch(event_position);
-        event_generator_->PressTouch();
-        event_generator_->ReleaseTouch();
+        gfx::Point screen_position = event_position;
+        views::View::ConvertPointToScreen(top_container_, &screen_position);
+
+        aura::test::EventGenerator& event_generator(GetEventGenerator());
+        event_generator.MoveTouch(event_position);
+        event_generator.PressTouch();
+        event_generator.ReleaseTouch();
         break;
       }
       case MODALITY_GESTURE: {
@@ -208,63 +207,74 @@
   ASSERT_TRUE(controller()->IsEnabled());
   ASSERT_FALSE(controller()->IsRevealed());
 
+  aura::test::EventGenerator& event_generator(GetEventGenerator());
+
+  gfx::Rect top_container_bounds_in_screen =
+      top_container()->GetBoundsInScreen();
+  // A position along the top edge of TopContainerView in screen coordinates.
+  gfx::Point top_edge_pos(top_container_bounds_in_screen.x() + 100,
+                          top_container_bounds_in_screen.y());
+
   // Mouse wheel event does nothing.
   ui::MouseEvent wheel(
-      ui::ET_MOUSEWHEEL, gfx::Point(), gfx::Point(), ui::EF_NONE);
-  event_generator()->Dispatch(&wheel);
+      ui::ET_MOUSEWHEEL, top_edge_pos, top_edge_pos, ui::EF_NONE);
+  event_generator.Dispatch(&wheel);
   EXPECT_FALSE(top_edge_hover_timer_running());
 
   // Move to top edge of screen starts hover timer running. We cannot use
   // MoveMouse() because MoveMouse() stops the timer if it started running.
-  event_generator()->MoveMouseTo(100, 0);
+  event_generator.MoveMouseTo(top_edge_pos);
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(100, mouse_x_when_hit_top());
+  EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
 
-  // Moving off the top edge stops it.
-  event_generator()->MoveMouseTo(100, 1);
+  // Moving |ImmersiveModeControllerAsh::kMouseRevealBoundsHeight| down from
+  // the top edge stops it.
+  event_generator.MoveMouseBy(0, 3);
   EXPECT_FALSE(top_edge_hover_timer_running());
 
   // Moving back to the top starts the timer again.
-  event_generator()->MoveMouseTo(100, 0);
+  event_generator.MoveMouseTo(top_edge_pos);
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(100, mouse_x_when_hit_top());
+  EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
 
   // Slight move to the right keeps the timer running for the same hit point.
-  event_generator()->MoveMouseTo(101, 0);
+  event_generator.MoveMouseBy(1, 0);
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(100, mouse_x_when_hit_top());
+  EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
 
   // Moving back to the left also keeps the timer running.
-  event_generator()->MoveMouseTo(100, 0);
+  event_generator.MoveMouseBy(-1, 0);
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(100, mouse_x_when_hit_top());
+  EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
 
   // Large move right restarts the timer (so it is still running) and considers
   // this a new hit at the top.
-  event_generator()->MoveMouseTo(499, 0);
+  event_generator.MoveMouseTo(top_edge_pos.x() + 100, top_edge_pos.y());
   EXPECT_TRUE(top_edge_hover_timer_running());
-  EXPECT_EQ(499, mouse_x_when_hit_top());
+  EXPECT_EQ(top_edge_pos.x() + 100, mouse_x_when_hit_top());
 
   // Moving off the top edge horizontally stops the timer.
   EXPECT_GT(CurrentContext()->bounds().width(), top_container()->width());
-  EXPECT_EQ(500, top_container()->width());
-  event_generator()->MoveMouseTo(500, 0);
+  event_generator.MoveMouseTo(top_container_bounds_in_screen.right(),
+                              top_container_bounds_in_screen.y());
   EXPECT_FALSE(top_edge_hover_timer_running());
 
   // Once revealed, a move just a little below the top container doesn't end a
   // reveal.
   AttemptReveal(MODALITY_MOUSE);
-  event_generator()->MoveMouseTo(0, top_container()->height() + 1);
+  event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
+                              top_container_bounds_in_screen.bottom() + 1);
   EXPECT_TRUE(controller()->IsRevealed());
 
   // Once revealed, clicking just below the top container ends the reveal.
-  event_generator()->ClickLeftButton();
+  event_generator.ClickLeftButton();
   EXPECT_FALSE(controller()->IsRevealed());
 
   // Moving a lot below the top container ends a reveal.
   AttemptReveal(MODALITY_MOUSE);
   EXPECT_TRUE(controller()->IsRevealed());
-  event_generator()->MoveMouseTo(0, top_container()->height() + 50);
+  event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
+                              top_container_bounds_in_screen.bottom() + 50);
   EXPECT_FALSE(controller()->IsRevealed());
 
   // The mouse position cannot cause a reveal when TopContainerView's widget
@@ -280,7 +290,8 @@
   AttemptReveal(MODALITY_MOUSE);
   EXPECT_TRUE(controller()->IsRevealed());
   widget->SetCapture(top_container());
-  event_generator()->MoveMouseTo(0, top_container()->height() + 51);
+  event_generator.MoveMouseTo(top_container_bounds_in_screen.x(),
+                              top_container_bounds_in_screen.bottom() + 51);
   EXPECT_TRUE(controller()->IsRevealed());
 
   // Releasing capture should end the reveal.
@@ -288,6 +299,83 @@
   EXPECT_FALSE(controller()->IsRevealed());
 }
 
+// Test mouse event processing for top-of-screen reveal triggering when the user
+// has a vertical display layout (primary display above/below secondary display)
+// and the immersive fullscreen window is on the bottom display.
+TEST_F(ImmersiveModeControllerAshTest, MouseEventsVerticalDisplayLayout) {
+  if (!SupportsMultipleDisplays())
+    return;
+
+  // Set up initial state.
+  UpdateDisplay("800x600,800x600");
+  ash::DisplayLayout display_layout(ash::DisplayLayout::TOP, 0);
+  ash::Shell::GetInstance()->display_controller()->SetLayoutForCurrentDisplays(
+      display_layout);
+
+  controller()->SetEnabled(true);
+  ASSERT_TRUE(controller()->IsEnabled());
+  ASSERT_FALSE(controller()->IsRevealed());
+
+  ash::Shell::RootWindowList root_windows = ash::Shell::GetAllRootWindows();
+  ASSERT_EQ(root_windows[0],
+            top_container()->GetWidget()->GetNativeWindow()->GetRootWindow());
+
+  gfx::Rect primary_root_window_bounds_in_screen =
+      root_windows[0]->GetBoundsInScreen();
+  // Do not set |x| to the root window's x position because the display's
+  // corners have special behavior.
+  int x = primary_root_window_bounds_in_screen.x() + 10;
+  // The y position of the top edge of the primary display.
+  int y_top_edge = primary_root_window_bounds_in_screen.y();
+
+  aura::test::EventGenerator& event_generator(GetEventGenerator());
+
+  // Moving right below the top edge starts the hover timer running. We
+  // cannot use MoveMouse() because MoveMouse() stops the timer if it started
+  // running.
+  event_generator.MoveMouseTo(x, y_top_edge + 1);
+  EXPECT_TRUE(top_edge_hover_timer_running());
+  EXPECT_EQ(y_top_edge + 1,
+            aura::Env::GetInstance()->last_mouse_location().y());
+
+  // The timer should continue running if the user moves the mouse to the top
+  // edge even though the mouse is warped to the secondary display.
+  event_generator.MoveMouseTo(x, y_top_edge);
+  EXPECT_TRUE(top_edge_hover_timer_running());
+  EXPECT_NE(y_top_edge,
+            aura::Env::GetInstance()->last_mouse_location().y());
+
+  // The timer should continue running if the user overshoots the top edge
+  // a bit.
+  event_generator.MoveMouseTo(x, y_top_edge - 2);
+  EXPECT_TRUE(top_edge_hover_timer_running());
+
+  // The timer should stop running if the user overshoots the top edge by
+  // a lot.
+  event_generator.MoveMouseTo(x, y_top_edge - 20);
+  EXPECT_FALSE(top_edge_hover_timer_running());
+
+  // The timer should not start if the user moves the mouse to the bottom of the
+  // secondary display without crossing the top edge first.
+  event_generator.MoveMouseTo(x, y_top_edge - 2);
+
+  // Reveal the top-of-window views by overshooting the top edge slightly.
+  event_generator.MoveMouseTo(x, y_top_edge + 1);
+  // MoveMouse() runs the timer task.
+  MoveMouse(x, y_top_edge - 2);
+  EXPECT_TRUE(controller()->IsRevealed());
+
+  // The top-of-window views should stay revealed if the user moves the mouse
+  // around in the bottom region of the secondary display.
+  event_generator.MoveMouseTo(x + 10, y_top_edge - 3);
+  EXPECT_TRUE(controller()->IsRevealed());
+
+  // The top-of-window views should hide if the user moves the mouse away from
+  // the bottom region of the secondary display.
+  event_generator.MoveMouseTo(x, y_top_edge - 20);
+  EXPECT_FALSE(controller()->IsRevealed());
+}
+
 // Test that hovering the mouse over the find bar does not end a reveal.
 TEST_F(ImmersiveModeControllerAshTest, FindBar) {
   // Set up initial state.
@@ -333,7 +421,7 @@
 
   // Similar to the TopContainerView, clicking the mouse even slightly off of
   // the find bar ends the reveal.
-  event_generator()->ClickLeftButton();
+  GetEventGenerator().ClickLeftButton();
   EXPECT_FALSE(controller()->IsRevealed());
 
   // Set the find bar bounds to empty. Hovering over the position previously
diff --git a/chrome/browser/ui/views/message_center/web_notification_tray_win.cc b/chrome/browser/ui/views/message_center/web_notification_tray_win.cc
index 54a99f4..a6c6ab9 100644
--- a/chrome/browser/ui/views/message_center/web_notification_tray_win.cc
+++ b/chrome/browser/ui/views/message_center/web_notification_tray_win.cc
@@ -38,8 +38,6 @@
   if (win_version == base::win::VERSION_PRE_XP)
     return;
 
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-
   // StatusIconWin uses NIIF_LARGE_ICON if the version is >= vista.  According
   // to http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352.aspx:
   // This corresponds to the icon with dimensions SM_CXICON x SM_CYICON. If
diff --git a/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc b/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
index 834a9d0..99125e9 100644
--- a/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/imageburner/imageburner_ui.cc
@@ -12,7 +12,6 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/imageburner/burn_controller.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -20,6 +19,7 @@
 #include "grit/browser_resources.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/text/bytes_formatting.h"
 #include "url/gurl.h"
 
@@ -168,7 +168,7 @@
       const base::TimeDelta& time_remaining) OVERRIDE {
     const string16 time_remaining_text = l10n_util::GetStringFUTF16(
         IDS_IMAGEBURN_DOWNLOAD_TIME_REMAINING,
-        TimeFormat::TimeRemaining(time_remaining));
+        ui::TimeFormat::TimeRemaining(time_remaining));
     SendProgressSignal(progress_type, amount_finished, amount_total,
                        time_remaining_text);
   }
diff --git a/chrome/browser/ui/webui/cookies_tree_model_util.cc b/chrome/browser/ui/webui/cookies_tree_model_util.cc
index 109f0c7..bb1ac1a 100644
--- a/chrome/browser/ui/webui/cookies_tree_model_util.cc
+++ b/chrome/browser/ui/webui/cookies_tree_model_util.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/indexed_db_context.h"
 #include "grit/generated_resources.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/ssl/ssl_client_cert_type.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/bytes_formatting.h"
 #include "webkit/common/fileapi/file_system_types.h"
@@ -249,7 +250,7 @@
 
       dict->SetString(kKeyServerId, server_bound_cert.server_identifier());
       dict->SetString(kKeyCertType,
-                      ClientCertTypeToString(server_bound_cert.type()));
+                      ClientCertTypeToString(net::CLIENT_CERT_ECDSA_SIGN));
       dict->SetString(kKeyCreated, UTF16ToUTF8(
           base::TimeFormatFriendlyDateAndTime(
               server_bound_cert.creation_time())));
diff --git a/chrome/browser/ui/webui/downloads_dom_handler.cc b/chrome/browser/ui/webui/downloads_dom_handler.cc
index f107e2c..d9938b2 100644
--- a/chrome/browser/ui/webui/downloads_dom_handler.cc
+++ b/chrome/browser/ui/webui/downloads_dom_handler.cc
@@ -37,7 +37,6 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/fileicon_source.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_item.h"
@@ -48,6 +47,7 @@
 #include "content/public/browser/web_ui.h"
 #include "grit/generated_resources.h"
 #include "net/base/net_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/gfx/image/image.h"
 
 #if defined(OS_CHROMEOS)
@@ -127,7 +127,7 @@
   file_value->SetInteger(
       "started", static_cast<int>(download_item->GetStartTime().ToTimeT()));
   file_value->SetString(
-      "since_string", TimeFormat::RelativeDate(
+      "since_string", ui::TimeFormat::RelativeDate(
           download_item->GetStartTime(), NULL));
   file_value->SetString(
       "date_string", base::TimeFormatShortDate(download_item->GetStartTime()));
diff --git a/chrome/browser/ui/webui/fileicon_source.cc b/chrome/browser/ui/webui/fileicon_source.cc
index b4a9b48..ee0cb11 100644
--- a/chrome/browser/ui/webui/fileicon_source.cc
+++ b/chrome/browser/ui/webui/fileicon_source.cc
@@ -13,7 +13,6 @@
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/common/time_format.h"
 #include "grit/generated_resources.h"
 #include "net/base/escape.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index 2afeea8..7a3f570 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -40,7 +40,6 @@
 #include "chrome/browser/ui/webui/metrics_handler.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
@@ -53,6 +52,7 @@
 #include "net/base/escape.h"
 #include "sync/protocol/history_delete_directive_specifics.pb.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/base/resource/resource_bundle.h"
 
 #if defined(ENABLE_MANAGED_USERS)
@@ -192,7 +192,7 @@
 // indicator (e.g. today, yesterday).
 string16 getRelativeDateLocalized(const base::Time& visit_time) {
   base::Time midnight = base::Time::Now().LocalMidnight();
-  string16 date_str = TimeFormat::RelativeDate(visit_time, &midnight);
+  string16 date_str = ui::TimeFormat::RelativeDate(visit_time, &midnight);
   if (date_str.empty()) {
     date_str = base::TimeFormatFriendlyDate(visit_time);
   } else {
@@ -345,7 +345,7 @@
     result->SetString("snippet", snippet);
   } else {
     base::Time midnight = base::Time::Now().LocalMidnight();
-    string16 date_str = TimeFormat::RelativeDate(time, &midnight);
+    string16 date_str = ui::TimeFormat::RelativeDate(time, &midnight);
     if (date_str.empty()) {
       date_str = base::TimeFormatFriendlyDate(time);
     } else {
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index d1f550c..ad6488b 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "chrome/browser/devtools/devtools_window.h"
@@ -74,6 +75,9 @@
 static const char kInitUICommand[]  = "init-ui";
 static const char kInspectCommand[]  = "inspect";
 static const char kTerminateCommand[]  = "terminate";
+static const char kReloadCommand[]  = "reload";
+static const char kOpenCommand[]  = "open";
+
 static const char kPortForwardingEnabledCommand[] =
     "set-port-forwarding-enabled";
 static const char kPortForwardingConfigCommand[] = "set-port-forwarding-config";
@@ -89,7 +93,7 @@
 static const char kAdbSerialField[] = "adbSerial";
 static const char kAdbModelField[] = "adbModel";
 static const char kAdbBrowserNameField[] = "adbBrowserName";
-static const char kAdbPageIdField[] = "adbPageId";
+static const char kAdbGlobalIdField[] = "adbGlobalId";
 static const char kAdbBrowsersField[] = "browsers";
 static const char kAdbPagesField[] = "pages";
 
@@ -178,12 +182,16 @@
   void HandleInitUICommand(const ListValue* args);
   void HandleInspectCommand(const ListValue* args);
   void HandleTerminateCommand(const ListValue* args);
+  void HandleReloadCommand(const ListValue* args);
+  void HandleOpenCommand(const ListValue* args);
   void HandlePortForwardingEnabledCommand(const ListValue* args);
   void HandlePortForwardingConfigCommand(const ListValue* args);
 
-  bool GetProcessAndRouteId(const ListValue* args,
-                            int* process_id,
-                            int* route_id);
+  static bool GetProcessAndRouteId(const ListValue* args,
+                                   int* process_id,
+                                   int* route_id);
+
+  static bool GetRemotePageId(const ListValue* args, std::string* page_id);
 
   InspectUI* inspect_ui_;
 
@@ -206,6 +214,12 @@
   web_ui()->RegisterMessageCallback(kPortForwardingConfigCommand,
       base::Bind(&InspectMessageHandler::HandlePortForwardingConfigCommand,
                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kReloadCommand,
+      base::Bind(&InspectMessageHandler::HandleReloadCommand,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(kOpenCommand,
+      base::Bind(&InspectMessageHandler::HandleOpenCommand,
+                 base::Unretained(this)));
 }
 
 void InspectMessageHandler::HandleInitUICommand(const ListValue*) {
@@ -217,17 +231,16 @@
   if (!profile)
     return;
 
+  std::string page_id;
+  if (GetRemotePageId(args, &page_id)) {
+    inspect_ui_->InspectRemotePage(page_id);
+    return;
+  }
+
   int process_id;
   int route_id;
   if (!GetProcessAndRouteId(args, &process_id, &route_id) || process_id == 0
       || route_id == 0) {
-    // Check for ADB page id
-    const DictionaryValue* data;
-    std::string page_id;
-    if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
-        data->GetString(kAdbPageIdField, &page_id)) {
-      inspect_ui_->InspectRemotePage(page_id);
-    }
     return;
   }
 
@@ -250,6 +263,12 @@
 }
 
 void InspectMessageHandler::HandleTerminateCommand(const ListValue* args) {
+  std::string page_id;
+  if (GetRemotePageId(args, &page_id)) {
+    inspect_ui_->CloseRemotePage(page_id);
+    return;
+  }
+
   int process_id;
   int route_id;
   if (!GetProcessAndRouteId(args, &process_id, &route_id))
@@ -259,6 +278,22 @@
       base::Bind(&TerminateWorker, process_id, route_id));
 }
 
+void InspectMessageHandler::HandleReloadCommand(const ListValue* args) {
+  std::string page_id;
+  if (GetRemotePageId(args, &page_id))
+    inspect_ui_->ReloadRemotePage(page_id);
+}
+
+void InspectMessageHandler::HandleOpenCommand(const ListValue* args) {
+  std::string browser_id;
+  std::string url;
+  if (args->GetSize() == 2 &&
+      args->GetString(0, &browser_id) &&
+      args->GetString(1, &url)) {
+    inspect_ui_->OpenRemotePage(browser_id, url);
+  }
+}
+
 bool InspectMessageHandler::GetProcessAndRouteId(const ListValue* args,
                                                  int* process_id,
                                                  int* route_id) {
@@ -295,6 +330,16 @@
     profile->GetPrefs()->Set(prefs::kDevToolsPortForwardingConfig, *dict_src);
 }
 
+bool InspectMessageHandler::GetRemotePageId(const ListValue* args,
+                                            std::string* page_id) {
+  const DictionaryValue* data;
+  if (args->GetSize() == 1 && args->GetDictionary(0, &data) &&
+      data->GetString(kAdbGlobalIdField, page_id)) {
+    return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 class InspectUI::WorkerCreationDestructionListener
@@ -419,6 +464,31 @@
   }
 }
 
+void InspectUI::ReloadRemotePage(const std::string& id) {
+  RemotePages::iterator it = remote_pages_.find(id);
+  if (it != remote_pages_.end())
+    it->second->Reload();
+}
+
+void InspectUI::CloseRemotePage(const std::string& id) {
+  RemotePages::iterator it = remote_pages_.find(id);
+  if (it != remote_pages_.end())
+    it->second->Close();
+}
+
+void InspectUI::OpenRemotePage(const std::string& browser_id,
+                               const std::string& url) {
+  GURL gurl(url);
+  if (!gurl.is_valid()) {
+    gurl = GURL("http://" + url);
+    if (!gurl.is_valid())
+      return;
+  }
+  RemoteBrowsers::iterator it = remote_browsers_.find(browser_id);
+  if (it != remote_browsers_.end())
+    it->second->Open(gurl.spec());
+}
+
 void InspectUI::PopulateLists() {
   std::set<RenderViewHost*> tab_rvhs;
   for (TabContentsIterator it; !it.done(); it.Next())
@@ -504,36 +574,53 @@
 
 void InspectUI::RemoteDevicesChanged(
     DevToolsAdbBridge::RemoteDevices* devices) {
+  remote_browsers_.clear();
   remote_pages_.clear();
   ListValue device_list;
   for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
        dit != devices->end(); ++dit) {
-    DevToolsAdbBridge::RemoteDevice& device = *(dit->get());
+    DevToolsAdbBridge::RemoteDevice* device = dit->get();
     DictionaryValue* device_data = new DictionaryValue();
-    device_data->SetString(kAdbModelField, device.model());
-    device_data->SetString(kAdbSerialField, device.serial());
+    device_data->SetString(kAdbModelField, device->model());
+    device_data->SetString(kAdbSerialField, device->serial());
+    std::string device_id = base::StringPrintf(
+        "device:%s",
+        device->serial().c_str());
+    device_data->SetString(kAdbGlobalIdField, device_id);
     ListValue* browser_list = new ListValue();
     device_data->Set(kAdbBrowsersField, browser_list);
 
-    DevToolsAdbBridge::RemoteBrowsers& browsers = device.browsers();
+    DevToolsAdbBridge::RemoteBrowsers& browsers = device->browsers();
     for (DevToolsAdbBridge::RemoteBrowsers::iterator bit =
         browsers.begin(); bit != browsers.end(); ++bit) {
-      DevToolsAdbBridge::RemoteBrowser& browser = *(bit->get());
+      DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
       DictionaryValue* browser_data = new DictionaryValue();
-      browser_data->SetString(kAdbBrowserNameField, browser.name());
+      browser_data->SetString(kAdbBrowserNameField, browser->name());
+      std::string browser_id = base::StringPrintf(
+          "browser:%s:%s:%s",
+          device->serial().c_str(),
+          browser->socket().c_str(),
+          browser->name().c_str());
+      browser_data->SetString(kAdbGlobalIdField, browser_id);
+      remote_browsers_[browser_id] = browser;
       ListValue* page_list = new ListValue();
       browser_data->Set(kAdbPagesField, page_list);
 
-      DevToolsAdbBridge::RemotePages& pages = browser.pages();
+      DevToolsAdbBridge::RemotePages& pages = browser->pages();
       for (DevToolsAdbBridge::RemotePages::iterator it =
           pages.begin(); it != pages.end(); ++it) {
         DevToolsAdbBridge::RemotePage* page =  it->get();
-        DictionaryValue* page_data = BuildTargetDescriptor(kAdbTargetType,
-            false, GURL(page->url()), page->title(), GURL(page->favicon_url()),
+        DictionaryValue* page_data = BuildTargetDescriptor(
+            kAdbTargetType, page->attached(),
+            GURL(page->url()), page->title(), GURL(page->favicon_url()),
             0, 0);
-        page_data->SetString(kAdbPageIdField, page->global_id());
+        std::string page_id = base::StringPrintf("page:%s:%s:%s",
+            device->serial().c_str(),
+            browser->socket().c_str(),
+            page->id().c_str());
+        page_data->SetString(kAdbGlobalIdField, page_id);
+        remote_pages_[page_id] = page;
         page_list->Append(page_data);
-        remote_pages_[page->global_id()] = page;
       }
       browser_list->Append(browser_data);
     }
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index 8f5b4d9..9647b76 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -24,7 +24,10 @@
   virtual ~InspectUI();
 
   void InitUI();
-  void InspectRemotePage(const std::string& id);
+  void InspectRemotePage(const std::string& page_id);
+  void CloseRemotePage(const std::string& page_id);
+  void ReloadRemotePage(const std::string& page_id);
+  void OpenRemotePage(const std::string& browser_id, const std::string& url);
 
  private:
   class WorkerCreationDestructionListener;
@@ -60,6 +63,10 @@
       RemotePages;
   RemotePages remote_pages_;
 
+  typedef std::map<std::string,
+      scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
+  RemoteBrowsers remote_browsers_;
+
   DISALLOW_COPY_AND_ASSIGN(InspectUI);
 };
 
diff --git a/chrome/browser/ui/webui/ntp/foreign_session_handler.cc b/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
index 7c42a9b..daed59b 100644
--- a/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
+++ b/chrome/browser/ui/webui/ntp/foreign_session_handler.cc
@@ -25,7 +25,6 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/webui/ntp/new_tab_ui.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "components/user_prefs/pref_registry_syncable.h"
 #include "content/public/browser/notification_service.h"
@@ -36,6 +35,7 @@
 #include "content/public/browser/web_ui.h"
 #include "grit/generated_resources.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 #include "ui/webui/web_ui_util.h"
 
 namespace browser_sync {
@@ -221,7 +221,8 @@
   // Return a time like "1 hour ago", "2 days ago", etc.
   base::Time now = base::Time::Now();
   // TimeElapsed does not support negative TimeDelta values, so then we use 0.
-  return TimeFormat::TimeElapsed(now < time ? base::TimeDelta() : now - time);
+  return ui::TimeFormat::TimeElapsed(
+      now < time ? base::TimeDelta() : now - time);
 }
 
 void ForeignSessionHandler::HandleGetForeignSessions(const ListValue* args) {
@@ -401,7 +402,7 @@
   dictionary->SetString("userVisibleTimestamp",
       last_synced < base::TimeDelta::FromMinutes(1) ?
           l10n_util::GetStringUTF16(IDS_SYNC_TIME_JUST_NOW) :
-          TimeFormat::TimeElapsed(last_synced));
+          ui::TimeFormat::TimeElapsed(last_synced));
   dictionary->SetInteger("sessionId", window.window_id.id());
   dictionary->Set("tabs", tab_values.release());
   return true;
diff --git a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
index 4774a9d..c890db3 100644
--- a/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_login_handler.cc
@@ -186,7 +186,7 @@
 
 void NTPLoginHandler::HandleLoginMessageSeen(const ListValue* args) {
   Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
-      prefs::kSyncPromoShowNTPBubble, false);
+      prefs::kSignInPromoShowNTPBubble, false);
   NewTabUI* ntp_ui = NewTabUI::FromWebUIController(web_ui()->GetController());
   // When instant extended is enabled, there may not be a NewTabUI object.
   if (ntp_ui)
@@ -269,20 +269,17 @@
 void NTPLoginHandler::GetLocalizedValues(Profile* profile,
                                          DictionaryValue* values) {
   PrefService* prefs = profile->GetPrefs();
-  std::string error_message = prefs->GetString(prefs::kSyncPromoErrorMessage);
-  bool hide_sync = !prefs->GetBoolean(prefs::kSyncPromoShowNTPBubble);
+  bool hide_sync = !prefs->GetBoolean(prefs::kSignInPromoShowNTPBubble);
 
-  string16 message =
-      hide_sync ? string16() :
-          !error_message.empty() ? UTF8ToUTF16(error_message) :
-              l10n_util::GetStringFUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_MESSAGE,
-                  l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
+  string16 message = hide_sync ? string16() :
+      l10n_util::GetStringFUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_MESSAGE,
+          l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
 
   values->SetString("login_status_message", message);
   values->SetString("login_status_url",
       hide_sync ? std::string() : chrome::kSyncLearnMoreURL);
   values->SetString("login_status_advanced",
-      hide_sync || !error_message.empty() ? string16() :
+      hide_sync ? string16() :
       l10n_util::GetStringUTF16(IDS_SYNC_PROMO_NTP_BUBBLE_ADVANCED));
   values->SetString("login_status_dismiss",
       hide_sync ? string16() :
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index e2ccfe2..ef3e419 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -189,7 +189,8 @@
                                      callback);
   profile_pref_change_registrar_.Add(prefs::kShowBookmarkBar, callback);
   profile_pref_change_registrar_.Add(prefs::kNtpShownPage, callback);
-  profile_pref_change_registrar_.Add(prefs::kSyncPromoShowNTPBubble, callback);
+  profile_pref_change_registrar_.Add(prefs::kSignInPromoShowNTPBubble,
+                                     callback);
   profile_pref_change_registrar_.Add(prefs::kHideWebStoreIcon, callback);
 
   // Some tests don't have a local state.
diff --git a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
index b2fff85..7cb13218 100644
--- a/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/internet_options_handler.cc
@@ -48,7 +48,6 @@
 #include "chrome/browser/ui/host_desktop.h"
 #include "chrome/browser/ui/singleton_tabs.h"
 #include "chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h"
-#include "chrome/common/time_format.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/network/device_state.h"
 #include "chromeos/network/favorite_state.h"
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index 077ad1b..0d86576 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -45,7 +45,6 @@
 #include "chrome/browser/ui/webui/options/startup_pages_handler.h"
 #include "chrome/browser/ui/webui/sync_setup_handler.h"
 #include "chrome/browser/ui/webui/theme_source.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
diff --git a/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc b/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc
index 118452f..333ecb1 100644
--- a/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc
+++ b/chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.cc
@@ -263,7 +263,6 @@
 
       for (DictionaryValue::Iterator data(*(*event)->data()); !data.IsAtEnd();
            data.Advance()) {
-        std::string localized_key;
         Value* value = NULL;
 
         // The property 'eventType' is set in HandleGetEvents as part of the
diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc
index c1c5fc4..c514db3 100644
--- a/chrome/browser/ui/webui/policy_ui.cc
+++ b/chrome/browser/ui/webui/policy_ui.cc
@@ -33,7 +33,6 @@
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -46,6 +45,7 @@
 #include "grit/generated_resources.h"
 #include "policy/policy_constants.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/l10n/time_format.h"
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/login/user_manager.h"
@@ -153,11 +153,11 @@
   dict->SetString("clientId", client_id);
   dict->SetString("username", username);
   dict->SetString("refreshInterval",
-                  TimeFormat::TimeRemainingShort(refresh_interval));
+                  ui::TimeFormat::TimeRemainingShort(refresh_interval));
   dict->SetString("timeSinceLastRefresh", last_refresh_time.is_null() ?
       l10n_util::GetStringUTF16(IDS_POLICY_NEVER_FETCHED) :
-      TimeFormat::TimeElapsed(base::Time::NowFromSystemTime() -
-                              last_refresh_time));
+      ui::TimeFormat::TimeElapsed(base::Time::NowFromSystemTime() -
+                                  last_refresh_time));
 }
 
 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
diff --git a/chrome/browser/ui/webui/sync_promo/OWNERS b/chrome/browser/ui/webui/sync_promo/OWNERS
deleted file mode 100644
index 1a98f5f..0000000
--- a/chrome/browser/ui/webui/sync_promo/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-dbeam@chromium.org
-rogerta@chromium.org
-sail@chromium.org
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
deleted file mode 100644
index 4f8afac..0000000
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.cc
+++ /dev/null
@@ -1,135 +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/sync_promo/sync_promo_trial.h"
-
-#include "base/logging.h"
-#include "chrome/browser/metrics/metrics_service.h"
-#include "chrome/browser/signin/signin_promo.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui.h"
-
-namespace {
-
-enum {
-  UMA_START_PAGE_SHOWN = 0,
-  UMA_START_PAGE_SIGNED_IN,
-  UMA_NTP_LINK_SHOWN,
-  UMA_NTP_LINK_SIGNED_IN,
-  UMA_MENU_SHOWN,
-  UMA_MENU_SIGNED_IN,
-  UMA_SETTINGS_SHOWN,
-  UMA_SETTINGS_SIGNED_IN,
-  UMA_EXTENSION_INSTALL_BUBBLE_SHOWN,
-  UMA_EXTENSION_INSTALL_BUBBLE_SIGNED_IN,
-  UMA_UNKNOWN_SHOWN,
-  UMA_UNKNOWN_SIGNED_IN,
-  UMA_WEBSTORE_INSTALL_SHOWN,
-  UMA_WEBSTORE_INSTALL_SIGNED_IN,
-  UMA_APP_LAUNCHER_SHOWN,
-  UMA_APP_LAUNCHER_SIGNED_IN,
-  UMA_APPS_PAGE_LINK_SHOWN,
-  UMA_APPS_PAGE_LINK_SIGNED_IN,
-  UMA_BOOKMARK_BUBBLE_SHOWN,
-  UMA_BOOKMARK_BUBBLE_SIGNED_IN,
-  UMA_MAX,
-};
-
-}  // namespace
-
-namespace sync_promo_trial {
-
-void RecordUserShownPromo(content::WebUI* web_ui) {
-  signin::Source source =
-      signin::GetSourceForPromoURL(web_ui->GetWebContents()->GetURL());
-  int uma = 0;
-  switch (source) {
-    case signin::SOURCE_START_PAGE:
-      uma = UMA_START_PAGE_SHOWN;
-      break;
-    case signin::SOURCE_NTP_LINK:
-      uma = UMA_NTP_LINK_SHOWN;
-      break;
-    case signin::SOURCE_MENU:
-      uma = UMA_MENU_SHOWN;
-      break;
-    case signin::SOURCE_SETTINGS:
-      uma = UMA_SETTINGS_SHOWN;
-      break;
-    case signin::SOURCE_EXTENSION_INSTALL_BUBBLE:
-      uma = UMA_EXTENSION_INSTALL_BUBBLE_SHOWN;
-      break;
-    case signin::SOURCE_WEBSTORE_INSTALL:
-      uma = UMA_WEBSTORE_INSTALL_SHOWN;
-      break;
-    case signin::SOURCE_APP_LAUNCHER:
-      uma = UMA_APP_LAUNCHER_SHOWN;
-      break;
-    case signin::SOURCE_APPS_PAGE_LINK:
-      uma = UMA_APPS_PAGE_LINK_SHOWN;
-      break;
-    case signin::SOURCE_BOOKMARK_BUBBLE:
-      uma = UMA_BOOKMARK_BUBBLE_SHOWN;
-      break;
-    case signin::SOURCE_UNKNOWN:
-      uma = UMA_UNKNOWN_SHOWN;
-      break;
-    default:
-      // If this assert hits, then the signin::Source enum has
-      // changed and the UMA enum above, this switch statement and
-      // histograms.xml all need to be updated to reflect that.
-      COMPILE_ASSERT(signin::SOURCE_UNKNOWN == 9,
-                     kSourceEnumHasChangedButNotThisSwitchStatement);
-      NOTREACHED();
-      break;
-  }
-  UMA_HISTOGRAM_ENUMERATION("SyncPromo.ShowAndSignIn", uma, UMA_MAX);
-}
-
-void RecordUserSignedIn(content::WebUI* web_ui) {
-  signin::Source source =
-      signin::GetSourceForPromoURL(web_ui->GetWebContents()->GetURL());
-  int uma = 0;
-  switch (source) {
-    case signin::SOURCE_START_PAGE:
-      uma = UMA_START_PAGE_SIGNED_IN;
-      break;
-    case signin::SOURCE_NTP_LINK:
-      uma = UMA_NTP_LINK_SIGNED_IN;
-      break;
-    case signin::SOURCE_MENU:
-      uma = UMA_MENU_SIGNED_IN;
-      break;
-    case signin::SOURCE_SETTINGS:
-      uma = UMA_SETTINGS_SIGNED_IN;
-      break;
-    case signin::SOURCE_EXTENSION_INSTALL_BUBBLE:
-      uma = UMA_EXTENSION_INSTALL_BUBBLE_SIGNED_IN;
-      break;
-    case signin::SOURCE_WEBSTORE_INSTALL:
-      uma = UMA_WEBSTORE_INSTALL_SIGNED_IN;
-      break;
-    case signin::SOURCE_APP_LAUNCHER:
-      uma = UMA_APP_LAUNCHER_SIGNED_IN;
-      break;
-    case signin::SOURCE_APPS_PAGE_LINK:
-      uma = UMA_APPS_PAGE_LINK_SIGNED_IN;
-      break;
-    case signin::SOURCE_BOOKMARK_BUBBLE:
-      uma = UMA_BOOKMARK_BUBBLE_SIGNED_IN;
-      break;
-    case signin::SOURCE_UNKNOWN:
-      uma = UMA_UNKNOWN_SIGNED_IN;
-      break;
-    default:
-      // This switch statement needs to be updated when the enum Source changes.
-      COMPILE_ASSERT(signin::SOURCE_UNKNOWN == 9,
-                     kSourceEnumHasChangedButNotThisSwitchStatement);
-      NOTREACHED();
-      break;
-  }
-  UMA_HISTOGRAM_ENUMERATION("SyncPromo.ShowAndSignIn", uma, UMA_MAX);
-}
-
-}  // namespace sync_promo_trial
diff --git a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h b/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h
deleted file mode 100644
index de0820e..0000000
--- a/chrome/browser/ui/webui/sync_promo/sync_promo_trial.h
+++ /dev/null
@@ -1,28 +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_SYNC_PROMO_SYNC_PROMO_TRIAL_H_
-#define CHROME_BROWSER_UI_WEBUI_SYNC_PROMO_SYNC_PROMO_TRIAL_H_
-
-#include "base/basictypes.h"
-
-class Profile;
-namespace content {
-class WebUI;
-}
-
-// TODO(fdoray): This file should be moved to chrome/browser/signin.
-namespace sync_promo_trial {
-
-// Records that the user was shown the sync promo for any currently running sync
-// promo trials. |web_ui| is the web UI where the promo was shown.
-void RecordUserShownPromo(content::WebUI* web_ui);
-
-// Records that the user signed into sync for any currently running sync promo
-// trials. |web_ui| is the web UI where the user signed into sync.
-void RecordUserSignedIn(content::WebUI* web_ui);
-
-}  // namespace sync_promo_trial
-
-#endif  // CHROME_BROWSER_UI_WEBUI_SYNC_PROMO_SYNC_PROMO_TRIAL_H_
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 18493f8..f9334b1 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -192,6 +192,8 @@
             'browser/devtools/devtools_file_helper.h',
             'browser/devtools/devtools_file_system_indexer.cc',
             'browser/devtools/devtools_file_system_indexer.h',
+            'browser/devtools/devtools_protocol.cc',
+            'browser/devtools/devtools_protocol.h',
             'browser/devtools/devtools_toggle_action.h',
             'browser/devtools/devtools_window.cc',
             'browser/devtools/devtools_window.h',
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 01d77ee..dc86b55 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -985,6 +985,8 @@
         'browser/media/webrtc_log_uploader.h',
         'browser/media/webrtc_logging_handler_host.cc',
         'browser/media/webrtc_logging_handler_host.h',
+        'browser/media_galleries/fileapi/av_scanning_file_validator.cc',
+        'browser/media_galleries/fileapi/av_scanning_file_validator.h',
         'browser/media_galleries/fileapi/itunes_finder.cc',
         'browser/media_galleries/fileapi/itunes_finder.h',
         'browser/media_galleries/fileapi/itunes_finder_mac.h',
@@ -2178,6 +2180,8 @@
         'browser/sync_file_system/drive_backend/remote_sync_delegate.h',
         'browser/sync_file_system/drive_backend/remote_sync_operation_resolver.cc',
         'browser/sync_file_system/drive_backend/remote_sync_operation_resolver.h',
+        'browser/sync_file_system/drive_backend/tracker_set.cc',
+        'browser/sync_file_system/drive_backend/tracker_set.h',
         'browser/sync_file_system/file_change.cc',
         'browser/sync_file_system/file_change.h',
         'browser/sync_file_system/file_status_observer.h',
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 79881ee..6f7425d 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -282,6 +282,14 @@
         'browser/extensions/api/location/location_api.h',
         'browser/extensions/api/location/location_manager.cc',
         'browser/extensions/api/location/location_manager.h',
+        'browser/extensions/api/log_private/filter_handler.cc',
+        'browser/extensions/api/log_private/filter_handler.h',
+        'browser/extensions/api/log_private/log_parser.cc',
+        'browser/extensions/api/log_private/log_parser.h',
+        'browser/extensions/api/log_private/log_private_api.h',
+        'browser/extensions/api/log_private/log_private_api_nonchromeos.cc',
+        'browser/extensions/api/log_private/syslog_parser.cc',
+        'browser/extensions/api/log_private/syslog_parser.h',
         'browser/extensions/api/management/management_api.cc',
         'browser/extensions/api/management/management_api.h',
         'browser/extensions/api/management/management_api_constants.cc',
@@ -723,8 +731,6 @@
         'browser/extensions/pending_extension_manager.h',
         'browser/extensions/permissions_updater.cc',
         'browser/extensions/permissions_updater.h',
-        'browser/extensions/platform_app_launcher.cc',
-        'browser/extensions/platform_app_launcher.h',
         'browser/extensions/plugin_manager.cc',
         'browser/extensions/plugin_manager.h',
         'browser/extensions/process_map.cc',
@@ -751,6 +757,7 @@
         'browser/extensions/suggest_permission_util.cc',
         'browser/extensions/api/system_info/system_info_api.cc',
         'browser/extensions/api/system_info/system_info_api.h',
+        'browser/extensions/api/system_info/system_info_provider.cc',
         'browser/extensions/api/system_info/system_info_provider.h',
         'browser/extensions/api/system_private/system_private_api.cc',
         'browser/extensions/api/system_private/system_private_api.h',
@@ -806,8 +813,9 @@
           ],
           'sources!': [
             'browser/extensions/api/audio/audio_service.cc',
-            'browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc',
             'browser/extensions/api/diagnostics/diagnostics_api_nonchromeos.cc',
+            'browser/extensions/api/feedback_private/feedback_service_nonchromeos.cc',
+            'browser/extensions/api/log_private/log_private_api_nonchromeos.cc',
             'browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc',
             'browser/extensions/default_apps.cc',
             'browser/extensions/default_apps.h',
@@ -817,6 +825,7 @@
             'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h',
             'browser/extensions/api/input_ime/input_ime_api.cc',
             'browser/extensions/api/input_ime/input_ime_api.h',
+            'browser/extensions/api/log_private/log_private_api_chromeos.cc',
             'browser/extensions/api/rtc_private/rtc_private_api.cc',
             'browser/extensions/api/rtc_private/rtc_private_api.h',
             'browser/extensions/api/terminal/terminal_extension_helper.cc',
@@ -989,8 +998,6 @@
             'browser/extensions/extension_error_ui_default.cc',
             'browser/extensions/extension_error_ui_default.h',
             'browser/extensions/extension_tab_util.cc',
-            'browser/extensions/platform_app_launcher.cc',
-            'browser/extensions/platform_app_launcher.h',
           ],
         }],
         ['chrome_multiple_dll!=1', {
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index c9b6885..ea97dd7 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2355,8 +2355,6 @@
         'browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h',
         'browser/ui/webui/sync_internals_ui.cc',
         'browser/ui/webui/sync_internals_ui.h',
-        'browser/ui/webui/sync_promo/sync_promo_trial.cc',
-        'browser/ui/webui/sync_promo/sync_promo_trial.h',
         'browser/ui/webui/sync_setup_handler.cc',
         'browser/ui/webui/sync_setup_handler.h',
         'browser/ui/webui/task_manager/task_manager_dialog.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index d510065..bf7f2ae 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -455,8 +455,6 @@
         'common/switch_utils.h',
         'common/thumbnail_score.cc',
         'common/thumbnail_score.h',
-        'common/time_format.cc',
-        'common/time_format.h',
         'common/translate/language_detection_details.cc',
         'common/translate/language_detection_details.h',
         'common/translate/language_detection_util.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 5de1502..79f7a73 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -30,6 +30,7 @@
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/zlib/zlib.gyp:zlib',
+        '../ui/message_center/message_center.gyp:message_center_test_support',
       ],
       'export_dependent_settings': [
         'app/policy/cloud_policy_codegen.gyp:policy_test_support',
@@ -645,6 +646,7 @@
         'browser/chromeos/drive/webkit_file_stream_reader_impl_unittest.cc',
         'browser/chromeos/extensions/default_app_order_unittest.cc',
         'browser/chromeos/extensions/file_manager/desktop_notifications_unittest.cc',
+        'browser/chromeos/extensions/file_manager/file_watcher_unittest.cc',
         'browser/chromeos/extensions/wallpaper_private_api_unittest.cc',
         'browser/chromeos/external_metrics_unittest.cc',
         'browser/chromeos/fileapi/file_access_permissions_unittest.cc',
@@ -791,6 +793,7 @@
         'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc',
         'browser/extensions/api/identity/identity_mint_queue_unittest.cc',
         'browser/extensions/api/idle/idle_api_unittest.cc',
+        'browser/extensions/api/log_private/syslog_parser_unittest.cc',
         'browser/extensions/api/messaging/native_message_process_host_unittest.cc',
         'browser/extensions/api/messaging/native_messaging_host_manifest_unittest.cc',
         'browser/extensions/api/omnibox/omnibox_unittest.cc',
@@ -997,6 +1000,7 @@
         'browser/net/url_info_unittest.cc',
         'browser/notifications/desktop_notification_service_unittest.cc',
         'browser/notifications/message_center_notifications_unittest_win.cc',
+        'browser/notifications/message_center_settings_controller_unittest.cc',
         'browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc',
         'browser/notifications/sync_notifier/synced_notification_unittest.cc',
         'browser/notifications/sync_notifier/sync_notifier_test_utils.cc',
@@ -1762,7 +1766,6 @@
         'common/service_process_util_unittest.cc',
         'common/switch_utils_unittest.cc',
         'common/thumbnail_score_unittest.cc',
-        'common/time_format_unittest.cc',
         'common/translate/language_detection_util_unittest.cc',
         'common/translate/translate_common_metrics_unittest.cc',
         'common/translate/translate_util_unittest.cc',
@@ -2209,6 +2212,7 @@
           'sources!': [
             'browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc',
             'browser/net/gaia/gaia_oauth_fetcher_unittest.cc',
+            'browser/extensions/api/log_private/syslog_parser_unittest.cc',
           ],
         }],
         ['use_x11==1', {
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index d3d5d24..8119470 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1491,10 +1491,6 @@
 
 // Uses the tablet specific UI components when available.
 const char kTabletUI[]                      = "tablet-ui";
-
-// Enables support for playing videos on Google Cast devices.
-const char kEnableCast[]                    = "enable-cast";
-
 #endif
 
 #if defined(USE_ASH)
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 3b73862..3272ce5 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -408,7 +408,6 @@
 extern const char kEnableTranslate[];
 extern const char kFakeCloudPolicyType[];
 extern const char kTabletUI[];
-extern const char kEnableCast[];
 #endif
 
 #if defined(USE_ASH)
diff --git a/chrome/common/extensions/OWNERS b/chrome/common/extensions/OWNERS
index a32e240..c80762a 100644
--- a/chrome/common/extensions/OWNERS
+++ b/chrome/common/extensions/OWNERS
@@ -5,6 +5,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 2780ca1..d9075d7 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -308,6 +308,11 @@
     "dependencies": ["permission:location"],
     "contexts": ["blessed_extension"]
   },
+  "logPrivate": {
+    "dependencies": ["permission:logPrivate"],
+    "extension_types": ["extension", "packaged_app"],
+    "contexts": ["blessed_extension"]
+  },
   "management": {
     "dependencies": ["permission:management"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 464645c..1c761cc 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -334,6 +334,11 @@
       "location": "component"
     }
   ],
+  "logPrivate": {
+    "channel": "dev",
+    "extension_types": ["extension", "packaged_app"],
+    "location": "component"
+  },
   "management": [
     {
       "channel": "stable",
diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp
index f079337..465021a 100644
--- a/chrome/common/extensions/api/api.gyp
+++ b/chrome/common/extensions/api/api.gyp
@@ -66,6 +66,7 @@
           'idle.json',
           'infobars.json',
           'input_ime.json',
+          'log_private.idl',
           'management.json',
           'manifest_types.json',
           'media_galleries.idl',
@@ -123,6 +124,7 @@
         ['OS!="chromeos"', {
           'schema_files!': [
             'file_browser_handler_internal.json',
+            'log_private.idl',
             'rtc_private.idl',
           ],
         }],
diff --git a/chrome/common/extensions/api/audio.idl b/chrome/common/extensions/api/audio.idl
index 15efd77..ebf6585 100644
--- a/chrome/common/extensions/api/audio.idl
+++ b/chrome/common/extensions/api/audio.idl
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Use the <code>chrome.audio</code> API to query audio device configuration and
-// be notified when it changes.
+// The <code>chrome.audio</code> API is provided to allow users to
+// get information about and control the audio devices attached to the
+// system. This API is currently only implemented for ChromeOS.
 namespace audio {
 
   dictionary OutputDeviceInfo {
diff --git a/chrome/common/extensions/api/file_browser_private.json b/chrome/common/extensions/api/file_browser_private.json
index 7447974..98fb729 100644
--- a/chrome/common/extensions/api/file_browser_private.json
+++ b/chrome/common/extensions/api/file_browser_private.json
@@ -331,14 +331,14 @@
             "description": "Defines file transfer direction."
           },
           "processed": {
-            "type": "integer",
+            "type": "number",
             "optional": true,
-            "description": "Completed portion of the transfer operation."
+            "description": "Approximated completed portion of the transfer operation."
           },
           "total": {
-            "type": "integer",
+            "type": "number",
             "optional": true,
-            "description": "Total size (cost) of transfer operation."
+            "description": "Approximated total size of transfer operation."
           }
         }
       },
@@ -646,11 +646,6 @@
             "items": {"type": "string"}
           },
           {
-            "name": "id",
-            "type": "string",
-            "description": "File browser handler id as for internal tasks."
-          },
-          {
             "name": "callback",
             "type": "function",
             "parameters": [
diff --git a/chrome/common/extensions/api/log_private.idl b/chrome/common/extensions/api/log_private.idl
new file mode 100644
index 0000000..2194357
--- /dev/null
+++ b/chrome/common/extensions/api/log_private.idl
@@ -0,0 +1,52 @@
+// 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.
+
+// Use chrome.logPrivate API to retrieve log information from multiple
+// resources in a consistent format.
+namespace logPrivate {
+
+  // A filter class that filters log entries by different fields
+  dictionary Filter {
+    // Only logs from |sources| will be returned.
+    DOMString[] sources;
+    // Only logs created in [|start_timestamp|, |end_timestamp|] will
+    // be returned.
+    double start_timestamp;
+    double end_timestamp;
+    // Only logs have process name in |process| will be returned.
+    DOMString[] process;
+    //  Only logs have level in |level| will be returned.
+    DOMString[] level;
+  };
+
+  // The class that contains log information.
+  dictionary LogEntry {
+    // The time of the log in milliseconds.
+    double timestamp;
+    // The raw text of log.
+    DOMString full_entry;
+    // The name of the process that the log associated with.
+    DOMString process;
+    // The ID of the process that the log associated with.
+    DOMString process_id;
+    // The log level.
+    DOMString level;
+  };
+
+  // The class that is returned to callback function.
+  dictionary Result {
+    // The filter specified to filter log result.
+    Filter filter;
+    // Log entries returned based on the filter.
+    LogEntry[] data;
+  };
+
+  callback GetHistoricalCallback = void (Result res);
+
+  interface Functions {
+    // Get the existing logs from ChromeOS system.
+    static void getHistorical(Filter filter, GetHistoricalCallback callback);
+  };
+
+};
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json b/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json
index affbc47..4745d3b 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json
@@ -3,11 +3,7 @@
   "description": "Select links on a page and download them.",
   "version": "0.1",
   "minimum_chrome_version": "16.0.884",
-  "permissions": [
-    "experimental", "tabs", "http://*/*", "https://*/*"
-  ],
-  "browser_action": {
-    "default_popup": "popup.html"
-  },
+  "permissions": ["tabs", "downloads"],
+  "browser_action": {"default_popup": "popup.html"},
   "manifest_version": 2
 }
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json b/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
index cc1b636..3f59ae2 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
@@ -28,6 +28,12 @@
  "zeroSearchResults": {
    "message": "Zero matches",
    "description": ""},
+ "managementPermissionInfo": {
+   "message": "Some files were downloaded by an extension.",
+   "description": ""},
+ "grantManagementPermission": {
+   "message": "Show links to extensions that download files.",
+   "description": ""},
  "showOlderDownloads": {
    "message": "Show Older Downloads",
    "description": ""},
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
index 1141c0d..6ae38ad 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
@@ -11,4 +11,5 @@
    "default_popup": "popup.html"},
  "background": {"persistent": false, "scripts": ["background.js"]},
  "default_locale": "en",
- "permissions": ["management", "downloads", "downloads.open", "downloads.shelf"]}
+ "optional_permissions": ["management"],
+ "permissions": ["downloads", "downloads.open", "downloads.shelf"]}
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
index 46b0800..967d512 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.css
@@ -2,10 +2,6 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
-body {
-  text-align: center;
-}
-
 #outer,
 #empty,
 #open-folder,
@@ -15,6 +11,16 @@
   display: inline-block;
 }
 
+#q-outer {
+  display:inline-block;
+  height:1.7em;
+  overflow:hidden;
+}
+
+#q {
+  margin-right: 2em;
+}
+
 #head {
   position: fixed;
   width: 100%;
@@ -58,15 +64,9 @@
 }
 
 #q {
-  margin-top: 0.5em;
   margin-left: 3%;
 }
 
-#clear-all,
-#open-folder {
-  float: right;
-}
-
 .by-ext img,
 svg {
   width: 2em;
@@ -96,11 +96,6 @@
   stroke: black;
 }
 
-.clearfix {
-  clear: both;
-  float: right;
-}
-
 #older,
 #loading-older,
 .item {
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.html b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.html
index b1cc635..95933be 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.html
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.html
@@ -12,7 +12,9 @@
     <a id="bad-chrome-version" hidden
         href="https://www.google.com/intl/en/chrome/browser/beta.html"></a>
     <span id="empty" hidden></span>
-    <input type="search" id="q" incremental>
+    <div id="q-outer">
+      <input type="search" id="q" incremental><br>&nbsp;
+    </div>
     <a href="#" id="clear-all"><svg viewBox="0 0 100 100"><g>
       <rect x="5" y="5" rx="20" ry="20" width="90" height="90" class="border" />
       <ellipse rx="30" ry="8" cx="50" cy="55" />
@@ -30,13 +32,16 @@
       <polygon points="20,20 20,80 60,80 60,30 35,30 35,20" />
       <polygon points="20,80 60,80 80,45 40,45" />
       </g></svg></a>
-    <div class="clearfix"> </div>
   </div>
   <div id="searching" hidden></div>
   <div id="search-zero" hidden></div>
   <div id="items"></div>
   <a href="#" id="older" hidden></a>
   <span id="loading-older" hidden></span>
+  <div id="request-management-permission" hidden><div
+      id="management-permission-info"></div>
+    <a href="#" id="grant-management-permission"></a>
+  </div>
 </div>
 
 <div class="item" hidden>
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
index e878fc7..6c88e3d 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/popup.js
@@ -26,6 +26,10 @@
   setProperty('#empty', 'innerText', 'zeroItems');
   setProperty('#searching', 'innerText', 'searching');
   setProperty('#search-zero', 'innerText', 'zeroSearchResults');
+  setProperty('#management-permission-info', 'innerText',
+              'managementPermissionInfo');
+  setProperty('#grant-management-permission', 'innerText',
+              'grantManagementPermission');
   setProperty('#older', 'innerText', 'showOlderDownloads');
   setProperty('#loading-older', 'innerText', 'loadingOlderDownloads');
   setProperty('.pause', 'title', 'pauseTitle');
@@ -296,9 +300,9 @@
     });
   }
 
-  item.getElement('removed').style.display = openable ? 'none' : 'inline-block';
+  item.getElement('removed').style.display = openable ? 'none' : 'inline';
   item.getElement('open-filename').style.display = (
-    openable ? 'inline-block' : 'none');
+    openable ? 'inline' : 'none');
   item.getElement('in-progress').hidden = !in_progress;
   item.getElement('pause').style.display = (
     !in_progress || item.paused) ? 'none' : 'inline-block';
@@ -321,14 +325,43 @@
   item.getElement('removed').innerText = item.basename;
   item.getElement('open-filename').innerText = item.basename;
 
+  function setByExtension(show) {
+    if (show) {
+      item.getElement('by-ext').title = item.byExtensionName;
+      item.getElement('by-ext').href =
+        'chrome://extensions#' + item.byExtensionId;
+      item.getElement('by-ext img').src =
+        'chrome://extension-icon/' + item.byExtensionId + '/48/1';
+    } else {
+      item.getElement('by-ext').hidden = true;
+    }
+  }
   if (item.byExtensionId && item.byExtensionName) {
-    item.getElement('by-ext').title = item.byExtensionName;
-    item.getElement('by-ext').href =
-      'chrome://extensions#' + item.byExtensionId;
-    item.getElement('by-ext img').src =
-      'chrome://extension-icon/' + item.byExtensionId + '/48/1';
+    chrome.permissions.contains({permissions: ['management']},
+                                function(result) {
+      if (result) {
+        setByExtension(true);
+      } else {
+        setByExtension(false);
+        if (!localStorage.managementPermissionDenied) {
+          document.getElementById('request-management-permission').hidden =
+            false;
+          document.getElementById('grant-management-permission').onclick =
+              function() {
+            chrome.permissions.request({permissions: ['management']},
+                                      function(granted) {
+              setByExtension(granted);
+              if (!granted) {
+                localStorage.managementPermissionDenied = true;
+              }
+            });
+            return false;
+          };
+        }
+      }
+    });
   } else {
-    item.getElement('by-ext').hidden = true;
+    setByExtension(false);
   }
 
   if (!item.getElement('error').hidden) {
@@ -509,9 +542,9 @@
   var any_items = (document.getElementById('items').childNodes.length > 0);
   document.getElementById('empty').style.display =
     any_items ? 'none' : 'inline-block';
+  document.getElementById('head').style.borderBottomWidth =
+    (any_items ? 1 : 0) + 'px';
   document.getElementById('clear-all').hidden = !any_items;
-  document.getElementById('open-folder').style.float =
-    any_items ? 'right' : 'none';
 
   var query_search = document.getElementById('q');
   query_search.hidden = !any_items;
@@ -682,7 +715,7 @@
 
   window.onload = function() {
     document.body.style.minWidth = (
-      document.getElementById('q').offsetWidth +
+      document.getElementById('q-outer').offsetWidth +
       document.getElementById('clear-all').offsetWidth +
       document.getElementById('open-folder').offsetWidth) + 'px';
     setLastOpened();
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json b/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json
index 5a6df11..eae1fbe 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json
@@ -1,5 +1,5 @@
 {"extName": {
-   "message": "Download and Open Context Menu Button",
+   "message": "Download and Open Button",
    "description": "Extension name"},
  "extDesc": {
    "message": "Download and Open Context Menu Button",
diff --git a/chrome/common/extensions/docs/server2/api_data_source.py b/chrome/common/extensions/docs/server2/api_data_source.py
index 0301e30..a73a971 100644
--- a/chrome/common/extensions/docs/server2/api_data_source.py
+++ b/chrome/common/extensions/docs/server2/api_data_source.py
@@ -316,7 +316,7 @@
     }
     if (function.parent is not None and
         not isinstance(function.parent, model.Namespace)):
-      function_dict['parent_name'] = function.parent.simple_name
+      function_dict['parentName'] = function.parent.simple_name
     if function.returns:
       function_dict['returns'] = self._GenerateType(function.returns)
     for param in function.params:
@@ -347,7 +347,7 @@
     }
     if (event.parent is not None and
         not isinstance(event.parent, model.Namespace)):
-      event_dict['parent_name'] = event.parent.simple_name
+      event_dict['parentName'] = event.parent.simple_name
     if event.callback is not None:
       # Show the callback as an extra parameter.
       event_dict['parameters'].append(
@@ -408,7 +408,7 @@
 
     if (property_.parent is not None and
         not isinstance(property_.parent, model.Namespace)):
-      property_dict['parent_name'] = property_.parent.simple_name
+      property_dict['parentName'] = property_.parent.simple_name
 
     value = property_.value
     if value is not None:
@@ -431,7 +431,7 @@
     }
     if (callback.parent is not None and
         not isinstance(callback.parent, model.Namespace)):
-      property_dict['parent_name'] = callback.parent.simple_name
+      property_dict['parentName'] = callback.parent.simple_name
     return property_dict
 
   def _RenderTypeInformation(self, type_, dst_dict):
diff --git a/chrome/common/extensions/docs/server2/app.yaml b/chrome/common/extensions/docs/server2/app.yaml
index d0489f2..9c33888 100644
--- a/chrome/common/extensions/docs/server2/app.yaml
+++ b/chrome/common/extensions/docs/server2/app.yaml
@@ -1,5 +1,5 @@
 application: chrome-apps-doc
-version: 2-17-0
+version: 2-18-0
 runtime: python27
 api_version: 1
 threadsafe: false
diff --git a/chrome/common/extensions/docs/server2/cron.yaml b/chrome/common/extensions/docs/server2/cron.yaml
index 9f4691b..902bb80 100644
--- a/chrome/common/extensions/docs/server2/cron.yaml
+++ b/chrome/common/extensions/docs/server2/cron.yaml
@@ -2,4 +2,4 @@
 - description: Repopulates all cached data.
   url: /_cron
   schedule: every 5 minutes
-  target: 2-17-0
+  target: 2-18-0
diff --git a/chrome/common/extensions/docs/server2/fail_on_access_file_system.py b/chrome/common/extensions/docs/server2/fail_on_access_file_system.py
new file mode 100644
index 0000000..866cfd3
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/fail_on_access_file_system.py
@@ -0,0 +1,12 @@
+# 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 file_system import FileSystem
+
+class FailOnAccessFileSystem(FileSystem):
+  # All this needs to do is implement GetIdentity. All other methods will
+  # automatically fail with NotImplementedErrors.
+  def GetIdentity(self):
+    return '42'
+
diff --git a/chrome/common/extensions/docs/server2/handler.py b/chrome/common/extensions/docs/server2/handler.py
index 8701b75..8e5cae8 100644
--- a/chrome/common/extensions/docs/server2/handler.py
+++ b/chrome/common/extensions/docs/server2/handler.py
@@ -6,11 +6,13 @@
 from instance_servlet import InstanceServlet
 from patch_servlet import PatchServlet
 from servlet import Servlet, Request, Response
+from test_servlet import TestServlet
 
 _DEFAULT_SERVLET = InstanceServlet.GetConstructor()
 _SERVLETS = {
   'cron': CronServlet,
   'patch': PatchServlet,
+  'test': TestServlet,
 }
 
 class Handler(Servlet):
diff --git a/chrome/common/extensions/docs/server2/instance_servlet.py b/chrome/common/extensions/docs/server2/instance_servlet.py
index 0382ce4..47a9be4 100644
--- a/chrome/common/extensions/docs/server2/instance_servlet.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet.py
@@ -13,7 +13,7 @@
 from object_store_creator import ObjectStoreCreator
 from server_instance import ServerInstance
 
-class _OfflineRenderServletDelegate(RenderServlet.Delegate):
+class OfflineRenderServletDelegate(RenderServlet.Delegate):
   '''AppEngine instances should never need to call out to SVN. That should only
   ever be done by the cronjobs, which then write the result into DataStore,
   which is as far as instances look. To enable this, crons can pass a custom
@@ -73,7 +73,7 @@
 
   @staticmethod
   def GetConstructor(delegate_for_test=None):
-    render_servlet_delegate = _OfflineRenderServletDelegate(
+    render_servlet_delegate = OfflineRenderServletDelegate(
         delegate_for_test or InstanceServlet.Delegate())
     return lambda request: RenderServlet(request, render_servlet_delegate)
 
diff --git a/chrome/common/extensions/docs/server2/instance_servlet_test.py b/chrome/common/extensions/docs/server2/instance_servlet_test.py
index 8d9abc3..3a2b999 100755
--- a/chrome/common/extensions/docs/server2/instance_servlet_test.py
+++ b/chrome/common/extensions/docs/server2/instance_servlet_test.py
@@ -6,9 +6,9 @@
 import unittest
 
 from empty_dir_file_system import EmptyDirFileSystem
-from file_system import FileSystem
 from instance_servlet import InstanceServlet
 from servlet import Request
+from fail_on_access_file_system import FailOnAccessFileSystem
 from test_branch_utility import TestBranchUtility
 from test_util import DisableLogging
 
@@ -27,16 +27,10 @@
   def CreateAppSamplesFileSystem(self, object_store_creator):
     return EmptyDirFileSystem()
 
-class _FailOnAccessFileSystem(FileSystem):
-  # All this needs to do is implement GetIdentity. All other methods will
-  # automatically fail with NotImplementedErrors.
-  def GetIdentity(self):
-    return '42'
-
 class InstanceServletTest(unittest.TestCase):
   @DisableLogging('warning')
   def testHostFileSystemNotAccessed(self):
-    delegate = _TestDelegate(_FailOnAccessFileSystem)
+    delegate = _TestDelegate(FailOnAccessFileSystem)
     constructor = InstanceServlet.GetConstructor(delegate_for_test=delegate)
     def test_path(path, status=404):
       response = constructor(Request.ForTest(path)).Get()
diff --git a/chrome/common/extensions/docs/server2/integration_test.py b/chrome/common/extensions/docs/server2/integration_test.py
index fa2d1322..6d0e99b 100755
--- a/chrome/common/extensions/docs/server2/integration_test.py
+++ b/chrome/common/extensions/docs/server2/integration_test.py
@@ -8,8 +8,6 @@
 import build_server
 build_server.main()
 
-from itertools import groupby
-from operator import itemgetter
 import optparse
 import os
 import posixpath
@@ -18,7 +16,7 @@
 import unittest
 
 from branch_utility import BranchUtility
-from link_error_detector import LinkErrorDetector
+from link_error_detector import LinkErrorDetector, StringifyBrokenLinks
 from local_file_system import LocalFileSystem
 from local_renderer import LocalRenderer
 from fake_fetchers import ConfigureFakeFetchers
@@ -45,35 +43,6 @@
         public_files['/'.join((relative_posix_path, filename))] = f.read()
   return public_files
 
-def _PrintBrokenLinks(broken_links):
-  '''Prints out broken links in a more readable format.
-  '''
-  def fixed_width(string, width):
-    return "%s%s" % (string, (width - len(string)) * ' ')
-
-  first_col_width = max(len(link[1]) for link in broken_links)
-  second_col_width = max(len(link[2]) for link in broken_links)
-  target = itemgetter(2)
-
-  def pretty_print(link, col_offset=0):
-    return "%s -> %s %s" % (
-        fixed_width(link[1], first_col_width - col_offset),
-        fixed_width(link[2], second_col_width),
-        link[3])
-
-  for target, links in groupby(sorted(broken_links, key=target), target):
-    links = list(links)
-    # Compress messages
-    if len(links) > 50 and not links[0][2].startswith('#'):
-      message = "Found %d broken links (" % len(links)
-      print("%s%s)" % (message, pretty_print(links[0], len(message))))
-        # link = links[0]
-        # out = "%s and %d others" % (link[1], len(links) - 1)
-      # pretty_print(link, url=out)
-    else:
-      for link in links:
-        print(pretty_print(link))
-
 class IntegrationTest(unittest.TestCase):
   def setUp(self):
     ConfigureFakeFetchers()
@@ -108,7 +77,7 @@
       # TODO(jshumway): Test should fail when broken links are detected.
       print('Warning: Found %d broken links:' % (
         len(broken_links)))
-      _PrintBrokenLinks(broken_links)
+      print(StringifyBrokenLinks(broken_links))
 
     print('Took %s seconds.' % (time.time() - start_time))
 
diff --git a/chrome/common/extensions/docs/server2/link_error_detector.py b/chrome/common/extensions/docs/server2/link_error_detector.py
index 7e4c137..528c810 100644
--- a/chrome/common/extensions/docs/server2/link_error_detector.py
+++ b/chrome/common/extensions/docs/server2/link_error_detector.py
@@ -4,6 +4,8 @@
 
 from collections import defaultdict, deque, namedtuple
 from HTMLParser import HTMLParser, HTMLParseError
+from itertools import groupby
+from operator import itemgetter
 import posixpath
 from urlparse import urlsplit
 
@@ -263,3 +265,32 @@
         [url for url, page in self._pages.iteritems() if page.status == 200])
 
     return [url for url in all_urls - found if url.endswith('.html')]
+
+def StringifyBrokenLinks(broken_links):
+  '''Prints out broken links in a more readable format.
+  '''
+  def fixed_width(string, width):
+    return "%s%s" % (string, (width - len(string)) * ' ')
+
+  first_col_width = max(len(link[1]) for link in broken_links)
+  second_col_width = max(len(link[2]) for link in broken_links)
+  target = itemgetter(2)
+  output = []
+
+  def pretty_print(link, col_offset=0):
+    return "%s -> %s %s" % (
+        fixed_width(link[1], first_col_width - col_offset),
+        fixed_width(link[2], second_col_width),
+        link[3])
+
+  for target, links in groupby(sorted(broken_links, key=target), target):
+    links = list(links)
+    # Compress messages
+    if len(links) > 50 and not links[0][2].startswith('#'):
+      message = "Found %d broken links (" % len(links)
+      output.append("%s%s)" % (message, pretty_print(links[0], len(message))))
+    else:
+      for link in links:
+        output.append(pretty_print(link))
+
+  return '\n'.join(output)
diff --git a/chrome/common/extensions/docs/server2/test_servlet.py b/chrome/common/extensions/docs/server2/test_servlet.py
new file mode 100644
index 0000000..81f12aa
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_servlet.py
@@ -0,0 +1,69 @@
+# 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 instance_servlet import InstanceServlet, OfflineRenderServletDelegate
+from link_error_detector import LinkErrorDetector, StringifyBrokenLinks
+from servlet import Request, Response, Servlet
+import svn_constants
+
+class BrokenLinkTester(object):
+  '''Run link error detector tests.
+  '''
+  def __init__(self, server_instance, renderer):
+    self.link_error_detector = LinkErrorDetector(
+      server_instance.host_file_system,
+      renderer,
+      svn_constants.PUBLIC_TEMPLATE_PATH,
+      root_pages=('extensions/index.html', 'apps/about_apps.html'))
+
+  def TestBrokenLinks(self):
+    broken_links = self.link_error_detector.GetBrokenLinks()
+    return (
+        len(broken_links),
+        'Warning: Found %d broken links:\n%s' % (
+            len(broken_links), StringifyBrokenLinks(broken_links)))
+
+  def TestOrphanedPages(self):
+    orphaned_pages = self.link_error_detector.GetOrphanedPages()
+    return (
+        len(orphaned_pages),
+        'Warning: Found %d orphaned pages:\n%s' % (
+            len(orphaned_pages), '\n'.join(orphaned_pages)))
+
+class TestServlet(Servlet):
+  '''Runs tests against the live server. Supports running all broken link
+  detection tests, in parts or all at once.
+  '''
+  def __init__(self, request, delegate_for_test=None):
+    Servlet.__init__(self, request)
+    self._delegate = delegate_for_test or InstanceServlet.Delegate()
+
+  def Get(self):
+    link_error_tests = ('broken_links', 'orphaned_pages', 'link_errors')
+
+    if not self._request.path in link_error_tests:
+      return Response.NotFound('Test %s not found. Available tests are: %s' % (
+          self._request.path, ','.join(link_error_tests)))
+
+    constructor = InstanceServlet.GetConstructor(self._delegate)
+    def renderer(path):
+      return constructor(Request(path, '', self._request.headers)).Get()
+
+    link_tester = BrokenLinkTester(
+        OfflineRenderServletDelegate(self._delegate).CreateServerInstance(),
+        renderer)
+    if self._request.path == 'broken_links':
+      errors, content = link_tester.TestBrokenLinks()
+    elif self._request.path == 'orphaned_pages':
+      errors, content = link_tester.TestOrphanedPages()
+    else:
+      link_errors, link_content = link_tester.TestBrokenLinks()
+      orphaned_errors, orphaned_content = link_tester.TestOrphanedPages()
+      errors = link_errors + orphaned_errors
+      content = "%s\n%s" % (link_content, orphaned_content)
+
+    if errors:
+      return Response.InternalError(content=content)
+
+    return Response.Ok(content="%s test passed." % self._request.path)
diff --git a/chrome/common/extensions/docs/server2/test_servlet_test.py b/chrome/common/extensions/docs/server2/test_servlet_test.py
new file mode 100755
index 0000000..0e53afb
--- /dev/null
+++ b/chrome/common/extensions/docs/server2/test_servlet_test.py
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+# 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 unittest
+
+from empty_dir_file_system import EmptyDirFileSystem
+from host_file_system_creator import HostFileSystemCreator
+from servlet import Request
+from test_branch_utility import TestBranchUtility
+from fail_on_access_file_system import FailOnAccessFileSystem
+from test_servlet import TestServlet
+
+class _TestDelegate(object):
+  def CreateBranchUtility(self, object_store_creator):
+    return TestBranchUtility.CreateWithCannedData()
+
+  def CreateAppSamplesFileSystem(self, object_store_creator):
+    return EmptyDirFileSystem()
+
+  def CreateHostFileSystemCreator(self, object_store_creator):
+    return HostFileSystemCreator.ForTest(
+        FailOnAccessFileSystem(), object_store_creator)
+
+# This test can't really be useful. The set of valid tests is changing and
+# there is no reason to test the tests themselves, they are already tested in
+# their respective modules. The only testable behavior TestServlet adds is
+# returning a 404 if a test does not exist.
+class TestServletTest(unittest.TestCase):
+  def testTestServlet(self):
+    request = Request('not_a_real_test_url', 'localhost', {})
+    test_servlet = TestServlet(request, _TestDelegate())
+    response = test_servlet.Get()
+
+    self.assertEqual(404, response.status)
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/chrome/common/extensions/docs/templates/intros/downloads.html b/chrome/common/extensions/docs/templates/intros/downloads.html
index 559c039..84582dd 100644
--- a/chrome/common/extensions/docs/templates/intros/downloads.html
+++ b/chrome/common/extensions/docs/templates/intros/downloads.html
@@ -1,25 +1,15 @@
 <h2 id='manifest'>Manifest</h2>
 
 <p> You must declare the 'downloads' permission in the <a
-href='manifest.html'>extension manifest</a> to use this API, along with <a
-href='declare_permissions.html'>host permissions</a> for any hosts that you may
-pass to $ref:downloads.download.</p>
+href='manifest.html'>extension manifest</a> to use this API.</p>
 
 <pre>{
   'name': 'My extension',
   ...
-<b>  'permissions': [
-    'downloads',
-    '*://*.google.com'
-  ]</b>,
+<b>  'permissions': ['downloads']</b>,
   ...
 }</pre>
 
-<p>If the URL's hostname is not specified in the permissions, then
-$ref:downloads.download will call its callback with a null
-<code>downloadId</code> and set the $ref:runtime.lastError object to indicate
-that the extension does not have permission to access that hostname.</p>
-
 <h2 id='examples'>Examples</h2>
 
 <p>You can find simple examples of using the downloads module in the <a
diff --git a/chrome/common/extensions/docs/templates/json/intro_tables.json b/chrome/common/extensions/docs/templates/json/intro_tables.json
index 532b6eb..a156fae 100644
--- a/chrome/common/extensions/docs/templates/json/intro_tables.json
+++ b/chrome/common/extensions/docs/templates/json/intro_tables.json
@@ -84,10 +84,6 @@
       {
         "class": "code",
         "text": "\"downloads\""
-      },
-      {
-        "link": "declare_permissions.html",
-        "text": "host permissions"
       }
     ]
   },
diff --git a/chrome/common/extensions/docs/templates/private/event.html b/chrome/common/extensions/docs/templates/private/event.html
index b9443de..898b831 100644
--- a/chrome/common/extensions/docs/templates/private/event.html
+++ b/chrome/common/extensions/docs/templates/private/event.html
@@ -1,7 +1,7 @@
 <div>
   <h4 id="{{id}}">{{name}}</h4>
   <div class="summary">
-    <span class="subdued">{{?parent_name}}{{parent_name}}{{:}}chrome.{{api.name}}{{/}}.</span>{{name}}<span class="subdued">.addListener</span>(function({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})<span class="subdued"> {...}</span>);
+    <span class="subdued">{{?parentName}}{{parentName}}{{:}}chrome.{{api.name}}{{/}}.</span>{{name}}<span class="subdued">.addListener</span>(function({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})<span class="subdued"> {...}</span>);
   </div>
   <div class="description">
     {{?description}}<p>
diff --git a/chrome/common/extensions/docs/templates/private/function.html b/chrome/common/extensions/docs/templates/private/function.html
index a285d52..3cfcd41 100644
--- a/chrome/common/extensions/docs/templates/private/function.html
+++ b/chrome/common/extensions/docs/templates/private/function.html
@@ -1,7 +1,7 @@
 <div>
   <h4 id="{{id}}">{{name}}</h4>
   <div class="summary{{^returns}} uncapitalize{{/}}">
-    <span>{{?returns}}{{+partials.variable_type}} {{/}}{{?parent_name}}{{parent_name}}{{:}}chrome.{{api.name}}{{/}}.{{name}}</span>({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})
+    <span>{{?returns}}{{+partials.variable_type}} {{/}}{{?parentName}}{{parentName}}{{:}}chrome.{{api.name}}{{/}}.{{name}}</span>({{#parameters}}{{+partials.parameter_item}}{{^last}}, {{/}}{{/}})
   </div>
   <div class="description">
     {{?description}}
diff --git a/chrome/common/extensions/docs/templates/private/parameter_full.html b/chrome/common/extensions/docs/templates/private/parameter_full.html
index 7f51c2d..f298501 100644
--- a/chrome/common/extensions/docs/templates/private/parameter_full.html
+++ b/chrome/common/extensions/docs/templates/private/parameter_full.html
@@ -1,5 +1,5 @@
 <div>
-  {{?parent_name}}<a name="{{id}}"></a>{{/}}
+  {{?parentName}}<a name="{{id}}"></a>{{/}}
   {{+partials.property}}
   {{?properties}}
   <dd>
diff --git a/chrome/common/extensions/docs/templates/private/toc_events.html b/chrome/common/extensions/docs/templates/private/toc_events.html
index 00e8858..dd5d4be 100644
--- a/chrome/common/extensions/docs/templates/private/toc_events.html
+++ b/chrome/common/extensions/docs/templates/private/toc_events.html
@@ -1,4 +1,4 @@
-<a href="#{{?parent_name}}{{parent_name}}-{{/}}events">Events</a>
+<a href="#{{?parentName}}{{parentName}}-{{/}}events">Events</a>
 <ol>
   {{#events}}
   <li><a href="#{{id}}">{{name}}</a></li>
diff --git a/chrome/common/extensions/docs/templates/private/toc_functions.html b/chrome/common/extensions/docs/templates/private/toc_functions.html
index 15401a7..23d3995 100644
--- a/chrome/common/extensions/docs/templates/private/toc_functions.html
+++ b/chrome/common/extensions/docs/templates/private/toc_functions.html
@@ -1,4 +1,4 @@
-<a href="#{{?parent_name}}{{parent_name}}-{{/}}methods">Methods</a>
+<a href="#{{?parentName}}{{parentName}}-{{/}}methods">Methods</a>
 <ol>
   {{#functions}}
   <li><a href="#{{id}}">{{name}}</a></li>
diff --git a/chrome/common/extensions/docs/templates/private/toc_properties.html b/chrome/common/extensions/docs/templates/private/toc_properties.html
index 630eac9..02f76c3 100644
--- a/chrome/common/extensions/docs/templates/private/toc_properties.html
+++ b/chrome/common/extensions/docs/templates/private/toc_properties.html
@@ -1,16 +1,16 @@
-<a href="#{{?parent_name}}{{parent_name}}-{{/}}properties">Properties</a>
+<a href="#{{?parentName}}{{parentName}}-{{/}}properties">Properties</a>
 <ol>
   {{#properties}}
   <li>
     <a href="#{{id}}">{{name}}</a>
     {{?functions}}<ol><li>
-      {{+partials.toc_functions parent_name:name functions:functions}}
+      {{+partials.toc_functions parentName:name functions:functions}}
     </li></ol>{{/functions}}
     {{?events}}<ol><li>
-      {{+partials.toc_events parent_name:name events:events}}
+      {{+partials.toc_events parentName:name events:events}}
     </li></ol>{{/events}}
     {{?properties}}<ol><li>
-      {{+partials.toc_properties parent_name:name properties:properties}}
+      {{+partials.toc_properties parentName:name properties:properties}}
     </li></ol>{{/properties}}
   </li>
   {{/}}
diff --git a/chrome/common/extensions/docs/templates/private/toc_types.html b/chrome/common/extensions/docs/templates/private/toc_types.html
index bc46bc7..1bfdd2b 100644
--- a/chrome/common/extensions/docs/templates/private/toc_types.html
+++ b/chrome/common/extensions/docs/templates/private/toc_types.html
@@ -1,13 +1,13 @@
-<a href="#{{?parent_name}}{{parent_name}}-{{/}}types">Types</a>
+<a href="#{{?parentName}}{{parentName}}-{{/}}types">Types</a>
 <ol>
   {{#types}}
   <li>
     <a href="#{{id}}">{{name}}</a>
     {{?functions}}<ol><li>
-      {{+partials.toc_functions parent_name:name functions:functions}}
+      {{+partials.toc_functions parentName:name functions:functions}}
     </li></ol>{{/}}
     {{?events}}<ol><li>
-      {{+partials.toc_events parent_name:name events:events}}
+      {{+partials.toc_events parentName:name events:events}}
     </li></ol>{{/}}
   </li>
   {{/}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/audio.html b/chrome/common/extensions/docs/templates/public/extensions/audio.html
new file mode 100644
index 0000000..0bf6943
--- /dev/null
+++ b/chrome/common/extensions/docs/templates/public/extensions/audio.html
@@ -0,0 +1 @@
+{{+partials.standard_extensions_api api:apis.audio}}
diff --git a/chrome/common/extensions/docs/templates/public/extensions/redirects.json b/chrome/common/extensions/docs/templates/public/extensions/redirects.json
index 471fa5d..428f62f 100644
--- a/chrome/common/extensions/docs/templates/public/extensions/redirects.json
+++ b/chrome/common/extensions/docs/templates/public/extensions/redirects.json
@@ -1,5 +1,8 @@
 {
   "": "index.html",
+  "experimental.infobars.html": "infobars.html",
+  "experimental_infobars.html": "infobars.html",
+  "experimental.systemInfo_storage.html": "system_storage.html",
   "experimental_systemInfo_storage.html": "system_storage.html",
   "systemInfo_cpu.html": "system_cpu.html",
   "systemInfo_memory.html": "system_memory.html"
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index d99616d..980be54 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -91,6 +91,7 @@
     kInput,
     kInputMethodPrivate,
     kLocation,
+    kLogPrivate,
     kManagement,
     kMediaGalleries,
     kMediaGalleriesPrivate,
@@ -141,6 +142,8 @@
     kWebView,
     kSystemCpu,
     kSystemMemory,
+    kSystemInfoCpu,
+    kSystemInfoMemory,
     kEnumBoundary
   };
 
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 6562f9c..0b368f8 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -166,6 +166,7 @@
       APIPermissionInfo::kFlagCannotBeOptional },
     { APIPermission::kIdentityPrivate, "identityPrivate",
       APIPermissionInfo::kFlagCannotBeOptional },
+    { APIPermission::kLogPrivate, "logPrivate"},
     { APIPermission::kNetworkingPrivate, "networkingPrivate",
       APIPermissionInfo::kFlagCannotBeOptional,
       IDS_EXTENSION_PROMPT_WARNING_NETWORKING_PRIVATE,
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 366843e..f5adabd 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -647,6 +647,7 @@
   skip.insert(APIPermission::kFontSettings);
   skip.insert(APIPermission::kFullscreen);
   skip.insert(APIPermission::kIdle);
+  skip.insert(APIPermission::kLogPrivate);
   skip.insert(APIPermission::kNotification);
   skip.insert(APIPermission::kPointerLock);
   skip.insert(APIPermission::kPower);
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 64ea5b7..bdbb346 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1916,25 +1916,21 @@
     "google.services.username_pattern";
 
 #if !defined(OS_ANDROID)
-// Tracks the number of times that we have shown the sync promo at startup.
-const char kSyncPromoStartupCount[] = "sync_promo.startup_count";
+// Tracks the number of times that we have shown the sign in promo at startup.
+const char kSignInPromoStartupCount[] = "sync_promo.startup_count";
 
-// Boolean tracking whether the user chose to skip the sync promo.
-const char kSyncPromoUserSkipped[] = "sync_promo.user_skipped";
+// Boolean tracking whether the user chose to skip the sign in promo.
+const char kSignInPromoUserSkipped[] = "sync_promo.user_skipped";
 
-// Boolean that specifies if the sync promo is allowed to show on first run.
+// Boolean that specifies if the sign in promo is allowed to show on first run.
 // This preference is specified in the master preference file to suppress the
-// sync promo for some installations.
-const char kSyncPromoShowOnFirstRunAllowed[] =
+// sign in promo for some installations.
+const char kSignInPromoShowOnFirstRunAllowed[] =
     "sync_promo.show_on_first_run_allowed";
 
 // Boolean that specifies if we should show a bubble in the new tab page.
 // The bubble is used to confirm that the user is signed into sync.
-const char kSyncPromoShowNTPBubble[] = "sync_promo.show_ntp_bubble";
-
-// An error to show in the sync promo bubble, if needed.  If the sign in was
-// successful, this property holds an empty string.
-const char kSyncPromoErrorMessage[] = "sync_promo.error_message";
+const char kSignInPromoShowNTPBubble[] = "sync_promo.show_ntp_bubble";
 #endif
 
 // Time when the user's GAIA info was last updated (represented as an int64).
@@ -2061,6 +2057,20 @@
 const char kDailyHttpReceivedContentLength[] =
     "data_reduction.daily_received_length";
 
+// A List pref that contains daily totals of the size of all HTTP content that
+// has been received via the data reduction proxy.
+const char kDailyHttpReceivedContentLengthViaDataReductionProxy[] =
+    "data_reduction.daily_received_length_via_data_reduction_proxy";
+
+// A List pref that contains daily totals of the size of all HTTP content that
+// has been received when the data reduction proxy is enabled.
+// Note: this is different from
+// kDailyHttpReceivedContentLengthViaDataReductionProxy because content
+// doesn't necessarily go through the data reduction proxy when it is enabled.
+// E.g., the proxy doesn't handle HTTPS traffic.
+const char kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled[] =
+    "data_reduction.daily_received_length_with_data_reduction_proxy_enabled";
+
 // An int64 pref that contains an internal representation of midnight on the
 // date of the last update to |kDailyHttp{Original,Received}ContentLength|.
 const char kDailyHttpContentLengthLastUpdateDate[] =
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 7fe5493..d6d79b2 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -676,11 +676,10 @@
 extern const char kInvalidatorInvalidationState[];
 extern const char kInvalidatorMaxInvalidationVersions[];
 
-extern const char kSyncPromoStartupCount[];
-extern const char kSyncPromoUserSkipped[];
-extern const char kSyncPromoShowOnFirstRunAllowed[];
-extern const char kSyncPromoShowNTPBubble[];
-extern const char kSyncPromoErrorMessage[];
+extern const char kSignInPromoStartupCount[];
+extern const char kSignInPromoUserSkipped[];
+extern const char kSignInPromoShowOnFirstRunAllowed[];
+extern const char kSignInPromoShowNTPBubble[];
 
 extern const char kProfileGAIAInfoUpdateTime[];
 extern const char kProfileGAIAInfoPictureURL[];
@@ -819,6 +818,9 @@
 #if defined(OS_ANDROID) || defined(OS_IOS)
 extern const char kDailyHttpOriginalContentLength[];
 extern const char kDailyHttpReceivedContentLength[];
+extern const char kDailyHttpReceivedContentLengthViaDataReductionProxy[];
+extern const char
+    kDailyHttpReceivedContentLengthWithDataReductionProxyEnabled[];
 extern const char kDailyHttpContentLengthLastUpdateDate[];
 #endif
 
diff --git a/chrome/common/time_format_browsertest.cc b/chrome/common/time_format_browsertest.cc
index 649ac02..1431031 100644
--- a/chrome/common/time_format_browsertest.cc
+++ b/chrome/common/time_format_browsertest.cc
@@ -13,8 +13,8 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_locale.h"
-#include "chrome/common/time_format.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "ui/base/l10n/time_format.h"
 
 using base::TimeDelta;
 
@@ -34,6 +34,7 @@
   // This showed up on the browser on estimated download time, for example.
   // http://crbug.com/60476
 
-  string16 one_min = TimeFormat::TimeRemainingShort(TimeDelta::FromMinutes(1));
+  string16 one_min =
+      ui::TimeFormat::TimeRemainingShort(TimeDelta::FromMinutes(1));
   EXPECT_EQ(ASCIIToUTF16("1 min"), one_min);
 }
diff --git a/chrome/installer/linux/debian/build.sh b/chrome/installer/linux/debian/build.sh
index d9d98a1..39e2153 100755
--- a/chrome/installer/linux/debian/build.sh
+++ b/chrome/installer/linux/debian/build.sh
@@ -288,14 +288,16 @@
 rm -rf "$DUMMY_STAGING_DIR"
 
 # Additional dependencies not in the dpkg-shlibdeps output.
-ADDITION_DEPS="ca-certificates, libcurl3, \
+# Pull a more recent version of NSS than required by runtime linking, for
+# security and stability updates in NSS.
+ADDITION_DEPS="ca-certificates, libcurl3, libnss3 (>= 3.14.3), \
   lsb-base (>=3.2), xdg-utils (>= 1.0.2), wget"
 
 # Fix-up libnspr dependency due to renaming in Ubuntu (the old package still
 # exists, but it was moved to "universe" repository, which isn't installed by
 # default).
 DPKG_SHLIB_DEPS=$(sed \
-    's/\(libnspr4-0d ([^)]*)\), /\1 | libnspr4 (>= 4.8.7-0ubuntu1), /g' \
+    's/\(libnspr4-0d ([^)]*)\), /\1 | libnspr4 (>= 4.9.5-0ubuntu0), /g' \
     <<< $DPKG_SHLIB_DEPS)
 
 # Fix-up libudev dependency because Ubuntu 13.04 has libudev1 instead of
diff --git a/chrome/installer/linux/rpm/build.sh b/chrome/installer/linux/rpm/build.sh
index 544a46a..7134e59 100755
--- a/chrome/installer/linux/rpm/build.sh
+++ b/chrome/installer/linux/rpm/build.sh
@@ -124,7 +124,7 @@
   # https://bugzilla.novell.com/show_bug.cgi?id=556248
   DEPENDS="lsb >= 4.0, \
   libcurl.so.4${EMPTY_VERSION}${PKG_ARCH}, \
-  libnss3.so(NSS_3.12.3)${PKG_ARCH}, \
+  libnss3.so(NSS_3.14.3)${PKG_ARCH}, \
   wget, \
   xdg-utils, \
   zlib, \
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index 6409d44..07b75b3 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -648,7 +648,6 @@
     Version* existing_version,
     const base::FilePath& temp_path) const {
   Version version;
-  std::vector<base::FilePath> key_files;
   scoped_ptr<WorkItem> item;
 
   std::set<std::string> existing_version_strings;
diff --git a/chrome/renderer/extensions/OWNERS b/chrome/renderer/extensions/OWNERS
index 16f17f1..a6cd87d 100644
--- a/chrome/renderer/extensions/OWNERS
+++ b/chrome/renderer/extensions/OWNERS
@@ -5,6 +5,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/chrome/renderer/pepper/pnacl_translation_resource_host.cc b/chrome/renderer/pepper/pnacl_translation_resource_host.cc
index 75aa6d4..609ddec 100644
--- a/chrome/renderer/pepper/pnacl_translation_resource_host.cc
+++ b/chrome/renderer/pepper/pnacl_translation_resource_host.cc
@@ -102,26 +102,30 @@
 }
 
 void PnaclTranslationResourceHost::ReportTranslationFinished(
-    PP_Instance instance) {
+    PP_Instance instance,
+    PP_Bool success) {
   DCHECK(PpapiGlobals::Get()->
          GetMainThreadMessageLoop()->BelongsToCurrentThread());
   io_message_loop_->PostTask(
       FROM_HERE,
       base::Bind(&PnaclTranslationResourceHost::SendReportTranslationFinished,
                  this,
-                 instance));
+                 instance,
+                 success));
   return;
 }
 
 void PnaclTranslationResourceHost::SendReportTranslationFinished(
-    PP_Instance instance) {
+    PP_Instance instance,
+    PP_Bool success) {
   DCHECK(io_message_loop_->BelongsToCurrentThread());
   // If the channel is closed or we have been detached, we are probably shutting
   // down, so just don't send anything.
   if (!channel_)
     return;
   DCHECK(pending_cache_requests_.count(instance) == 0);
-  channel_->Send(new NaClHostMsg_ReportTranslationFinished(instance));
+  channel_->Send(new NaClHostMsg_ReportTranslationFinished(instance,
+                                                           PP_ToBool(success)));
 }
 
 void PnaclTranslationResourceHost::OnNexeTempFileReply(
diff --git a/chrome/renderer/pepper/pnacl_translation_resource_host.h b/chrome/renderer/pepper/pnacl_translation_resource_host.h
index 9f1a204..5958544 100644
--- a/chrome/renderer/pepper/pnacl_translation_resource_host.h
+++ b/chrome/renderer/pepper/pnacl_translation_resource_host.h
@@ -33,7 +33,7 @@
                      PP_Bool* is_hit,
                      PP_FileHandle* file_handle,
                      scoped_refptr<ppapi::TrackedCallback> callback);
-  void ReportTranslationFinished(PP_Instance instance);
+  void ReportTranslationFinished(PP_Instance instance, PP_Bool success);
 
   // Ensure that PNaCl resources (pnacl-llc.nexe, linker, libs) are installed.
   void EnsurePnaclInstalled(PP_Instance instance,
@@ -74,7 +74,8 @@
                          PP_Bool* is_hit,
                          PP_FileHandle* file_handle,
                          scoped_refptr<ppapi::TrackedCallback> callback);
-  void SendReportTranslationFinished(PP_Instance instance);
+  void SendReportTranslationFinished(PP_Instance instance,
+                                     PP_Bool success);
   void SendEnsurePnaclInstalled(PP_Instance instance,
                                 scoped_refptr<ppapi::TrackedCallback> callback);
 
diff --git a/chrome/renderer/pepper/ppb_nacl_private_impl.cc b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
index 91ce85c..ce95b62 100644
--- a/chrome/renderer/pepper/ppb_nacl_private_impl.cc
+++ b/chrome/renderer/pepper/ppb_nacl_private_impl.cc
@@ -290,12 +290,12 @@
   return enter.SetResult(PP_OK_COMPLETIONPENDING);
 }
 
-void ReportTranslationFinished(PP_Instance instance) {
+void ReportTranslationFinished(PP_Instance instance, PP_Bool success) {
   // If the resource host isn't initialized, don't try to do that here.
   // Just return because something is already very wrong.
   if (g_pnacl_resource_host.Get() == NULL)
     return;
-  g_pnacl_resource_host.Get()->ReportTranslationFinished(instance);
+  g_pnacl_resource_host.Get()->ReportTranslationFinished(instance, success);
 }
 
 PP_Bool IsOffTheRecord() {
diff --git a/chrome/renderer/resources/extensions/OWNERS b/chrome/renderer/resources/extensions/OWNERS
index ad38aab..50f29c1 100644
--- a/chrome/renderer/resources/extensions/OWNERS
+++ b/chrome/renderer/resources/extensions/OWNERS
@@ -5,6 +5,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/chrome/renderer/resources/neterror.html b/chrome/renderer/resources/neterror.html
index 14e0a74..8b81d1d 100644
--- a/chrome/renderer/resources/neterror.html
+++ b/chrome/renderer/resources/neterror.html
@@ -43,6 +43,12 @@
 </if>
 }
 
+#diagnose-button {
+  margin-top: 20px;
+  margin-bottom: 10px;
+  -webkit-margin-start: 0px;
+}
+
 h1 {
   color: #666;
   margin: 10px 0px 25px 0px;
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index d9b8c06..73efa62 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -51,7 +51,7 @@
   // perhaps by AshTestHelper owning an AuraTestHelper.
   ash_test_helper_.reset(new ash::test::AshTestHelper(
       base::MessageLoopForUI::current()));
-  ash_test_helper_->SetUp();
+  ash_test_helper_->SetUp(true);
 #elif defined(USE_AURA)
   aura_test_helper_.reset(new aura::test::AuraTestHelper(
       base::MessageLoopForUI::current()));
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index c9d15d8..0aef3d5 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -679,7 +679,14 @@
       LIST_TEST(PostMessage_ExtraParam)
   );
 }
-IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, PostMessage) {
+
+// Flaky: crbug.com/269530
+#if defined(OS_WIN)
+#define MAYBE_PostMessage DISABLED_PostMessage
+#else
+#define MAYBE_PostMessage PostMessage
+#endif
+IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, MAYBE_PostMessage) {
   RunTestViaHTTP(
       LIST_TEST(PostMessage_SendInInit)
       LIST_TEST(PostMessage_SendingData)
diff --git a/chrome/utility/importer/firefox_importer.cc b/chrome/utility/importer/firefox_importer.cc
index 2869032..b1a29a0 100644
--- a/chrome/utility/importer/firefox_importer.cc
+++ b/chrome/utility/importer/firefox_importer.cc
@@ -19,7 +19,6 @@
 #include "chrome/common/importer/imported_favicon_usage.h"
 #include "chrome/common/importer/importer_bridge.h"
 #include "chrome/common/importer/importer_url_row.h"
-#include "chrome/common/time_format.h"
 #include "chrome/utility/importer/bookmark_html_reader.h"
 #include "chrome/utility/importer/favicon_reencode.h"
 #include "chrome/utility/importer/nss_decryptor.h"
diff --git a/chrome/utility/importer/ie_importer_win.cc b/chrome/utility/importer/ie_importer_win.cc
index 76c350d..11a61c2 100644
--- a/chrome/utility/importer/ie_importer_win.cc
+++ b/chrome/utility/importer/ie_importer_win.cc
@@ -36,7 +36,6 @@
 #include "chrome/common/importer/importer_data_types.h"
 #include "chrome/common/importer/importer_url_row.h"
 #include "chrome/common/importer/pstore_declarations.h"
-#include "chrome/common/time_format.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/utility/importer/favicon_reencode.h"
 #include "content/public/common/password_form.h"
diff --git a/chrome/utility/local_discovery/service_discovery_client_unittest.cc b/chrome/utility/local_discovery/service_discovery_client_unittest.cc
index 2f7a15d..43914ee 100644
--- a/chrome/utility/local_discovery/service_discovery_client_unittest.cc
+++ b/chrome/utility/local_discovery/service_discovery_client_unittest.cc
@@ -135,6 +135,40 @@
   0x03, 0x04,
 };
 
+const uint8 kSamplePacketPTR2[] = {
+  // Header
+  0x00, 0x00,               // ID is zeroed out
+  0x81, 0x80,               // Standard query response, RA, no error
+  0x00, 0x00,               // No questions (for simplicity)
+  0x00, 0x02,               // 2 RR (answers)
+  0x00, 0x00,               // 0 authority RRs
+  0x00, 0x00,               // 0 additional RRs
+
+  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.
+  0x02, 0x00,        // TTL (4 bytes) is 1 second.
+  0x00, 0x01,
+  0x00, 0x08,        // RDLENGTH is 8 bytes.
+  0x05, 'g', 'd', 'b', 'y', 'e',
+  0xc0, 0x0c,
+
+  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.
+  0x02, 0x00,        // TTL (4 bytes) is 1 second.
+  0x00, 0x01,
+  0x00, 0x08,        // RDLENGTH is 8 bytes.
+  0x05, 'h', 'e', 'l', 'l', 'o',
+  0xc0, 0x0c
+};
+
 class MockServiceWatcherClient {
  public:
   MOCK_METHOD2(OnServiceUpdated,
@@ -220,12 +254,6 @@
 };
 
 TEST_F(ServiceDiscoveryTest, ReadCachedServices) {
-  scoped_ptr<ServiceWatcher> watcher_irrelevant(
-      service_discovery_client_.CreateServiceWatcher(
-          "_privet._tcp.local", ServiceWatcher::UpdatedCallback()));
-
-  watcher_irrelevant->Start();
-
   socket_factory_->SimulateReceive(
       kSamplePacketPTR, sizeof(kSamplePacketPTR));
 
@@ -244,6 +272,30 @@
   base::MessageLoop::current()->RunUntilIdle();
 };
 
+
+TEST_F(ServiceDiscoveryTest, ReadCachedServicesMultiple) {
+  socket_factory_->SimulateReceive(
+      kSamplePacketPTR2, sizeof(kSamplePacketPTR2));
+
+  StrictMock<MockServiceWatcherClient> delegate;
+  scoped_ptr<ServiceWatcher> watcher =
+      service_discovery_client_.CreateServiceWatcher(
+          "_privet._tcp.local", delegate.GetCallback());
+
+  watcher->Start();
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "hello._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  EXPECT_CALL(delegate, OnServiceUpdated(ServiceWatcher::UPDATE_ADDED,
+                                         "gdbye._privet._tcp.local"))
+      .Times(Exactly(1));
+
+  base::MessageLoop::current()->RunUntilIdle();
+};
+
+
 TEST_F(ServiceDiscoveryTest, OnServiceChanged) {
   StrictMock<MockServiceWatcherClient> delegate;
   scoped_ptr<ServiceWatcher> watcher(
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 48692ed..80e13f6 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-4503.0.0
\ No newline at end of file
+4509.0.0
\ No newline at end of file
diff --git a/components/autofill/content/browser/autocheckout_manager.cc b/components/autofill/content/browser/autocheckout_manager.cc
index ee1c457..be81923 100644
--- a/components/autofill/content/browser/autocheckout_manager.cc
+++ b/components/autofill/content/browser/autocheckout_manager.cc
@@ -356,25 +356,27 @@
   for (size_t i = 0; i < result->field_count(); ++i) {
     const AutofillType& type = result->field(i)->Type();
     const base::string16& value = result->field(i)->value;
-    if (type.server_type() == CREDIT_CARD_VERIFICATION_CODE) {
+    ServerFieldType server_type = type.GetStorableType();
+    if (server_type == CREDIT_CARD_VERIFICATION_CODE) {
       cvv_ = result->field(i)->value;
       continue;
     }
     FieldTypeGroup group = type.group();
     if (group == CREDIT_CARD) {
-      credit_card_->SetRawInfo(type.server_type(), value);
+      credit_card_->SetRawInfo(server_type, value);
       // TODO(dgwallinga): Find a way of cleanly deprecating CREDIT_CARD_NAME.
       // code.google.com/p/chromium/issues/detail?id=263498
-      if (type.server_type() == CREDIT_CARD_NAME)
+      if (server_type == CREDIT_CARD_NAME)
         billing_address_->SetRawInfo(NAME_BILLING_FULL, value);
-    } else if (type.server_type() == ADDRESS_HOME_COUNTRY) {
-      profile_->SetInfo(type, value, autofill_manager_->app_locale());
-    } else if (type.server_type() == ADDRESS_BILLING_COUNTRY) {
-      billing_address_->SetInfo(type, value, autofill_manager_->app_locale());
+    } else if (server_type == ADDRESS_HOME_COUNTRY) {
+      if (IsBillingGroup(group))
+        billing_address_->SetInfo(type, value, autofill_manager_->app_locale());
+      else
+        profile_->SetInfo(type, value, autofill_manager_->app_locale());
     } else if (IsBillingGroup(group)) {
-      billing_address_->SetRawInfo(type.server_type(), value);
+      billing_address_->SetRawInfo(server_type, value);
     } else {
-      profile_->SetRawInfo(type.server_type(), value);
+      profile_->SetRawInfo(server_type, value);
     }
   }
 
@@ -431,11 +433,11 @@
       &AutocheckoutManager::MaybeShowAutocheckoutDialog,
       weak_ptr_factory_.GetWeakPtr(),
       frame_url);
-  autofill_manager_->delegate()->ShowAutocheckoutBubble(
-      bounding_box,
-      cookies.find("LSID") != std::string::npos,
-      callback);
-  is_autocheckout_bubble_showing_ = true;
+  is_autocheckout_bubble_showing_ =
+      autofill_manager_->delegate()->ShowAutocheckoutBubble(
+          bounding_box,
+          cookies.find("LSID") != std::string::npos,
+          callback);
 }
 
 bool AutocheckoutManager::IsStartOfAutofillableFlow() const {
@@ -454,7 +456,8 @@
 
   const AutofillType& type = field.Type();
 
-  if (type.server_type() == FIELD_WITH_DEFAULT_VALUE) {
+  ServerFieldType server_type = type.GetStorableType();
+  if (server_type == FIELD_WITH_DEFAULT_VALUE) {
     // For a form with radio buttons, like:
     // <form>
     //   <input type="radio" name="sex" value="male">Male<br>
@@ -488,7 +491,7 @@
   }
 
   // Handle verification code directly.
-  if (type.server_type() == CREDIT_CARD_VERIFICATION_CODE) {
+  if (server_type == CREDIT_CARD_VERIFICATION_CODE) {
     field_to_fill->value = cvv_;
     return;
   }
diff --git a/components/autofill/content/browser/autocheckout_manager_unittest.cc b/components/autofill/content/browser/autocheckout_manager_unittest.cc
index 3333384..c8e4255 100644
--- a/components/autofill/content/browser/autocheckout_manager_unittest.cc
+++ b/components/autofill/content/browser/autocheckout_manager_unittest.cc
@@ -286,13 +286,14 @@
   MOCK_METHOD0(OnAutocheckoutError, void());
   MOCK_METHOD0(OnAutocheckoutSuccess, void());
 
-  virtual void ShowAutocheckoutBubble(
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounds,
       bool is_google_user,
       const base::Callback<void(AutocheckoutBubbleState)>& callback) OVERRIDE {
     autocheckout_bubble_shown_ = true;
     if (should_autoclick_bubble_)
       callback.Run(AUTOCHECKOUT_BUBBLE_ACCEPTED);
+    return true;
   }
 
   virtual void ShowRequestAutocompleteDialog(
diff --git a/components/autofill/content/browser/wallet/full_wallet.cc b/components/autofill/content/browser/wallet/full_wallet.cc
index eaadcc4..28c47b3 100644
--- a/components/autofill/content/browser/wallet/full_wallet.cc
+++ b/components/autofill/content/browser/wallet/full_wallet.cc
@@ -128,7 +128,7 @@
 }
 
 base::string16 FullWallet::GetInfo(const AutofillType& type) {
-  switch (type.server_type()) {
+  switch (type.GetStorableType()) {
     case CREDIT_CARD_NUMBER:
       return UTF8ToUTF16(GetPan());
 
diff --git a/components/autofill/content/browser/wallet/wallet_address.cc b/components/autofill/content/browser/wallet/wallet_address.cc
index 5b69ea3..9595c3c 100644
--- a/components/autofill/content/browser/wallet/wallet_address.cc
+++ b/components/autofill/content/browser/wallet/wallet_address.cc
@@ -264,7 +264,7 @@
 
 string16 Address::GetInfo(const AutofillType& type,
                           const std::string& app_locale) const {
-  switch (AutofillType::GetEquivalentFieldType(type.server_type())) {
+  switch (type.GetStorableType()) {
     case NAME_FULL:
       return recipient_name();
 
diff --git a/components/autofill/content/browser/wallet/wallet_items.cc b/components/autofill/content/browser/wallet/wallet_items.cc
index 6a861e2..03cf3f4 100644
--- a/components/autofill/content/browser/wallet/wallet_items.cc
+++ b/components/autofill/content/browser/wallet/wallet_items.cc
@@ -314,7 +314,7 @@
   if (type.group() != CREDIT_CARD)
     return address().GetInfo(type, app_locale);
 
-  switch (type.server_type()) {
+  switch (type.GetStorableType()) {
     case CREDIT_CARD_NAME:
       return address().recipient_name();
 
diff --git a/components/autofill/content/renderer/autofill_agent.cc b/components/autofill/content/renderer/autofill_agent.cc
index f2300e6..e8509c7 100644
--- a/components/autofill/content/renderer/autofill_agent.cc
+++ b/components/autofill/content/renderer/autofill_agent.cc
@@ -177,6 +177,8 @@
                         OnFillFormsAndClick)
     IPC_MESSAGE_HANDLER(AutofillMsg_AutocheckoutSupported,
                         OnAutocheckoutSupported)
+    IPC_MESSAGE_HANDLER(AutofillMsg_PageShown,
+                        OnPageShown)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -613,6 +615,11 @@
   MaybeShowAutocheckoutBubble();
 }
 
+void AutofillAgent::OnPageShown() {
+  if (is_autocheckout_supported_)
+    MaybeShowAutocheckoutBubble();
+}
+
 void AutofillAgent::CompleteAutocheckoutPage(
     autofill::AutocheckoutStatus status) {
   click_timer_.Stop();
diff --git a/components/autofill/content/renderer/autofill_agent.h b/components/autofill/content/renderer/autofill_agent.h
index 319b3aa..9236246 100644
--- a/components/autofill/content/renderer/autofill_agent.h
+++ b/components/autofill/content/renderer/autofill_agent.h
@@ -132,6 +132,10 @@
   // Called when |topmost_frame_| is supported for Autocheckout.
   void OnAutocheckoutSupported();
 
+  // Called when the page is actually shown in the browser, as opposed to simply
+  // being preloaded.
+  void OnPageShown();
+
   // Called when an Autocheckout page is completed by the renderer.
   void CompleteAutocheckoutPage(autofill::AutocheckoutStatus status);
 
diff --git a/components/autofill/core/browser/address.cc b/components/autofill/core/browser/address.cc
index 339352f..ca522f6 100644
--- a/components/autofill/core/browser/address.cc
+++ b/components/autofill/core/browser/address.cc
@@ -44,70 +44,84 @@
 }
 
 base::string16 Address::GetRawInfo(ServerFieldType type) const {
-  type = AutofillType::GetEquivalentFieldType(type);
-  if (type == ADDRESS_HOME_LINE1)
-    return line1_;
+  // TODO(isherman): Is GetStorableType even necessary?
+  switch (AutofillType(type).GetStorableType()) {
+    case ADDRESS_HOME_LINE1:
+      return line1_;
 
-  if (type == ADDRESS_HOME_LINE2)
-    return line2_;
+    case ADDRESS_HOME_LINE2:
+      return line2_;
 
-  if (type == ADDRESS_HOME_CITY)
-    return city_;
+    case ADDRESS_HOME_CITY:
+      return city_;
 
-  if (type == ADDRESS_HOME_STATE)
-    return state_;
+    case ADDRESS_HOME_STATE:
+      return state_;
 
-  if (type ==  ADDRESS_HOME_ZIP)
-    return zip_code_;
+    case ADDRESS_HOME_ZIP:
+      return zip_code_;
 
-  if (type == ADDRESS_HOME_COUNTRY)
-    return country_code_;
+    case ADDRESS_HOME_COUNTRY:
+      return country_code_;
 
-  return base::string16();
+    default:
+      return base::string16();
+  }
 }
 
 void Address::SetRawInfo(ServerFieldType type, const base::string16& value) {
-  type = AutofillType::GetEquivalentFieldType(type);
-  if (type == ADDRESS_HOME_LINE1) {
-    line1_ = value;
-  } else if (type == ADDRESS_HOME_LINE2) {
-    line2_ = value;
-  } else if (type == ADDRESS_HOME_CITY) {
-    city_ = value;
-  } else if (type == ADDRESS_HOME_STATE) {
-    state_ = value;
-  } else if (type == ADDRESS_HOME_COUNTRY) {
-    DCHECK(value.empty() || value.length() == 2u);
-    country_code_ = value;
-  } else if (type == ADDRESS_HOME_ZIP) {
-    zip_code_ = value;
-  } else {
-    NOTREACHED();
+  // TODO(isherman): Is GetStorableType even necessary?
+  switch (AutofillType(type).GetStorableType()) {
+    case ADDRESS_HOME_LINE1:
+      line1_ = value;
+      break;
+
+    case ADDRESS_HOME_LINE2:
+      line2_ = value;
+      break;
+
+    case ADDRESS_HOME_CITY:
+      city_ = value;
+      break;
+
+    case ADDRESS_HOME_STATE:
+      state_ = value;
+      break;
+
+    case ADDRESS_HOME_COUNTRY:
+      DCHECK(value.empty() || value.length() == 2u);
+      country_code_ = value;
+      break;
+
+    case ADDRESS_HOME_ZIP:
+      zip_code_ = value;
+      break;
+
+    default:
+      NOTREACHED();
   }
 }
 
 base::string16 Address::GetInfo(const AutofillType& type,
                                 const std::string& app_locale) const {
-  ServerFieldType server_type =
-      AutofillType::GetEquivalentFieldType(type.server_type());
-  if (server_type == ADDRESS_HOME_COUNTRY && !country_code_.empty())
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == ADDRESS_HOME_COUNTRY && !country_code_.empty())
     return AutofillCountry(UTF16ToASCII(country_code_), app_locale).name();
 
-  return GetRawInfo(server_type);
+  return GetRawInfo(storable_type);
 }
 
 bool Address::SetInfo(const AutofillType& type,
                       const base::string16& value,
                       const std::string& app_locale) {
-  ServerFieldType server_type =
-      AutofillType::GetEquivalentFieldType(type.server_type());
-  if (server_type == ADDRESS_HOME_COUNTRY && !value.empty()) {
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == ADDRESS_HOME_COUNTRY && !value.empty()) {
     country_code_ =
         ASCIIToUTF16(AutofillCountry::GetCountryCode(value, app_locale));
     return !country_code_.empty();
   }
 
-  SetRawInfo(server_type, value);
+  SetRawInfo(storable_type, value);
   return true;
 }
 
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc
index 28a380e..2d1edcf 100644
--- a/components/autofill/core/browser/autofill_data_model.cc
+++ b/components/autofill/core/browser/autofill_data_model.cc
@@ -158,22 +158,20 @@
     return;
   }
 
-  ServerFieldType server_type = type.server_type();
-  if (server_type == ADDRESS_HOME_STATE ||
-      server_type == ADDRESS_BILLING_STATE) {
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == ADDRESS_HOME_STATE) {
     FillStateSelectControl(field_text, field);
-  } else if (server_type == ADDRESS_HOME_COUNTRY ||
-             server_type == ADDRESS_BILLING_COUNTRY) {
+  } else if (storable_type == ADDRESS_HOME_COUNTRY) {
     FillCountrySelectControl(app_locale, field);
-  } else if (server_type == CREDIT_CARD_EXP_MONTH) {
+  } else if (storable_type == CREDIT_CARD_EXP_MONTH) {
     FillExpirationMonthSelectControl(field_text, field);
-  } else if (server_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
+  } else if (storable_type == CREDIT_CARD_EXP_4_DIGIT_YEAR) {
     // Attempt to fill the year as a 2-digit year.  This compensates for the
     // fact that our heuristics do not always correctly detect when a website
     // requests a 2-digit rather than a 4-digit year.
     FillSelectControl(AutofillType(CREDIT_CARD_EXP_2_DIGIT_YEAR), app_locale,
                       field);
-  } else if (server_type == CREDIT_CARD_TYPE) {
+  } else if (storable_type == CREDIT_CARD_TYPE) {
     FillCreditCardTypeSelectControl(field_text, field);
   }
 }
diff --git a/components/autofill/core/browser/autofill_field.cc b/components/autofill/core/browser/autofill_field.cc
index 5d19232..4bcb118 100644
--- a/components/autofill/core/browser/autofill_field.cc
+++ b/components/autofill/core/browser/autofill_field.cc
@@ -31,6 +31,8 @@
 AutofillField::AutofillField()
     : server_type_(NO_SERVER_DATA),
       heuristic_type_(UNKNOWN_TYPE),
+      html_type_(HTML_TYPE_UNKNOWN),
+      html_mode_(HTML_MODE_NONE),
       phone_part_(IGNORED) {
 }
 
@@ -40,6 +42,8 @@
       unique_name_(unique_name),
       server_type_(NO_SERVER_DATA),
       heuristic_type_(UNKNOWN_TYPE),
+      html_type_(HTML_TYPE_UNKNOWN),
+      html_mode_(HTML_MODE_NONE),
       phone_part_(IGNORED) {
 }
 
@@ -65,7 +69,20 @@
   server_type_ = type;
 }
 
+void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) {
+  html_type_ = type;
+  html_mode_ = mode;
+
+  if (type == HTML_TYPE_TEL_LOCAL_PREFIX)
+    phone_part_ = AutofillField::PHONE_PREFIX;
+  else if (type == HTML_TYPE_TEL_LOCAL_SUFFIX)
+    phone_part_ = AutofillField::PHONE_SUFFIX;
+}
+
 AutofillType AutofillField::Type() const {
+  if (html_type_ != HTML_TYPE_UNKNOWN)
+    return AutofillType(html_type_, html_mode_);
+
   if (server_type_ != NO_SERVER_DATA)
     return AutofillType(server_type_);
 
@@ -83,7 +100,7 @@
 }
 
 bool AutofillField::IsFieldFillable() const {
-  return Type().server_type() != UNKNOWN_TYPE;
+  return !Type().IsUnknown();
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_field.h b/components/autofill/core/browser/autofill_field.h
index 53826cd..6f57484 100644
--- a/components/autofill/core/browser/autofill_field.h
+++ b/components/autofill/core/browser/autofill_field.h
@@ -33,17 +33,19 @@
   const std::string& section() const { return section_; }
   ServerFieldType heuristic_type() const { return heuristic_type_; }
   ServerFieldType server_type() const { return server_type_; }
+  HtmlFieldType html_type() const { return html_type_; }
+  HtmlFieldMode html_mode() const { return html_mode_; }
   const ServerFieldTypeSet& possible_types() const { return possible_types_; }
   PhonePart phone_part() const { return phone_part_; }
 
-  // Sets the heuristic type of this field, validating the input.
+  // Setters for the detected type and section for this field.
   void set_section(const std::string& section) { section_ = section; }
   void set_heuristic_type(ServerFieldType type);
   void set_server_type(ServerFieldType type);
   void set_possible_types(const ServerFieldTypeSet& possible_types) {
     possible_types_ = possible_types;
   }
-  void set_phone_part(PhonePart part) { phone_part_ = part; }
+  void SetHtmlType(HtmlFieldType type, HtmlFieldMode mode);
 
   // This function automatically chooses between server and heuristic autofill
   // type, depending on the data available.
@@ -77,6 +79,13 @@
   // The type of the field, as determined by the local heuristics.
   ServerFieldType heuristic_type_;
 
+  // The type of the field, as specified by the site author in HTML.
+  HtmlFieldType html_type_;
+
+  // The "mode" of the field, as specified by the site author in HTML.
+  // Currently this is used to distinguish between billing and shipping fields.
+  HtmlFieldMode html_mode_;
+
   // The set of possible types for this field.
   ServerFieldTypeSet possible_types_;
 
diff --git a/components/autofill/core/browser/autofill_field_unittest.cc b/components/autofill/core/browser/autofill_field_unittest.cc
index c47f314..3c26302 100644
--- a/components/autofill/core/browser/autofill_field_unittest.cc
+++ b/components/autofill/core/browser/autofill_field_unittest.cc
@@ -18,19 +18,22 @@
   ASSERT_EQ(UNKNOWN_TYPE, field.heuristic_type());
 
   // |server_type_| is NO_SERVER_DATA, so |heuristic_type_| is returned.
-  EXPECT_EQ(UNKNOWN_TYPE, field.Type().server_type());
+  EXPECT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
 
   // Set the heuristic type and check it.
   field.set_heuristic_type(NAME_FIRST);
-  EXPECT_EQ(NAME_FIRST, field.Type().server_type());
+  EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
+  EXPECT_EQ(NAME, field.Type().group());
 
   // Set the server type and check it.
   field.set_server_type(ADDRESS_BILLING_LINE1);
-  EXPECT_EQ(ADDRESS_BILLING_LINE1, field.Type().server_type());
+  EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
+  EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
 
   // Remove the server type to make sure the heuristic type is preserved.
   field.set_server_type(NO_SERVER_DATA);
-  EXPECT_EQ(NAME_FIRST, field.Type().server_type());
+  EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
+  EXPECT_EQ(NAME, field.Type().group());
 }
 
 TEST(AutofillFieldTest, IsEmpty) {
@@ -72,7 +75,7 @@
 
 TEST(AutofillFieldTest, IsFieldFillable) {
   AutofillField field;
-  ASSERT_EQ(UNKNOWN_TYPE, field.Type().server_type());
+  ASSERT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
 
   // Type is unknown.
   EXPECT_FALSE(field.IsFieldFillable());
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index dded980..4c66699 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -1075,7 +1075,7 @@
     std::vector<int>* unique_ids) const {
   std::vector<ServerFieldType> field_types(form->field_count());
   for (size_t i = 0; i < form->field_count(); ++i) {
-    field_types.push_back(form->field(i)->Type().server_type());
+    field_types.push_back(form->field(i)->Type().GetStorableType());
   }
   std::vector<GUIDPair> guid_pairs;
 
diff --git a/components/autofill/core/browser/autofill_manager_delegate.h b/components/autofill/core/browser/autofill_manager_delegate.h
index 9847f6b..374c105 100644
--- a/components/autofill/core/browser/autofill_manager_delegate.h
+++ b/components/autofill/core/browser/autofill_manager_delegate.h
@@ -96,8 +96,9 @@
   // Causes the Autocheckout bubble UI to be displayed. |bounding_box| is the
   // anchor for the bubble. |is_google_user| is whether or not the user is
   // logged into or has been logged into accounts.google.com. |callback| is run
-  // if the bubble is accepted.
-  virtual void ShowAutocheckoutBubble(
+  // if the bubble is accepted. The returned boolean informs the caller whether
+  // or not the bubble is successfully shown.
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounding_box,
       bool is_google_user,
       const base::Callback<void(AutocheckoutBubbleState)>& callback) = 0;
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 8c2a8ef..e69ed0f 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -522,7 +522,7 @@
                  expected_submitted_field_types_[i].begin();
              it != expected_submitted_field_types_[i].end(); ++it) {
           EXPECT_TRUE(possible_types.count(*it))
-              << "Expected type: " << AutofillType::FieldTypeToString(*it);
+              << "Expected type: " << AutofillType(*it).ToString();
         }
       }
     }
@@ -2652,7 +2652,7 @@
   std::vector<ServerFieldType> heuristic_types, server_types;
   for (size_t i = 0; i < form.fields.size(); ++i) {
     heuristic_types.push_back(UNKNOWN_TYPE);
-    server_types.push_back(form_structure->field(i)->Type().server_type());
+    server_types.push_back(form_structure->field(i)->heuristic_type());
   }
   form_structure->SetFieldTypes(heuristic_types, server_types);
   autofill_manager_->AddSeenForm(form_structure);
@@ -3113,12 +3113,13 @@
 
   virtual ~MockAutofillManagerDelegate() {}
 
-  virtual void ShowAutocheckoutBubble(
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounds,
       bool is_google_user,
       const base::Callback<void(AutocheckoutBubbleState)>& callback) OVERRIDE {
     autocheckout_bubble_shown_ = true;
     callback.Run(AUTOCHECKOUT_BUBBLE_ACCEPTED);
+    return true;
   }
 
   virtual void ShowRequestAutocompleteDialog(
@@ -3166,7 +3167,7 @@
   std::vector<ServerFieldType> heuristic_types, server_types;
   for (size_t i = 0; i < form.fields.size(); ++i) {
     heuristic_types.push_back(UNKNOWN_TYPE);
-    server_types.push_back(form_structure->field(i)->Type().server_type());
+    server_types.push_back(form_structure->field(i)->heuristic_type());
   }
   form_structure->SetFieldTypes(heuristic_types, server_types);
   autofill_manager_->AddSeenForm(form_structure);
@@ -3195,7 +3196,7 @@
   // Build form structure without server data.
   std::vector<ServerFieldType> heuristic_types, server_types;
   for (size_t i = 0; i < form.fields.size(); ++i) {
-    heuristic_types.push_back(form_structure->field(i)->Type().server_type());
+    heuristic_types.push_back(form_structure->field(i)->heuristic_type());
     server_types.push_back(NO_SERVER_DATA);
   }
   form_structure->SetFieldTypes(heuristic_types, server_types);
@@ -3240,7 +3241,7 @@
   std::vector<ServerFieldType> heuristic_types, server_types;
   for (size_t i = 0; i < address.fields.size(); ++i) {
     heuristic_types.push_back(UNKNOWN_TYPE);
-    server_types.push_back(form_structure->field(i)->Type().server_type());
+    server_types.push_back(form_structure->field(i)->heuristic_type());
   }
   form_structure->SetFieldTypes(heuristic_types, server_types);
   autofill_manager_->AddSeenForm(form_structure.release());
diff --git a/components/autofill/core/browser/autofill_merge_unittest.cc b/components/autofill/core/browser/autofill_merge_unittest.cc
index e13f494..21918d7 100644
--- a/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -67,7 +67,7 @@
       std::vector<base::string16> values;
       profiles[i]->GetRawMultiInfo(type, &values);
       for (size_t k = 0; k < values.size(); ++k) {
-        result += AutofillType::FieldTypeToString(type);
+        result += AutofillType(type).ToString();
         result += kFieldSeparator;
         result += UTF16ToUTF8(values[k]);
         result += "\n";
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index f1577ed..6e18011 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -30,14 +30,14 @@
 namespace autofill {
 namespace {
 
-// Like |AutofillType::GetEquivalentFieldType()|, but also returns |NAME_FULL|
-// for first, middle, and last name field types.
-ServerFieldType GetEquivalentFieldTypeCollapsingNames(ServerFieldType type) {
-  if (type == NAME_FIRST || type == NAME_MIDDLE || type == NAME_LAST ||
-      type == NAME_MIDDLE_INITIAL)
+// Like |AutofillType::GetStorableType()|, but also returns |NAME_FULL| for
+// first, middle, and last name field types.
+ServerFieldType GetStorableTypeCollapsingNames(ServerFieldType type) {
+  ServerFieldType storable_type = AutofillType(type).GetStorableType();
+  if (AutofillType(storable_type).group() == NAME)
     return NAME_FULL;
 
-  return AutofillType::GetEquivalentFieldType(type);
+  return storable_type;
 }
 
 // Fills |distinguishing_fields| with a list of fields to use when creating
@@ -76,13 +76,13 @@
   // Always ignore fields of unknown type and the excluded field.
   std::set<ServerFieldType> seen_fields;
   seen_fields.insert(UNKNOWN_TYPE);
-  seen_fields.insert(GetEquivalentFieldTypeCollapsingNames(excluded_field));
+  seen_fields.insert(GetStorableTypeCollapsingNames(excluded_field));
 
   distinguishing_fields->clear();
   for (std::vector<ServerFieldType>::const_iterator it =
            suggested_fields->begin();
        it != suggested_fields->end(); ++it) {
-    ServerFieldType suggested_type = GetEquivalentFieldTypeCollapsingNames(*it);
+    ServerFieldType suggested_type = GetStorableTypeCollapsingNames(*it);
     if (seen_fields.insert(suggested_type).second)
       distinguishing_fields->push_back(suggested_type);
   }
@@ -92,12 +92,12 @@
   // list of distinguishing fields as a last-ditch fallback. This allows us to
   // distinguish between profiles that are identical except for the name.
   if (excluded_field != NAME_FULL &&
-      GetEquivalentFieldTypeCollapsingNames(excluded_field) == NAME_FULL) {
+      GetStorableTypeCollapsingNames(excluded_field) == NAME_FULL) {
     for (std::vector<ServerFieldType>::const_iterator it =
              suggested_fields->begin();
          it != suggested_fields->end(); ++it) {
       if (*it != excluded_field &&
-          GetEquivalentFieldTypeCollapsingNames(*it) == NAME_FULL) {
+          GetStorableTypeCollapsingNames(*it) == NAME_FULL) {
         distinguishing_fields->push_back(NAME_FULL);
         break;
       }
@@ -124,7 +124,7 @@
                                 const AutofillType& type,
                                 const std::string& app_locale) {
   return app_locale.empty() ?
-      form_group.GetRawInfo(type.server_type()) :
+      form_group.GetRawInfo(type.GetStorableType()) :
       form_group.GetInfo(type, app_locale);
 }
 
@@ -275,12 +275,11 @@
 }
 
 base::string16 AutofillProfile::GetRawInfo(ServerFieldType type) const {
-  ServerFieldType return_type = AutofillType::GetEquivalentFieldType(type);
-  const FormGroup* form_group = FormGroupForType(AutofillType(return_type));
+  const FormGroup* form_group = FormGroupForType(AutofillType(type));
   if (!form_group)
     return base::string16();
 
-  return form_group->GetRawInfo(return_type);
+  return form_group->GetRawInfo(type);
 }
 
 void AutofillProfile::SetRawInfo(ServerFieldType type,
@@ -292,13 +291,11 @@
 
 base::string16 AutofillProfile::GetInfo(const AutofillType& type,
                                         const std::string& app_locale) const {
-  ServerFieldType return_type =
-      AutofillType::GetEquivalentFieldType(type.server_type());
-  const FormGroup* form_group = FormGroupForType(AutofillType(return_type));
+  const FormGroup* form_group = FormGroupForType(type);
   if (!form_group)
     return base::string16();
 
-  return form_group->GetInfo(AutofillType(return_type), app_locale);
+  return form_group->GetInfo(type, app_locale);
 }
 
 bool AutofillProfile::SetInfo(const AutofillType& type,
@@ -363,8 +360,7 @@
   DCHECK_NE(CREDIT_CARD, type.group());
   DCHECK(field_data);
 
-  if (type.server_type() == PHONE_HOME_NUMBER ||
-      type.server_type() == PHONE_BILLING_NUMBER) {
+  if (type.GetStorableType() == PHONE_HOME_NUMBER) {
     FillPhoneNumberField(field, variant, app_locale, field_data);
   } else if (field_data->form_control_type == "select-one") {
     FillSelectControl(type, app_locale, field_data);
diff --git a/components/autofill/core/browser/autofill_type.cc b/components/autofill/core/browser/autofill_type.cc
index 14eeee0..c47a9df 100644
--- a/components/autofill/core/browser/autofill_type.cc
+++ b/components/autofill/core/browser/autofill_type.cc
@@ -4,13 +4,13 @@
 
 #include "components/autofill/core/browser/autofill_type.h"
 
-#include <ostream>
-
 #include "base/logging.h"
 
 namespace autofill {
 
-AutofillType::AutofillType(ServerFieldType field_type) {
+AutofillType::AutofillType(ServerFieldType field_type)
+    : html_type_(HTML_TYPE_UNKNOWN),
+      html_mode_(HTML_MODE_NONE) {
   if ((field_type < NO_SERVER_DATA || field_type >= MAX_VALID_FIELD_TYPE) ||
       (field_type >= 15 && field_type <= 19) ||
       (field_type >= 25 && field_type <= 29) ||
@@ -21,13 +21,23 @@
   }
 }
 
+AutofillType::AutofillType(HtmlFieldType field_type, HtmlFieldMode mode)
+    : server_type_(UNKNOWN_TYPE),
+      html_type_(field_type),
+      html_mode_(mode) {}
+
+
 AutofillType::AutofillType(const AutofillType& autofill_type) {
   *this = autofill_type;
 }
 
 AutofillType& AutofillType::operator=(const AutofillType& autofill_type) {
-  if (this != &autofill_type)
+  if (this != &autofill_type) {
     this->server_type_ = autofill_type.server_type_;
+    this->html_type_ = autofill_type.html_type_;
+    this->html_mode_ = autofill_type.html_mode_;
+  }
+
   return *this;
 }
 
@@ -98,17 +108,83 @@
     case COMPANY_NAME:
       return COMPANY;
 
-    default:
+    case NO_SERVER_DATA:
+    case EMPTY_TYPE:
+    case PHONE_FAX_NUMBER:
+    case PHONE_FAX_CITY_CODE:
+    case PHONE_FAX_COUNTRY_CODE:
+    case PHONE_FAX_CITY_AND_NUMBER:
+    case PHONE_FAX_WHOLE_NUMBER:
+    case FIELD_WITH_DEFAULT_VALUE:
       return NO_GROUP;
+
+    case MAX_VALID_FIELD_TYPE:
+      NOTREACHED();
+      return NO_GROUP;
+
+    case UNKNOWN_TYPE:
+      break;
   }
+
+  switch (html_type_) {
+    case HTML_TYPE_NAME:
+    case HTML_TYPE_GIVEN_NAME:
+    case HTML_TYPE_ADDITIONAL_NAME:
+    case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
+    case HTML_TYPE_FAMILY_NAME:
+      return html_mode_ == HTML_MODE_BILLING ? NAME_BILLING : NAME;
+
+    case HTML_TYPE_ORGANIZATION:
+      return COMPANY;
+
+    case HTML_TYPE_ADDRESS_LINE1:
+    case HTML_TYPE_ADDRESS_LINE2:
+    case HTML_TYPE_LOCALITY:
+    case HTML_TYPE_REGION:
+    case HTML_TYPE_COUNTRY_CODE:
+    case HTML_TYPE_COUNTRY_NAME:
+    case HTML_TYPE_POSTAL_CODE:
+      return html_mode_ == HTML_MODE_BILLING ? ADDRESS_BILLING : ADDRESS_HOME;
+
+    case HTML_TYPE_CREDIT_CARD_NAME:
+    case HTML_TYPE_CREDIT_CARD_NUMBER:
+    case HTML_TYPE_CREDIT_CARD_EXP:
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+    case HTML_TYPE_CREDIT_CARD_EXP_MONTH:
+    case HTML_TYPE_CREDIT_CARD_EXP_YEAR:
+    case HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR:
+    case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR:
+    case HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE:
+    case HTML_TYPE_CREDIT_CARD_TYPE:
+      return CREDIT_CARD;
+
+    case HTML_TYPE_TEL:
+    case HTML_TYPE_TEL_COUNTRY_CODE:
+    case HTML_TYPE_TEL_NATIONAL:
+    case HTML_TYPE_TEL_AREA_CODE:
+    case HTML_TYPE_TEL_LOCAL:
+    case HTML_TYPE_TEL_LOCAL_PREFIX:
+    case HTML_TYPE_TEL_LOCAL_SUFFIX:
+      return html_mode_ == HTML_MODE_BILLING ? PHONE_BILLING : PHONE_HOME;
+
+    case HTML_TYPE_EMAIL:
+      return EMAIL;
+
+    case HTML_TYPE_UNKNOWN:
+      break;
+  }
+
+  return NO_GROUP;
 }
 
-// static
-ServerFieldType AutofillType::GetEquivalentFieldType(
-    ServerFieldType field_type) {
-  // When billing information is requested from the profile we map to the
-  // home address equivalents.
-  switch (field_type) {
+bool AutofillType::IsUnknown() const {
+  return server_type_ == UNKNOWN_TYPE && html_type_ == HTML_TYPE_UNKNOWN;
+}
+
+ServerFieldType AutofillType::GetStorableType() const {
+  // Map billing types to the equivalent non-billing types.
+  switch (server_type_) {
     case ADDRESS_BILLING_LINE1:
       return ADDRESS_HOME_LINE1;
 
@@ -163,9 +239,110 @@
     case NAME_BILLING_SUFFIX:
       return NAME_SUFFIX;
 
+    case UNKNOWN_TYPE:
+      break;  // Try to parse HTML types instead.
+
     default:
-      return field_type;
+      return server_type_;
   }
+
+  switch (html_type_) {
+    case HTML_TYPE_UNKNOWN:
+      return UNKNOWN_TYPE;
+
+    case HTML_TYPE_NAME:
+      return NAME_FULL;
+
+    case HTML_TYPE_GIVEN_NAME:
+      return NAME_FIRST;
+
+    case HTML_TYPE_ADDITIONAL_NAME:
+      return NAME_MIDDLE;
+
+    case HTML_TYPE_FAMILY_NAME:
+      return NAME_LAST;
+
+    case HTML_TYPE_ORGANIZATION:
+      return COMPANY_NAME;
+
+    case HTML_TYPE_ADDRESS_LINE1:
+      return ADDRESS_HOME_LINE1;
+
+    case HTML_TYPE_ADDRESS_LINE2:
+      return ADDRESS_HOME_LINE2;
+
+    case HTML_TYPE_LOCALITY:
+      return ADDRESS_HOME_CITY;
+
+    case HTML_TYPE_REGION:
+      return ADDRESS_HOME_STATE;
+
+    case HTML_TYPE_COUNTRY_CODE:
+    case HTML_TYPE_COUNTRY_NAME:
+      return ADDRESS_HOME_COUNTRY;
+
+    case HTML_TYPE_POSTAL_CODE:
+      return ADDRESS_HOME_ZIP;
+
+    case HTML_TYPE_CREDIT_CARD_NAME:
+      return CREDIT_CARD_NAME;
+
+    case HTML_TYPE_CREDIT_CARD_NUMBER:
+      return CREDIT_CARD_NUMBER;
+
+    case HTML_TYPE_CREDIT_CARD_EXP:
+      return CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_MONTH:
+      return CREDIT_CARD_EXP_MONTH;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_YEAR:
+      return CREDIT_CARD_EXP_4_DIGIT_YEAR;
+
+    case HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE:
+      return CREDIT_CARD_VERIFICATION_CODE;
+
+    case HTML_TYPE_CREDIT_CARD_TYPE:
+      return CREDIT_CARD_TYPE;
+
+    case HTML_TYPE_TEL:
+      return PHONE_HOME_WHOLE_NUMBER;
+
+    case HTML_TYPE_TEL_COUNTRY_CODE:
+      return PHONE_HOME_COUNTRY_CODE;
+
+    case HTML_TYPE_TEL_NATIONAL:
+      return PHONE_HOME_CITY_AND_NUMBER;
+
+    case HTML_TYPE_TEL_AREA_CODE:
+      return PHONE_HOME_CITY_CODE;
+
+    case HTML_TYPE_TEL_LOCAL:
+    case HTML_TYPE_TEL_LOCAL_PREFIX:
+    case HTML_TYPE_TEL_LOCAL_SUFFIX:
+      return PHONE_HOME_NUMBER;
+
+    case HTML_TYPE_EMAIL:
+      return EMAIL_ADDRESS;
+
+    case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
+      return NAME_MIDDLE_INITIAL;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+      return CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+      return CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR:
+      return CREDIT_CARD_EXP_2_DIGIT_YEAR;
+
+    case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR:
+      return CREDIT_CARD_EXP_4_DIGIT_YEAR;
+  }
+
+  NOTREACHED();
+  return UNKNOWN_TYPE;
 }
 
 // static
@@ -231,13 +408,15 @@
   }
 }
 
-// static
-std::string AutofillType::FieldTypeToString(ServerFieldType type) {
-  switch (type) {
+std::string AutofillType::ToString() const {
+  if (IsUnknown())
+    return "UNKNOWN_TYPE";
+
+  switch (server_type_) {
     case NO_SERVER_DATA:
       return "NO_SERVER_DATA";
     case UNKNOWN_TYPE:
-      return "UNKNOWN_TYPE";
+      break;  // Should be handled in the HTML type handling code below.
     case EMPTY_TYPE:
       return "EMPTY_TYPE";
     case NAME_FIRST:
@@ -349,6 +528,78 @@
     case MAX_VALID_FIELD_TYPE:
       return std::string();
   }
+
+  switch (html_type_) {
+    case HTML_TYPE_UNKNOWN:
+      NOTREACHED();
+      break;
+    case HTML_TYPE_NAME:
+      return "HTML_TYPE_NAME";
+    case HTML_TYPE_GIVEN_NAME:
+      return "HTML_TYPE_GIVEN_NAME";
+    case HTML_TYPE_ADDITIONAL_NAME:
+      return "HTML_TYPE_ADDITIONAL_NAME";
+    case HTML_TYPE_FAMILY_NAME:
+      return "HTML_TYPE_FAMILY_NAME";
+    case HTML_TYPE_ORGANIZATION:
+      return "HTML_TYPE_ORGANIZATION";
+    case HTML_TYPE_ADDRESS_LINE1:
+      return "HTML_TYPE_ADDRESS_LINE1";
+    case HTML_TYPE_ADDRESS_LINE2:
+      return "HTML_TYPE_ADDRESS_LINE2";
+    case HTML_TYPE_LOCALITY:
+      return "HTML_TYPE_LOCALITY";
+    case HTML_TYPE_REGION:
+      return "HTML_TYPE_REGION";
+    case HTML_TYPE_COUNTRY_CODE:
+      return "HTML_TYPE_COUNTRY_CODE";
+    case HTML_TYPE_COUNTRY_NAME:
+      return "HTML_TYPE_COUNTRY_NAME";
+    case HTML_TYPE_POSTAL_CODE:
+      return "HTML_TYPE_POSTAL_CODE";
+    case HTML_TYPE_CREDIT_CARD_NAME:
+      return "HTML_TYPE_CREDIT_CARD_NAME";
+    case HTML_TYPE_CREDIT_CARD_NUMBER:
+      return "HTML_TYPE_CREDIT_CARD_NUMBER";
+    case HTML_TYPE_CREDIT_CARD_EXP:
+      return "HTML_TYPE_CREDIT_CARD_EXP";
+    case HTML_TYPE_CREDIT_CARD_EXP_MONTH:
+      return "HTML_TYPE_CREDIT_CARD_EXP_MONTH";
+    case HTML_TYPE_CREDIT_CARD_EXP_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_YEAR";
+    case HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE:
+      return "HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE";
+    case HTML_TYPE_CREDIT_CARD_TYPE:
+      return "HTML_TYPE_CREDIT_CARD_TYPE";
+    case HTML_TYPE_TEL:
+      return "HTML_TYPE_TEL";
+    case HTML_TYPE_TEL_COUNTRY_CODE:
+      return "HTML_TYPE_TEL_COUNTRY_CODE";
+    case HTML_TYPE_TEL_NATIONAL:
+      return "HTML_TYPE_TEL_NATIONAL";
+    case HTML_TYPE_TEL_AREA_CODE:
+      return "HTML_TYPE_TEL_AREA_CODE";
+    case HTML_TYPE_TEL_LOCAL:
+      return "HTML_TYPE_TEL_LOCAL";
+    case HTML_TYPE_TEL_LOCAL_PREFIX:
+      return "HTML_TYPE_TEL_LOCAL_PREFIX";
+    case HTML_TYPE_TEL_LOCAL_SUFFIX:
+      return "HTML_TYPE_TEL_LOCAL_SUFFIX";
+    case HTML_TYPE_EMAIL:
+      return "HTML_TYPE_EMAIL";
+    case HTML_TYPE_ADDITIONAL_NAME_INITIAL:
+      return "HTML_TYPE_ADDITIONAL_NAME_INITIAL";
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR";
+    case HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR:
+      return "HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR";
+  }
+
+  NOTREACHED();
   return std::string();
 }
 
diff --git a/components/autofill/core/browser/autofill_type.h b/components/autofill/core/browser/autofill_type.h
index a7d243c..653c023 100644
--- a/components/autofill/core/browser/autofill_type.h
+++ b/components/autofill/core/browser/autofill_type.h
@@ -16,31 +16,45 @@
 class AutofillType {
  public:
   explicit AutofillType(ServerFieldType field_type);
+  AutofillType(HtmlFieldType field_type, HtmlFieldMode mode);
   AutofillType(const AutofillType& autofill_type);
   AutofillType& operator=(const AutofillType& autofill_type);
 
-  // TODO(isherman): Audit all uses of this method.
-  ServerFieldType server_type() const { return server_type_; }
   FieldTypeGroup group() const;
 
-  // Maps |field_type| to a field type that can be directly stored in a profile
-  // (in the sense that it makes sense to call |AutofillProfile::SetInfo()| with
-  // the returned field type as the first parameter).
-  static ServerFieldType GetEquivalentFieldType(ServerFieldType field_type);
+  // Returns true if both the |server_type_| and the |html_type_| are set to
+  // their respective enum's unknown value.
+  bool IsUnknown() const;
+
+  // Maps |this| type to a field type that can be directly stored in an Autofill
+  // data model (in the sense that it makes sense to call
+  // |AutofillDataModel::SetRawInfo()| with the returned field type as the first
+  // parameter).
+  ServerFieldType GetStorableType() const;
+
+  // Serializes |this| type to a string.
+  std::string ToString() const;
 
   // Maps |field_type| to a field type from ADDRESS_BILLING FieldTypeGroup if
   // field type is an Address type.
+  // TODO(isherman): This method is only used by the
+  // AutofillDialogControllerImpl class.  Consider moving it to a more focused
+  // location.
   static ServerFieldType GetEquivalentBillingFieldType(
       ServerFieldType field_type);
 
-  // Utilities for serializing and deserializing a |ServerFieldType|.
-  // TODO(isherman): This should probably serialize an HTML type as well.
-  //                 Audit all uses of these functions.
-  static std::string FieldTypeToString(ServerFieldType field_type);
+  // TODO(isherman): This method is only used be a single test class.  Move the
+  // logic into there or something, eh?
   static ServerFieldType StringToFieldType(const std::string& str);
 
  private:
+  // The server-native field type, or UNKNOWN_TYPE if unset.
   ServerFieldType server_type_;
+
+  // The HTML autocomplete field type and mode hints, or HTML_TYPE_UNKNOWN and
+  // HTML_MODE_NONE if unset.
+  HtmlFieldType html_type_;
+  HtmlFieldMode html_mode_;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_type_unittest.cc b/components/autofill/core/browser/autofill_type_unittest.cc
index d9e8f9e..71e98b4 100644
--- a/components/autofill/core/browser/autofill_type_unittest.cc
+++ b/components/autofill/core/browser/autofill_type_unittest.cc
@@ -8,47 +8,84 @@
 namespace autofill {
 namespace {
 
-TEST(AutofillTypeTest, AutofillTypes) {
+TEST(AutofillTypeTest, ServerFieldTypes) {
   // No server data.
   AutofillType none(NO_SERVER_DATA);
-  EXPECT_EQ(NO_SERVER_DATA, none.server_type());
+  EXPECT_EQ(NO_SERVER_DATA, none.GetStorableType());
   EXPECT_EQ(NO_GROUP, none.group());
 
   // Unknown type.
   AutofillType unknown(UNKNOWN_TYPE);
-  EXPECT_EQ(UNKNOWN_TYPE, unknown.server_type());
+  EXPECT_EQ(UNKNOWN_TYPE, unknown.GetStorableType());
   EXPECT_EQ(NO_GROUP, unknown.group());
 
   // Type with group but no subgroup.
   AutofillType first(NAME_FIRST);
-  EXPECT_EQ(NAME_FIRST, first.server_type());
+  EXPECT_EQ(NAME_FIRST, first.GetStorableType());
   EXPECT_EQ(NAME, first.group());
 
   // Type with group and subgroup.
   AutofillType phone(PHONE_HOME_NUMBER);
-  EXPECT_EQ(PHONE_HOME_NUMBER, phone.server_type());
+  EXPECT_EQ(PHONE_HOME_NUMBER, phone.GetStorableType());
   EXPECT_EQ(PHONE_HOME, phone.group());
 
+  // Billing type.
+  AutofillType billing_address(ADDRESS_BILLING_LINE1);
+  EXPECT_EQ(ADDRESS_HOME_LINE1, billing_address.GetStorableType());
+  EXPECT_EQ(ADDRESS_BILLING, billing_address.group());
+
   // Last value, to check any offset errors.
-  AutofillType last(COMPANY_NAME);
-  EXPECT_EQ(COMPANY_NAME, last.server_type());
-  EXPECT_EQ(COMPANY, last.group());
+  AutofillType last(NAME_BILLING_SUFFIX);
+  EXPECT_EQ(NAME_SUFFIX, last.GetStorableType());
+  EXPECT_EQ(NAME_BILLING, last.group());
 
   // Boundary (error) condition.
   AutofillType boundary(MAX_VALID_FIELD_TYPE);
-  EXPECT_EQ(UNKNOWN_TYPE, boundary.server_type());
+  EXPECT_EQ(UNKNOWN_TYPE, boundary.GetStorableType());
   EXPECT_EQ(NO_GROUP, boundary.group());
 
   // Beyond the boundary (error) condition.
-  AutofillType beyond(static_cast<ServerFieldType>(MAX_VALID_FIELD_TYPE+10));
-  EXPECT_EQ(UNKNOWN_TYPE, beyond.server_type());
+  AutofillType beyond(static_cast<ServerFieldType>(MAX_VALID_FIELD_TYPE + 10));
+  EXPECT_EQ(UNKNOWN_TYPE, beyond.GetStorableType());
   EXPECT_EQ(NO_GROUP, beyond.group());
 
   // In-between value.  Missing from enum but within range.  Error condition.
   AutofillType between(static_cast<ServerFieldType>(16));
-  EXPECT_EQ(UNKNOWN_TYPE, between.server_type());
+  EXPECT_EQ(UNKNOWN_TYPE, between.GetStorableType());
   EXPECT_EQ(NO_GROUP, between.group());
 }
 
+TEST(AutofillTypeTest, HtmlFieldTypes) {
+  // Unknown type.
+  AutofillType unknown(HTML_TYPE_UNKNOWN, HTML_MODE_NONE);
+  EXPECT_EQ(UNKNOWN_TYPE, unknown.GetStorableType());
+  EXPECT_EQ(NO_GROUP, unknown.group());
+
+  // Type with group but no subgroup.
+  AutofillType first(HTML_TYPE_GIVEN_NAME, HTML_MODE_NONE);
+  EXPECT_EQ(NAME_FIRST, first.GetStorableType());
+  EXPECT_EQ(NAME, first.group());
+
+  // Type with group and subgroup.
+  AutofillType phone(HTML_TYPE_TEL, HTML_MODE_NONE);
+  EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, phone.GetStorableType());
+  EXPECT_EQ(PHONE_HOME, phone.group());
+
+  // Last value, to check any offset errors.
+  AutofillType last(HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR, HTML_MODE_NONE);
+  EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR, last.GetStorableType());
+  EXPECT_EQ(CREDIT_CARD, last.group());
+
+  // Shipping mode.
+  AutofillType shipping_first(HTML_TYPE_GIVEN_NAME, HTML_MODE_SHIPPING);
+  EXPECT_EQ(NAME_FIRST, shipping_first.GetStorableType());
+  EXPECT_EQ(NAME, shipping_first.group());
+
+  // Billing mode.
+  AutofillType billing_first(HTML_TYPE_GIVEN_NAME, HTML_MODE_BILLING);
+  EXPECT_EQ(NAME_FIRST, billing_first.GetStorableType());
+  EXPECT_EQ(NAME_BILLING, billing_first.group());
+}
+
 }  // namespace
 }  // namespace autofill
diff --git a/components/autofill/core/browser/contact_info.cc b/components/autofill/core/browser/contact_info.cc
index 7ecf44d..603c4fa 100644
--- a/components/autofill/core/browser/contact_info.cc
+++ b/components/autofill/core/browser/contact_info.cc
@@ -52,38 +52,53 @@
 }
 
 base::string16 NameInfo::GetRawInfo(ServerFieldType type) const {
-  type = AutofillType::GetEquivalentFieldType(type);
-  if (type == NAME_FIRST)
-    return first();
+  // TODO(isherman): Is GetStorableType even necessary?
+  switch (AutofillType(type).GetStorableType()) {
+    case NAME_FIRST:
+      return first();
 
-  if (type == NAME_MIDDLE)
-    return middle();
+    case NAME_MIDDLE:
+      return middle();
 
-  if (type == NAME_LAST)
-    return last();
+    case NAME_LAST:
+      return last();
 
-  if (type == NAME_MIDDLE_INITIAL)
-    return MiddleInitial();
+    case NAME_MIDDLE_INITIAL:
+      return MiddleInitial();
 
-  if (type == NAME_FULL)
-    return FullName();
+    case NAME_FULL:
+      return FullName();
 
-  return base::string16();
+    default:
+      return base::string16();
+  }
 }
 
 void NameInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
-  type = AutofillType::GetEquivalentFieldType(type);
-  DCHECK_EQ(NAME, AutofillType(type).group());
-  if (type == NAME_FIRST)
-    first_ = value;
-  else if (type == NAME_MIDDLE || type == NAME_MIDDLE_INITIAL)
-    middle_ = value;
-  else if (type == NAME_LAST)
-    last_ = value;
-  else if (type == NAME_FULL)
-    SetFullName(value);
-  else
-    NOTREACHED();
+  // TODO(isherman): Is GetStorableType even necessary?
+  ServerFieldType storable_type = AutofillType(type).GetStorableType();
+  DCHECK_EQ(NAME, AutofillType(storable_type).group());
+  switch (storable_type) {
+    case NAME_FIRST:
+      first_ = value;
+      break;
+
+    case NAME_MIDDLE:
+    case NAME_MIDDLE_INITIAL:
+      middle_ = value;
+      break;
+
+    case NAME_LAST:
+      last_ = value;
+      break;
+
+    case NAME_FULL:
+      SetFullName(value);
+      break;
+
+    default:
+      NOTREACHED();
+  }
 }
 
 base::string16 NameInfo::FullName() const {
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index e627207..f3ac6b1 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -371,22 +371,23 @@
 
 base::string16 CreditCard::GetInfo(const AutofillType& type,
                                    const std::string& app_locale) const {
-  if (type.server_type() == CREDIT_CARD_NUMBER)
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == CREDIT_CARD_NUMBER)
     return StripSeparators(number_);
 
-  return GetRawInfo(type.server_type());
+  return GetRawInfo(storable_type);
 }
 
 bool CreditCard::SetInfo(const AutofillType& type,
                          const base::string16& value,
                          const std::string& app_locale) {
-  ServerFieldType server_type = type.server_type();
-  if (server_type == CREDIT_CARD_NUMBER)
-    SetRawInfo(server_type, StripSeparators(value));
-  else if (server_type == CREDIT_CARD_EXP_MONTH)
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == CREDIT_CARD_NUMBER)
+    SetRawInfo(storable_type, StripSeparators(value));
+  else if (storable_type == CREDIT_CARD_EXP_MONTH)
     SetExpirationMonthFromString(value, app_locale);
   else
-    SetRawInfo(server_type, value);
+    SetRawInfo(storable_type, value);
 
   return true;
 }
diff --git a/components/autofill/core/browser/field_types.h b/components/autofill/core/browser/field_types.h
index c083b39..dc86ffd 100644
--- a/components/autofill/core/browser/field_types.h
+++ b/components/autofill/core/browser/field_types.h
@@ -105,6 +105,70 @@
   MAX_VALID_FIELD_TYPE = 73,
 };
 
+// The list of all HTML autocomplete field type hints supported by Chrome.
+// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
+enum HtmlFieldType {
+  // Default type.
+  HTML_TYPE_UNKNOWN,
+
+  // Name types.
+  HTML_TYPE_NAME,
+  HTML_TYPE_GIVEN_NAME,
+  HTML_TYPE_ADDITIONAL_NAME,
+  HTML_TYPE_FAMILY_NAME,
+
+  // Business types.
+  HTML_TYPE_ORGANIZATION,
+
+  // Address types.
+  HTML_TYPE_ADDRESS_LINE1,
+  HTML_TYPE_ADDRESS_LINE2,
+  HTML_TYPE_LOCALITY,      // For U.S. addresses, corresponds to the city.
+  HTML_TYPE_REGION,        // For U.S. addresses, corresponds to the state.
+  HTML_TYPE_COUNTRY_CODE,  // The ISO 3166-1-alpha-2 country code.
+  HTML_TYPE_COUNTRY_NAME,  // The localized country name.
+  HTML_TYPE_POSTAL_CODE,
+
+  // Credit card types.
+  HTML_TYPE_CREDIT_CARD_NAME,
+  HTML_TYPE_CREDIT_CARD_NUMBER,
+  HTML_TYPE_CREDIT_CARD_EXP,
+  HTML_TYPE_CREDIT_CARD_EXP_MONTH,
+  HTML_TYPE_CREDIT_CARD_EXP_YEAR,
+  HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE,
+  HTML_TYPE_CREDIT_CARD_TYPE,
+
+  // Phone number types.
+  HTML_TYPE_TEL,
+  HTML_TYPE_TEL_COUNTRY_CODE,
+  HTML_TYPE_TEL_NATIONAL,
+  HTML_TYPE_TEL_AREA_CODE,
+  HTML_TYPE_TEL_LOCAL,
+  HTML_TYPE_TEL_LOCAL_PREFIX,
+  HTML_TYPE_TEL_LOCAL_SUFFIX,
+
+  // Email.
+  HTML_TYPE_EMAIL,
+
+  // Variants of type hints specified in the HTML specification that are
+  // inferred based on a field's 'maxlength' attribute.
+  // TODO(isherman): Remove these types, in favor of understanding maxlength
+  // when filling fields.  See also: AutofillField::phone_part_.
+  HTML_TYPE_ADDITIONAL_NAME_INITIAL,
+  HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
+  HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR,
+  HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR,
+  HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR,
+};
+
+// The list of all HTML autocomplete field mode hints supported by Chrome.
+// See [ http://is.gd/whatwg_autocomplete ] for the full list of specced hints.
+enum HtmlFieldMode {
+  HTML_MODE_NONE,
+  HTML_MODE_BILLING,
+  HTML_MODE_SHIPPING,
+};
+
 enum FieldTypeGroup {
   NO_GROUP,
   NAME,
diff --git a/components/autofill/core/browser/form_group.cc b/components/autofill/core/browser/form_group.cc
index 7114ee2..17eb036 100644
--- a/components/autofill/core/browser/form_group.cc
+++ b/components/autofill/core/browser/form_group.cc
@@ -38,13 +38,13 @@
 
 base::string16 FormGroup::GetInfo(const AutofillType& type,
                                   const std::string& app_locale) const {
-  return GetRawInfo(type.server_type());
+  return GetRawInfo(type.GetStorableType());
 }
 
 bool FormGroup::SetInfo(const AutofillType& type,
                         const base::string16& value,
                         const std::string& app_locale) {
-  SetRawInfo(type.server_type(), value);
+  SetRawInfo(type.GetStorableType(), value);
   return true;
 }
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index d502a0d..fd907dc 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -57,8 +57,8 @@
 const char kXMLElementField[] = "field";
 const char kXMLElementFields[] = "fields";
 const char kXMLElementForm[] = "form";
-const char kBillingSection[] = "billing";
-const char kShippingSection[] = "shipping";
+const char kBillingMode[] = "billing";
+const char kShippingMode[] = "shipping";
 
 // Stip away >= 5 consecutive digits.
 const char kIgnorePatternInFieldName[] = "\\d{5,}+";
@@ -165,130 +165,132 @@
 // Returns |true| iff the |token| is a type hint appropriate for a field of the
 // given |field_type|, as specified in the implementation section of
 // http://is.gd/whatwg_autocomplete
-// TODO(isherman): This should use HTML field types, not native ones.
 bool ContactTypeHintMatchesFieldType(const std::string& token,
-                                     ServerFieldType field_type) {
+                                     HtmlFieldType field_type) {
   // The "home" and "work" type hints are only appropriate for email and phone
   // number field types.
   if (token == "home" || token == "work") {
-    return field_type == EMAIL_ADDRESS ||
-        (field_type >= PHONE_HOME_NUMBER &&
-         field_type <= PHONE_HOME_WHOLE_NUMBER);
+    return field_type == HTML_TYPE_EMAIL ||
+        (field_type >= HTML_TYPE_TEL &&
+         field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX);
   }
 
   // The "mobile" type hint is only appropriate for phone number field types.
   // Note that "fax" and "pager" are intentionally ignored, as Chrome does not
   // support filling either type of information.
   if (token == "mobile") {
-    return field_type >= PHONE_HOME_NUMBER &&
-        field_type <= PHONE_HOME_WHOLE_NUMBER;
+    return field_type >= HTML_TYPE_TEL &&
+        field_type <= HTML_TYPE_TEL_LOCAL_SUFFIX;
   }
 
   return false;
 }
 
 // Returns the Chrome Autofill-supported field type corresponding to the given
-// |autocomplete_type|, if there is one, in the context of the given |field|.
-// Chrome Autofill supports a subset of the field types listed at
+// |autocomplete_attribute_value|, if there is one, in the context of the given
+// |field|.  Chrome Autofill supports a subset of the field types listed at
 // http://is.gd/whatwg_autocomplete
-// TODO(isherman): This should use HTML field types, not native ones.
-ServerFieldType FieldTypeFromAutocompleteType(
-    const std::string& autocomplete_type,
+HtmlFieldType FieldTypeFromAutocompleteAttributeValue(
+    const std::string& autocomplete_attribute_value,
     const AutofillField& field) {
-  if (autocomplete_type == "name")
-    return NAME_FULL;
+  if (autocomplete_attribute_value == "name")
+    return HTML_TYPE_NAME;
 
-  if (autocomplete_type == "given-name")
-    return NAME_FIRST;
+  if (autocomplete_attribute_value == "given-name")
+    return HTML_TYPE_GIVEN_NAME;
 
-  if (autocomplete_type == "additional-name") {
+  if (autocomplete_attribute_value == "additional-name") {
     if (field.max_length == 1)
-      return NAME_MIDDLE_INITIAL;
+      return HTML_TYPE_ADDITIONAL_NAME_INITIAL;
     else
-      return NAME_MIDDLE;
+      return HTML_TYPE_ADDITIONAL_NAME;
   }
 
-  if (autocomplete_type == "family-name")
-    return NAME_LAST;
+  if (autocomplete_attribute_value == "family-name")
+    return HTML_TYPE_FAMILY_NAME;
 
-  if (autocomplete_type == "honorific-suffix")
-    return NAME_SUFFIX;
+  if (autocomplete_attribute_value == "organization")
+    return HTML_TYPE_ORGANIZATION;
 
-  if (autocomplete_type == "organization")
-    return COMPANY_NAME;
+  if (autocomplete_attribute_value == "address-line1")
+    return HTML_TYPE_ADDRESS_LINE1;
 
-  if (autocomplete_type == "address-line1")
-    return ADDRESS_HOME_LINE1;
+  if (autocomplete_attribute_value == "address-line2")
+    return HTML_TYPE_ADDRESS_LINE2;
 
-  if (autocomplete_type == "address-line2")
-    return ADDRESS_HOME_LINE2;
+  if (autocomplete_attribute_value == "locality")
+    return HTML_TYPE_LOCALITY;
 
-  if (autocomplete_type == "locality")
-    return ADDRESS_HOME_CITY;
+  if (autocomplete_attribute_value == "region")
+    return HTML_TYPE_REGION;
 
-  if (autocomplete_type == "region")
-    return ADDRESS_HOME_STATE;
+  if (autocomplete_attribute_value == "country")
+    return HTML_TYPE_COUNTRY_CODE;
 
-  if (autocomplete_type == "country")
-    return ADDRESS_HOME_COUNTRY;
+  if (autocomplete_attribute_value == "country-name")
+    return HTML_TYPE_COUNTRY_NAME;
 
-  if (autocomplete_type == "postal-code")
-    return ADDRESS_HOME_ZIP;
+  if (autocomplete_attribute_value == "postal-code")
+    return HTML_TYPE_POSTAL_CODE;
 
-  if (autocomplete_type == "cc-name")
-    return CREDIT_CARD_NAME;
+  if (autocomplete_attribute_value == "cc-name")
+    return HTML_TYPE_CREDIT_CARD_NAME;
 
-  if (autocomplete_type == "cc-number")
-    return CREDIT_CARD_NUMBER;
+  if (autocomplete_attribute_value == "cc-number")
+    return HTML_TYPE_CREDIT_CARD_NUMBER;
 
-  if (autocomplete_type == "cc-exp") {
+  if (autocomplete_attribute_value == "cc-exp") {
     if (field.max_length == 5)
-      return CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
+      return HTML_TYPE_CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR;
+    else if (field.max_length == 7)
+      return HTML_TYPE_CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
     else
-      return CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
+      return HTML_TYPE_CREDIT_CARD_EXP;
   }
 
-  if (autocomplete_type == "cc-exp-month")
-    return CREDIT_CARD_EXP_MONTH;
+  if (autocomplete_attribute_value == "cc-exp-month")
+    return HTML_TYPE_CREDIT_CARD_EXP_MONTH;
 
-  if (autocomplete_type == "cc-exp-year") {
+  if (autocomplete_attribute_value == "cc-exp-year") {
     if (field.max_length == 2)
-      return CREDIT_CARD_EXP_2_DIGIT_YEAR;
+      return HTML_TYPE_CREDIT_CARD_EXP_2_DIGIT_YEAR;
+    else if (field.max_length == 4)
+      return HTML_TYPE_CREDIT_CARD_EXP_4_DIGIT_YEAR;
     else
-      return CREDIT_CARD_EXP_4_DIGIT_YEAR;
+      return HTML_TYPE_CREDIT_CARD_EXP_YEAR;
   }
 
-  if (autocomplete_type == "cc-csc")
-    return CREDIT_CARD_VERIFICATION_CODE;
+  if (autocomplete_attribute_value == "cc-csc")
+    return HTML_TYPE_CREDIT_CARD_VERIFICATION_CODE;
 
-  if (autocomplete_type == "cc-type")
-    return CREDIT_CARD_TYPE;
+  if (autocomplete_attribute_value == "cc-type")
+    return HTML_TYPE_CREDIT_CARD_TYPE;
 
-  if (autocomplete_type == "tel")
-    return PHONE_HOME_WHOLE_NUMBER;
+  if (autocomplete_attribute_value == "tel")
+    return HTML_TYPE_TEL;
 
-  if (autocomplete_type == "tel-country-code")
-    return PHONE_HOME_COUNTRY_CODE;
+  if (autocomplete_attribute_value == "tel-country-code")
+    return HTML_TYPE_TEL_COUNTRY_CODE;
 
-  if (autocomplete_type == "tel-national")
-    return PHONE_HOME_CITY_AND_NUMBER;
+  if (autocomplete_attribute_value == "tel-national")
+    return HTML_TYPE_TEL_NATIONAL;
 
-  if (autocomplete_type == "tel-area-code")
-    return PHONE_HOME_CITY_CODE;
+  if (autocomplete_attribute_value == "tel-area-code")
+    return HTML_TYPE_TEL_AREA_CODE;
 
-  if (autocomplete_type == "tel-local")
-    return PHONE_HOME_NUMBER;
+  if (autocomplete_attribute_value == "tel-local")
+    return HTML_TYPE_TEL_LOCAL;
 
-  if (autocomplete_type == "tel-local-prefix")
-    return PHONE_HOME_NUMBER;
+  if (autocomplete_attribute_value == "tel-local-prefix")
+    return HTML_TYPE_TEL_LOCAL_PREFIX;
 
-  if (autocomplete_type == "tel-local-suffix")
-    return PHONE_HOME_NUMBER;
+  if (autocomplete_attribute_value == "tel-local-suffix")
+    return HTML_TYPE_TEL_LOCAL_SUFFIX;
 
-  if (autocomplete_type == "email")
-    return EMAIL_ADDRESS;
+  if (autocomplete_attribute_value == "email")
+    return HTML_TYPE_EMAIL;
 
-  return UNKNOWN_TYPE;
+  return HTML_TYPE_UNKNOWN;
 }
 
 std::string StripDigitsIfRequired(const base::string16& input) {
@@ -377,8 +379,7 @@
   // autocomplete type hint, don't try to apply other heuristics to match fields
   // in this form.
   bool has_author_specified_sections;
-  ParseFieldTypesFromAutocompleteAttributes(PARSE_FOR_AUTOFILL,
-                                            &has_author_specified_types_,
+  ParseFieldTypesFromAutocompleteAttributes(&has_author_specified_types_,
                                             &has_author_specified_sections);
 
   if (!has_author_specified_types_) {
@@ -607,7 +608,7 @@
         heuristics_detected_fillable_field = true;
 
       (*field)->set_server_type(current_info->field_type);
-      if (heuristic_type != (*field)->Type().server_type())
+      if (heuristic_type != (*field)->Type().GetStorableType())
         query_response_overrode_heuristics = true;
 
       // Copy default value into the field if available.
@@ -659,11 +660,10 @@
       FormFieldDataPredictions annotated_field;
       annotated_field.signature = (*field)->FieldSignature();
       annotated_field.heuristic_type =
-          AutofillType::FieldTypeToString((*field)->heuristic_type());
+          AutofillType((*field)->heuristic_type()).ToString();
       annotated_field.server_type =
-          AutofillType::FieldTypeToString((*field)->server_type());
-      annotated_field.overall_type =
-          AutofillType::FieldTypeToString((*field)->Type().server_type());
+          AutofillType((*field)->server_type()).ToString();
+      annotated_field.overall_type = (*field)->Type().ToString();
       form.fields.push_back(annotated_field);
     }
 
@@ -835,7 +835,7 @@
       if (*it == PHONE_HOME_CITY_AND_NUMBER)
         collapsed_field_types.insert(PHONE_HOME_WHOLE_NUMBER);
       else
-        collapsed_field_types.insert(AutofillType::GetEquivalentFieldType(*it));
+        collapsed_field_types.insert(AutofillType(*it).GetStorableType());
     }
 
     // Capture the field's type, if it is unambiguous.
@@ -843,9 +843,11 @@
     if (collapsed_field_types.size() == 1)
       field_type = *collapsed_field_types.begin();
 
-    ServerFieldType heuristic_type = field->heuristic_type();
-    ServerFieldType server_type = field->server_type();
-    ServerFieldType predicted_type = field->Type().server_type();
+    ServerFieldType heuristic_type =
+        AutofillType(field->heuristic_type()).GetStorableType();
+    ServerFieldType server_type =
+        AutofillType(field->server_type()).GetStorableType();
+    ServerFieldType predicted_type = field->Type().GetStorableType();
 
     // Log heuristic, server, and overall type quality metrics, independently of
     // whether the field was autofilled.
@@ -1080,7 +1082,6 @@
 }
 
 void FormStructure::ParseFieldTypesFromAutocompleteAttributes(
-    ParseTarget parse_target,
     bool* found_types,
     bool* found_sections) {
   const std::string kDefaultSection = "-default";
@@ -1132,9 +1133,9 @@
     DCHECK(!tokens.empty());
     std::string field_type_token = tokens.back();
     tokens.pop_back();
-    ServerFieldType field_type =
-        FieldTypeFromAutocompleteType(field_type_token, *field);
-    if (field_type == UNKNOWN_TYPE)
+    HtmlFieldType field_type =
+        FieldTypeFromAutocompleteAttributeValue(field_type_token, *field);
+    if (field_type == HTML_TYPE_UNKNOWN)
       continue;
 
     // The preceding token, if any, may be a type hint.
@@ -1154,21 +1155,15 @@
     // section name suffixes.
     DCHECK_EQ(kDefaultSection, field->section());
     std::string section = field->section();
-    if (!tokens.empty() &&
-        (tokens.back() == kShippingSection ||
-         tokens.back() == kBillingSection)) {
-      // Set Autofill field type to billing if section is billing.
-      if (tokens.back() == kBillingSection) {
-        field_type = AutofillType::GetEquivalentBillingFieldType(field_type);
+    HtmlFieldMode mode = HTML_MODE_NONE;
+    if (!tokens.empty()) {
+      if (tokens.back() == kShippingMode)
+        mode = HTML_MODE_SHIPPING;
+      else if (tokens.back() == kBillingMode)
+        mode = HTML_MODE_BILLING;
+    }
 
-        // The Autofill dialog uses the type CREDIT_CARD_NAME to refer to both
-        // the credit card holder's name and the name on the billing address.
-        if (parse_target == PARSE_FOR_AUTOFILL_DIALOG &&
-            field_type == NAME_FULL) {
-          field_type = CREDIT_CARD_NAME;
-        }
-      }
-
+    if (mode != HTML_MODE_NONE) {
       section = "-" + tokens.back();
       tokens.pop_back();
     }
@@ -1193,11 +1188,7 @@
 
     // No errors encountered while parsing!
     // Update the |field|'s type based on what was parsed from the attribute.
-    field->set_heuristic_type(field_type);
-    if (field_type_token == "tel-local-prefix")
-      field->set_phone_part(AutofillField::PHONE_PREFIX);
-    else if (field_type_token == "tel-local-suffix")
-      field->set_phone_part(AutofillField::PHONE_SUFFIX);
+    field->SetHtmlType(field_type, mode);
   }
 }
 
@@ -1215,8 +1206,7 @@
 
     for (std::vector<AutofillField*>::iterator field = fields_.begin();
          field != fields_.end(); ++field) {
-      const ServerFieldType current_type =
-          AutofillType::GetEquivalentFieldType((*field)->Type().server_type());
+      const ServerFieldType current_type = (*field)->Type().GetStorableType();
 
       bool already_saw_current_type = seen_types.count(current_type) > 0;
 
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 8b914b1..1af7650 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -48,13 +48,6 @@
 // in the fields along with additional information needed by Autofill.
 class FormStructure {
  public:
-  // Whether the form fields should be parsed to match the semantics of plain
-  // ol' Autofill, or of the interactive Autofill dialog.
-  enum ParseTarget {
-    PARSE_FOR_AUTOFILL,
-    PARSE_FOR_AUTOFILL_DIALOG,
-  };
-
   FormStructure(const FormData& form,
                 const std::string& autocheckout_url_prefix);
   virtual ~FormStructure();
@@ -138,15 +131,12 @@
 
   // Classifies each field in |fields_| based upon its |autocomplete| attribute,
   // if the attribute is available.  The association is stored into the field's
-  // |heuristic_type|.  The exact method of classification depends on
-  // |parse_target|, as the Autofill dialog has slightly different semantics
-  // from regular ol' Autofill.
+  // |heuristic_type|.
   // Fills |found_types| with |true| if the attribute is available and neither
   // empty nor set to the special values "on" or "off" for at least one field.
   // Fills |found_sections| with |true| if the attribute specifies a section for
   // at least one field.
-  void ParseFieldTypesFromAutocompleteAttributes(ParseTarget parse_target,
-                                                 bool* found_types,
+  void ParseFieldTypesFromAutocompleteAttributes(bool* found_types,
                                                  bool* found_sections);
 
   const AutofillField* field(size_t index) const;
diff --git a/components/autofill/core/browser/form_structure_unittest.cc b/components/autofill/core/browser/form_structure_unittest.cc
index 73343f8..7d38165 100644
--- a/components/autofill/core/browser/form_structure_unittest.cc
+++ b/components/autofill/core/browser/form_structure_unittest.cc
@@ -442,9 +442,12 @@
   ASSERT_EQ(3U, form_structure->field_count());
   ASSERT_EQ(3U, form_structure->autofill_count());
 
-  EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type());
-  EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type());
-  EXPECT_EQ(EMAIL_ADDRESS, form_structure->field(2)->heuristic_type());
+  EXPECT_EQ(HTML_TYPE_GIVEN_NAME, form_structure->field(0)->html_type());
+  EXPECT_EQ(HTML_TYPE_FAMILY_NAME, form_structure->field(1)->html_type());
+  EXPECT_EQ(HTML_TYPE_EMAIL, form_structure->field(2)->html_type());
+  EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(0)->heuristic_type());
+  EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(1)->heuristic_type());
+  EXPECT_EQ(UNKNOWN_TYPE, form_structure->field(2)->heuristic_type());
 }
 
 // Verify that we can correctly process the 'autocomplete' attribute for phone
@@ -480,12 +483,12 @@
   ASSERT_EQ(3U, form_structure->field_count());
   EXPECT_EQ(3U, form_structure->autofill_count());
 
-  EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(0)->heuristic_type());
+  EXPECT_EQ(HTML_TYPE_TEL_LOCAL, form_structure->field(0)->html_type());
   EXPECT_EQ(AutofillField::IGNORED, form_structure->field(0)->phone_part());
-  EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(1)->heuristic_type());
+  EXPECT_EQ(HTML_TYPE_TEL_LOCAL_PREFIX, form_structure->field(1)->html_type());
   EXPECT_EQ(AutofillField::PHONE_PREFIX,
             form_structure->field(1)->phone_part());
-  EXPECT_EQ(PHONE_HOME_NUMBER, form_structure->field(2)->heuristic_type());
+  EXPECT_EQ(HTML_TYPE_TEL_LOCAL_SUFFIX, form_structure->field(2)->html_type());
   EXPECT_EQ(AutofillField::PHONE_SUFFIX,
             form_structure->field(2)->phone_part());
 }
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index c14723d..9ddff25 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -259,7 +259,7 @@
       continue;
 
     AutofillType field_type = field->Type();
-    ServerFieldType server_field_type = field_type.server_type();
+    ServerFieldType server_field_type = field_type.GetStorableType();
     FieldTypeGroup group(field_type.group());
 
     // There can be multiple email fields (e.g. in the case of 'confirm email'
@@ -617,8 +617,7 @@
         // Phone numbers could be split in US forms, so field value could be
         // either prefix or suffix of the phone.
         bool matched_phones = false;
-        if ((type.server_type() == PHONE_HOME_NUMBER ||
-             type.server_type() == PHONE_BILLING_NUMBER) &&
+        if (type.GetStorableType() == PHONE_HOME_NUMBER &&
             !field_value_lower_case.empty() &&
             profile_value_lower_case.find(field_value_lower_case) !=
                 base::string16::npos) {
@@ -646,7 +645,7 @@
   if (!field_is_autofilled) {
     AutofillProfile::CreateInferredLabels(
         &matched_profiles, &other_field_types,
-        type.server_type(), 1, labels);
+        type.GetStorableType(), 1, labels);
   } else {
     // No sub-labels for previously filled fields.
     labels->resize(values->size());
@@ -678,7 +677,7 @@
         credit_card->GetInfo(type, app_locale_);
     if (!creditcard_field_value.empty() &&
         StartsWith(creditcard_field_value, field_contents, false)) {
-      if (type.server_type() == CREDIT_CARD_NUMBER)
+      if (type.GetStorableType() == CREDIT_CARD_NUMBER)
         creditcard_field_value = credit_card->ObfuscatedNumber();
 
       base::string16 label;
diff --git a/components/autofill/core/browser/phone_number.cc b/components/autofill/core/browser/phone_number.cc
index e452f98..2ee67f9 100644
--- a/components/autofill/core/browser/phone_number.cc
+++ b/components/autofill/core/browser/phone_number.cc
@@ -74,8 +74,8 @@
 }
 
 base::string16 PhoneNumber::GetRawInfo(ServerFieldType type) const {
-  type = AutofillType::GetEquivalentFieldType(type);
-  if (type == PHONE_HOME_WHOLE_NUMBER)
+  // TODO(isherman): Is GetStorableType even necessary?
+  if (AutofillType(type).GetStorableType() == PHONE_HOME_WHOLE_NUMBER)
     return number_;
 
   // Only the whole number is available as raw data.  All of the other types are
@@ -86,9 +86,9 @@
 
 void PhoneNumber::SetRawInfo(ServerFieldType type,
                              const base::string16& value) {
-  type = AutofillType::GetEquivalentFieldType(type);
-  if (type != PHONE_HOME_CITY_AND_NUMBER &&
-      type != PHONE_HOME_WHOLE_NUMBER) {
+  // TODO(isherman): Is GetStorableType even necessary?
+  type = AutofillType(type).GetStorableType();
+  if (type != PHONE_HOME_CITY_AND_NUMBER && type != PHONE_HOME_WHOLE_NUMBER) {
     // Only full phone numbers should be set directly.  The remaining field
     // field types are read-only.
     return;
@@ -106,18 +106,17 @@
 // If the phone cannot be normalized, returns the stored value verbatim.
 base::string16 PhoneNumber::GetInfo(const AutofillType& type,
                                     const std::string& app_locale) const {
-  ServerFieldType server_type =
-      AutofillType::GetEquivalentFieldType(type.server_type());
+  ServerFieldType storable_type = type.GetStorableType();
   UpdateCacheIfNeeded(app_locale);
 
   // Queries for whole numbers will return the non-normalized number if
   // normalization for the number fails.  All other field types require
   // normalization.
-  if (server_type != PHONE_HOME_WHOLE_NUMBER &&
+  if (storable_type != PHONE_HOME_WHOLE_NUMBER &&
       !cached_parsed_phone_.IsValidNumber())
     return base::string16();
 
-  switch (server_type) {
+  switch (storable_type) {
     case PHONE_HOME_WHOLE_NUMBER:
       return cached_parsed_phone_.GetWholeNumber();
 
@@ -143,9 +142,7 @@
 bool PhoneNumber::SetInfo(const AutofillType& type,
                           const base::string16& value,
                           const std::string& app_locale) {
-  ServerFieldType server_type =
-      AutofillType::GetEquivalentFieldType(type.server_type());
-  SetRawInfo(server_type, value);
+  SetRawInfo(type.GetStorableType(), value);
 
   if (number_.empty())
     return true;
@@ -196,31 +193,30 @@
 PhoneNumber::PhoneCombineHelper::~PhoneCombineHelper() {
 }
 
-bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& field_type,
+bool PhoneNumber::PhoneCombineHelper::SetInfo(const AutofillType& type,
                                               const base::string16& value) {
-  ServerFieldType server_field_type =
-      AutofillType::GetEquivalentFieldType(field_type.server_type());
-  if (server_field_type == PHONE_HOME_COUNTRY_CODE) {
+  ServerFieldType storable_type = type.GetStorableType();
+  if (storable_type == PHONE_HOME_COUNTRY_CODE) {
     country_ = value;
     return true;
   }
 
-  if (server_field_type == PHONE_HOME_CITY_CODE) {
+  if (storable_type == PHONE_HOME_CITY_CODE) {
     city_ = value;
     return true;
   }
 
-  if (server_field_type == PHONE_HOME_CITY_AND_NUMBER) {
+  if (storable_type == PHONE_HOME_CITY_AND_NUMBER) {
     phone_ = value;
     return true;
   }
 
-  if (server_field_type == PHONE_HOME_WHOLE_NUMBER) {
+  if (storable_type == PHONE_HOME_WHOLE_NUMBER) {
     whole_number_ = value;
     return true;
   }
 
-  if (server_field_type == PHONE_HOME_NUMBER) {
+  if (storable_type == PHONE_HOME_NUMBER) {
     phone_.append(value);
     return true;
   }
diff --git a/components/autofill/core/browser/test_autofill_manager_delegate.cc b/components/autofill/core/browser/test_autofill_manager_delegate.cc
index 4ea359d..dc9781d 100644
--- a/components/autofill/core/browser/test_autofill_manager_delegate.cc
+++ b/components/autofill/core/browser/test_autofill_manager_delegate.cc
@@ -35,10 +35,12 @@
     const CreditCard& credit_card,
     const base::Closure& save_card_callback) {}
 
-void TestAutofillManagerDelegate::ShowAutocheckoutBubble(
+bool TestAutofillManagerDelegate::ShowAutocheckoutBubble(
     const gfx::RectF& bounding_box,
     bool is_google_user,
-    const base::Callback<void(AutocheckoutBubbleState)>& callback) {}
+    const base::Callback<void(AutocheckoutBubbleState)>& callback) {
+  return true;
+}
 
 void TestAutofillManagerDelegate::HideAutocheckoutBubble() {}
 
diff --git a/components/autofill/core/browser/test_autofill_manager_delegate.h b/components/autofill/core/browser/test_autofill_manager_delegate.h
index 24d771e..1fee0ba 100644
--- a/components/autofill/core/browser/test_autofill_manager_delegate.h
+++ b/components/autofill/core/browser/test_autofill_manager_delegate.h
@@ -32,7 +32,7 @@
       const AutofillMetrics& metric_logger,
       const CreditCard& credit_card,
       const base::Closure& save_card_callback) OVERRIDE;
-  virtual void ShowAutocheckoutBubble(
+  virtual bool ShowAutocheckoutBubble(
       const gfx::RectF& bounding_box,
       bool is_google_user,
       const base::Callback<void(AutocheckoutBubbleState)>& callback) OVERRIDE;
diff --git a/components/autofill/core/common/autofill_messages.h b/components/autofill/core/common/autofill_messages.h
index 81fde2c..a432887 100644
--- a/components/autofill/core/common/autofill_messages.h
+++ b/components/autofill/core/common/autofill_messages.h
@@ -183,6 +183,10 @@
 // metadata.
 IPC_MESSAGE_ROUTED0(AutofillMsg_AutocheckoutSupported)
 
+// Sent when the current page is actually displayed in the browser, possibly
+// after being preloaded.
+IPC_MESSAGE_ROUTED0(AutofillMsg_PageShown)
+
 // Autofill messages sent from the renderer to the browser.
 
 // TODO(creis): check in the browser that the renderer actually has permission
diff --git a/components/nacl/common/nacl_host_messages.h b/components/nacl/common/nacl_host_messages.h
index 7a39504..d9a835b 100644
--- a/components/nacl/common/nacl_host_messages.h
+++ b/components/nacl/common/nacl_host_messages.h
@@ -91,8 +91,9 @@
 
 // A renderer sends this to the browser to report that its translation has
 // finished and its temp file contains the translated nexe.
-IPC_MESSAGE_CONTROL1(NaClHostMsg_ReportTranslationFinished,
-                     int /* instance */)
+IPC_MESSAGE_CONTROL2(NaClHostMsg_ReportTranslationFinished,
+                     int /* instance */,
+                     bool /* success */)
 
 // A renderer sends this to the browser process to report an error.
 IPC_MESSAGE_CONTROL2(NaClHostMsg_NaClErrorStatus,
diff --git a/content/browser/accessibility/accessibility_tree_formatter_mac.mm b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
index fda76bf..58881b4 100644
--- a/content/browser/accessibility/accessibility_tree_formatter_mac.mm
+++ b/content/browser/accessibility/accessibility_tree_formatter_mac.mm
@@ -84,7 +84,7 @@
 }
 
 NSArray* BuildAllAttributesArray() {
-  return [NSArray arrayWithObjects:
+  NSArray* array = [NSArray arrayWithObjects:
       NSAccessibilityRoleDescriptionAttribute,
       NSAccessibilityTitleAttribute,
       NSAccessibilityValueAttribute,
@@ -115,6 +115,7 @@
       NSAccessibilityVisibleCharacterRangeAttribute,
       @"AXVisited",
       nil];
+  return [array retain];
 }
 
 }  // namespace
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.cc b/content/browser/android/in_process/synchronous_compositor_impl.cc
index 3c7dfe9..041511e 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_impl.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/renderer/android/synchronous_compositor_factory.h"
+#include "ui/gl/gl_surface.h"
 #include "webkit/common/gpu/context_provider_in_process.h"
 
 namespace content {
@@ -143,10 +144,12 @@
   compositor_client_ = compositor_client;
 }
 
-bool SynchronousCompositorImpl::InitializeHwDraw() {
+bool SynchronousCompositorImpl::InitializeHwDraw(
+    scoped_refptr<gfx::GLSurface> surface) {
   DCHECK(CalledOnValidThread());
   DCHECK(output_surface_);
   return output_surface_->InitializeHwDraw(
+      surface,
       g_factory.Get().GetOffscreenContextProviderForCompositorThread());
 }
 
diff --git a/content/browser/android/in_process/synchronous_compositor_impl.h b/content/browser/android/in_process/synchronous_compositor_impl.h
index f4c932b..f0ea2c6 100644
--- a/content/browser/android/in_process/synchronous_compositor_impl.h
+++ b/content/browser/android/in_process/synchronous_compositor_impl.h
@@ -48,7 +48,8 @@
   // SynchronousCompositor
   virtual void SetClient(SynchronousCompositorClient* compositor_client)
       OVERRIDE;
-  virtual bool InitializeHwDraw() OVERRIDE;
+  virtual bool InitializeHwDraw(
+      scoped_refptr<gfx::GLSurface> surface) OVERRIDE;
   virtual void ReleaseHwDraw() OVERRIDE;
   virtual bool DemandDrawHw(
       gfx::Size view_size,
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.cc b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
index fafd06f..a6115e9 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.cc
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.cc
@@ -15,30 +15,50 @@
 #include "content/browser/android/in_process/synchronous_compositor_impl.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "gpu/command_buffer/client/gl_in_process_context.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkDevice.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
-#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
 #include "webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h"
 
-using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
 
 namespace content {
 
 namespace {
 
-// TODO(boliu): RenderThreadImpl should create in process contexts as well.
-scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D() {
+scoped_ptr<WebKit::WebGraphicsContext3D> CreateWebGraphicsContext3D(
+    scoped_refptr<gfx::GLSurface> surface) {
+  using webkit::gpu::WebGraphicsContext3DInProcessCommandBufferImpl;
+  if (!gfx::GLSurface::InitializeOneOff())
+    return scoped_ptr<WebKit::WebGraphicsContext3D>();
+
+  const char* allowed_extensions = "*";
+  const gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
+
   WebKit::WebGraphicsContext3D::Attributes attributes;
   attributes.antialias = false;
   attributes.shareResources = true;
   attributes.noAutomaticFlushes = true;
 
+  gpu::GLInProcessContextAttribs in_process_attribs;
+  WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
+      attributes, &in_process_attribs);
+  scoped_ptr<gpu::GLInProcessContext> context(
+      gpu::GLInProcessContext::CreateWithSurface(surface,
+                                                 attributes.shareResources,
+                                                 allowed_extensions,
+                                                 in_process_attribs,
+                                                 gpu_preference));
+
+  if (!context.get())
+    return scoped_ptr<WebKit::WebGraphicsContext3D>();
+
   return scoped_ptr<WebKit::WebGraphicsContext3D>(
-      WebGraphicsContext3DInProcessCommandBufferImpl
-          ::CreateViewContext(attributes, NULL));
+      WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
+          context.Pass(), attributes));
 }
 
 void DidActivatePendingTree(int routing_id) {
@@ -176,13 +196,15 @@
 } // namespace
 
 bool SynchronousCompositorOutputSurface::InitializeHwDraw(
+    scoped_refptr<gfx::GLSurface> surface,
     scoped_refptr<cc::ContextProvider> offscreen_context) {
   DCHECK(CalledOnValidThread());
   DCHECK(HasClient());
   DCHECK(!context3d_);
+  DCHECK(surface);
 
-  return InitializeAndSetContext3D(CreateWebGraphicsContext3D().Pass(),
-                                   offscreen_context);
+  return InitializeAndSetContext3D(
+      CreateWebGraphicsContext3D(surface).Pass(), offscreen_context);
 }
 
 void SynchronousCompositorOutputSurface::ReleaseHwDraw() {
@@ -205,8 +227,6 @@
   SetExternalStencilTest(stencil_enabled);
   InvokeComposite(clip.size());
 
-  // TODO(boliu): Check if context is lost here.
-
   return did_swap_buffer_;
 }
 
diff --git a/content/browser/android/in_process/synchronous_compositor_output_surface.h b/content/browser/android/in_process/synchronous_compositor_output_surface.h
index a3a9066..3ab1498 100644
--- a/content/browser/android/in_process/synchronous_compositor_output_surface.h
+++ b/content/browser/android/in_process/synchronous_compositor_output_surface.h
@@ -61,7 +61,9 @@
   virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
 
   // Partial SynchronousCompositor API implementation.
-  bool InitializeHwDraw(scoped_refptr<cc::ContextProvider> offscreen_context);
+  bool InitializeHwDraw(
+      scoped_refptr<gfx::GLSurface> surface,
+      scoped_refptr<cc::ContextProvider> offscreen_context);
   void ReleaseHwDraw();
   bool DemandDrawHw(gfx::Size surface_size,
                     const gfx::Transform& transform,
diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc
index dda8bc8..8822e85 100644
--- a/content/browser/aura/gpu_process_transport_factory.cc
+++ b/content/browser/aura/gpu_process_transport_factory.cc
@@ -15,6 +15,7 @@
 #include "content/browser/aura/browser_compositor_output_surface.h"
 #include "content/browser/aura/browser_compositor_output_surface_proxy.h"
 #include "content/browser/aura/reflector_impl.h"
+#include "content/browser/aura/software_browser_compositor_output_surface.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_surface_tracker.h"
@@ -179,41 +180,6 @@
   DISALLOW_COPY_AND_ASSIGN(CompositorSwapClient);
 };
 
-class SoftwareOutputSurface : public cc::OutputSurface {
- public:
-  explicit SoftwareOutputSurface(
-      scoped_ptr<cc::SoftwareOutputDevice> software_device)
-      : cc::OutputSurface(software_device.Pass()) {}
-
-  virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE {
-    ui::LatencyInfo latency_info = frame->metadata.latency_info;
-    latency_info.swap_timestamp = base::TimeTicks::HighResNow();
-    RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
-    cc::OutputSurface::SwapBuffers(frame);
-  }
-};
-
-scoped_ptr<cc::OutputSurface> CreateSoftwareOutputSurface(
-    ui::Compositor* compositor) {
-  scoped_ptr<cc::OutputSurface> output_surface;
-
-#if defined(OS_WIN)
-  scoped_ptr<SoftwareOutputDeviceWin> software_device(
-      new SoftwareOutputDeviceWin(compositor));
-  output_surface.reset(new SoftwareOutputSurface(
-      software_device.PassAs<cc::SoftwareOutputDevice>()));
-#elif defined(USE_X11)
-  scoped_ptr<SoftwareOutputDeviceX11> software_device(
-      new SoftwareOutputDeviceX11(compositor));
-  output_surface.reset(new SoftwareOutputSurface(
-      software_device.PassAs<cc::SoftwareOutputDevice>()));
-#else
-  NOTIMPLEMENTED();
-#endif
-
-  return output_surface.Pass();
-}
-
 GpuProcessTransportFactory::GpuProcessTransportFactory()
     : callback_factory_(this) {
   output_surface_proxy_ = new BrowserCompositorOutputSurfaceProxy(
@@ -239,6 +205,20 @@
       .PassAs<WebKit::WebGraphicsContext3D>();
 }
 
+scoped_ptr<cc::SoftwareOutputDevice> CreateSoftwareOutputDevice(
+    ui::Compositor* compositor) {
+#if defined(OS_WIN)
+  return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceWin(
+      compositor));
+#elif defined(USE_X11)
+  return scoped_ptr<cc::SoftwareOutputDevice>(new SoftwareOutputDeviceX11(
+      compositor));
+#endif
+
+  NOTREACHED();
+  return scoped_ptr<cc::SoftwareOutputDevice>();
+}
+
 scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface(
     ui::Compositor* compositor) {
   PerCompositorData* data = per_compositor_data_[compositor];
@@ -251,8 +231,12 @@
     context =
         CreateContextCommon(data->swap_client->AsWeakPtr(), data->surface_id);
   }
-  if (!context)
-    return CreateSoftwareOutputSurface(compositor);
+  if (!context) {
+    scoped_ptr<SoftwareBrowserCompositorOutputSurface> surface =
+        SoftwareBrowserCompositorOutputSurface::Create(
+            CreateSoftwareOutputDevice(compositor));
+    return surface.PassAs<cc::OutputSurface>();
+  }
 
   scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner =
       ui::Compositor::GetCompositorMessageLoop();
diff --git a/content/browser/aura/software_browser_compositor_output_surface.cc b/content/browser/aura/software_browser_compositor_output_surface.cc
new file mode 100644
index 0000000..c59806e
--- /dev/null
+++ b/content/browser/aura/software_browser_compositor_output_surface.cc
@@ -0,0 +1,26 @@
+// 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 "content/browser/aura/software_browser_compositor_output_surface.h"
+
+#include "base/time/time.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/software_output_device.h"
+#include "content/browser/renderer_host/render_widget_host_impl.h"
+#include "ui/base/latency_info.h"
+
+namespace content {
+
+SoftwareBrowserCompositorOutputSurface::SoftwareBrowserCompositorOutputSurface(
+    scoped_ptr<cc::SoftwareOutputDevice> software_device)
+    : cc::OutputSurface(software_device.Pass()) {}
+
+void SoftwareBrowserCompositorOutputSurface::SwapBuffers(
+    cc::CompositorFrame* frame) {
+  ui::LatencyInfo latency_info = frame->metadata.latency_info;
+  latency_info.swap_timestamp = base::TimeTicks::HighResNow();
+  RenderWidgetHostImpl::CompositorFrameDrawn(latency_info);
+}
+
+}  // namespace content
diff --git a/content/browser/aura/software_browser_compositor_output_surface.h b/content/browser/aura/software_browser_compositor_output_surface.h
new file mode 100644
index 0000000..ac499da
--- /dev/null
+++ b/content/browser/aura/software_browser_compositor_output_surface.h
@@ -0,0 +1,33 @@
+// 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 CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_SURFACE_H_
+#define CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_SURFACE_H_
+
+#include "cc/output/output_surface.h"
+
+namespace cc { class SoftwareOutputDevice; }
+
+namespace content {
+
+// TODO(danakj): Inherit from BrowserCompositorOutputSurface to share stuff like
+// reflectors, when we split the GL-specific stuff out of the class.
+class SoftwareBrowserCompositorOutputSurface : public cc::OutputSurface {
+ public:
+  static scoped_ptr<SoftwareBrowserCompositorOutputSurface> Create(
+      scoped_ptr<cc::SoftwareOutputDevice> software_device) {
+    return make_scoped_ptr(
+        new SoftwareBrowserCompositorOutputSurface(software_device.Pass()));
+  }
+
+ private:
+  explicit SoftwareBrowserCompositorOutputSurface(
+      scoped_ptr<cc::SoftwareOutputDevice> software_device);
+
+  virtual void SwapBuffers(cc::CompositorFrame* frame) OVERRIDE;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_AURA_SOFTWARE_OUTPUT_SURFACE_H_
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index d02aa72..2e76dc0 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -6,7 +6,7 @@
 
 #if !defined(OS_IOS)
 #include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -65,7 +65,7 @@
   return partition_map->Get(partition_domain, partition_name, in_memory);
 }
 
-// Run |callback| on each DOMStorageContextImpl in |browser_context|.
+// Run |callback| on each DOMStorageContextWrapper in |browser_context|.
 void PurgeDOMStorageContextInPartition(StoragePartition* storage_partition) {
   static_cast<StoragePartitionImpl*>(storage_partition)->
       GetDOMStorageContext()->PurgeMemory();
@@ -233,10 +233,10 @@
             storage_partition->GetAppCacheService()));
   }
 
-  DOMStorageContextImpl* dom_storage_context_impl =
-      static_cast<DOMStorageContextImpl*>(
+  DOMStorageContextWrapper* dom_storage_context_proxy =
+      static_cast<DOMStorageContextWrapper*>(
           storage_partition->GetDOMStorageContext());
-  dom_storage_context_impl->SetForceKeepSessionState();
+  dom_storage_context_proxy->SetForceKeepSessionState();
 
   IndexedDBContextImpl* indexed_db_context_impl =
       static_cast<IndexedDBContextImpl*>(
diff --git a/content/browser/devtools/devtools_browser_target.cc b/content/browser/devtools/devtools_browser_target.cc
index f0fa8d0..a782462 100644
--- a/content/browser/devtools/devtools_browser_target.cc
+++ b/content/browser/devtools/devtools_browser_target.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/values.h"
 #include "content/public/browser/browser_thread.h"
@@ -44,8 +43,8 @@
 
 void DevToolsBrowserTarget::HandleMessage(const std::string& data) {
   std::string error_response;
-  scoped_ptr<DevToolsProtocol::Command> command(
-      DevToolsProtocol::ParseCommand(data, &error_response));
+  scoped_refptr<DevToolsProtocol::Command> command =
+      DevToolsProtocol::ParseCommand(data, &error_response);
   if (!command) {
     Respond(error_response);
     return;
@@ -61,8 +60,10 @@
   bool handle_directly = handle_on_ui_thread_.find(command->domain()) ==
       handle_on_ui_thread_.end();
   if (handle_directly) {
-    scoped_ptr<DevToolsProtocol::Response> response(
-        handler->HandleCommand(command.get()));
+    scoped_refptr<DevToolsProtocol::Response> response =
+        handler->HandleCommand(command);
+    if (response && response->is_async_promise())
+      return;
     if (response)
       Respond(response->Serialize());
     else
@@ -76,7 +77,7 @@
       base::Bind(&DevToolsBrowserTarget::HandleCommandOnUIThread,
                  this,
                  handler,
-                 command.release()));
+                 command));
 }
 
 void DevToolsBrowserTarget::Detach() {
@@ -106,10 +107,12 @@
 
 void DevToolsBrowserTarget::HandleCommandOnUIThread(
     DevToolsProtocol::Handler* handler,
-    DevToolsProtocol::Command* command_ptr) {
-  scoped_ptr<DevToolsProtocol::Command> command(command_ptr);
-  scoped_ptr<DevToolsProtocol::Response> response(
-      handler->HandleCommand(command.get()));
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  scoped_refptr<DevToolsProtocol::Response> response =
+      handler->HandleCommand(command);
+  if (response && response->is_async_promise())
+    return;
+
   if (response)
     RespondFromUIThread(response->Serialize());
   else
diff --git a/content/browser/devtools/devtools_browser_target.h b/content/browser/devtools/devtools_browser_target.h
index 04b1e8a..46ed291 100644
--- a/content/browser/devtools/devtools_browser_target.h
+++ b/content/browser/devtools/devtools_browser_target.h
@@ -51,8 +51,9 @@
   friend class base::RefCountedThreadSafe<DevToolsBrowserTarget>;
   ~DevToolsBrowserTarget();
 
-  void HandleCommandOnUIThread(DevToolsProtocol::Handler*,
-                               DevToolsProtocol::Command* command);
+  void HandleCommandOnUIThread(
+      DevToolsProtocol::Handler*,
+      scoped_refptr<DevToolsProtocol::Command> command);
 
   void DeleteHandlersOnUIThread(
       std::vector<DevToolsProtocol::Handler*> handlers);
diff --git a/content/browser/devtools/devtools_protocol.cc b/content/browser/devtools/devtools_protocol.cc
index d2883f9..d39cc33 100644
--- a/content/browser/devtools/devtools_protocol.cc
+++ b/content/browser/devtools/devtools_protocol.cc
@@ -61,30 +61,34 @@
   return json_command;
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 DevToolsProtocol::Command::SuccessResponse(base::DictionaryValue* result) {
-  return scoped_ptr<DevToolsProtocol::Response>(
-      new DevToolsProtocol::Response(id_, result));
+  return new DevToolsProtocol::Response(id_, result);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 DevToolsProtocol::Command::InternalErrorResponse(const std::string& message) {
-  return scoped_ptr<DevToolsProtocol::Response>(
-      new DevToolsProtocol::Response(id_, kErrorInternalError, message));
+  return new DevToolsProtocol::Response(id_, kErrorInternalError, message);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 DevToolsProtocol::Command::InvalidParamResponse(const std::string& param) {
   std::string message =
       base::StringPrintf("Missing or invalid '%s' parameter", param.c_str());
-  return scoped_ptr<DevToolsProtocol::Response>(
-      new DevToolsProtocol::Response(id_, kErrorInvalidParams, message));
+  return new DevToolsProtocol::Response(id_, kErrorInvalidParams, message);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 DevToolsProtocol::Command::NoSuchMethodErrorResponse() {
-  return scoped_ptr<DevToolsProtocol::Response>(
-      new Response(id_, kErrorNoSuchMethod, "No such method"));
+  return new Response(id_, kErrorNoSuchMethod, "No such method");
+}
+
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsProtocol::Command::AsyncResponsePromise() {
+  scoped_refptr<DevToolsProtocol::Response> promise =
+      new DevToolsProtocol::Response(0, NULL);
+  promise->is_async_promise_ = true;
+  return promise;
 }
 
 DevToolsProtocol::Command::Command(int id,
@@ -94,6 +98,9 @@
       id_(id) {
 }
 
+DevToolsProtocol::Response::~Response() {
+}
+
 std::string DevToolsProtocol::Response::Serialize() {
   base::DictionaryValue response;
 
@@ -118,7 +125,8 @@
 DevToolsProtocol::Response::Response(int id, base::DictionaryValue* result)
     : id_(id),
       result_(result),
-      error_code_(0) {
+      error_code_(0),
+      is_async_promise_(false) {
 }
 
 DevToolsProtocol::Response::Response(int id,
@@ -126,9 +134,6 @@
                                      const std::string& error_message)
     : id_(id), error_code_(error_code), error_message_(error_message) {}
 
-DevToolsProtocol::Response::~Response() {
-}
-
 DevToolsProtocol::Notification::Notification(const std::string& method,
                                              base::DictionaryValue* params)
     : Message(method, params) {
@@ -151,12 +156,12 @@
 DevToolsProtocol::Handler::~Handler() {
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 DevToolsProtocol::Handler::HandleCommand(
-    DevToolsProtocol::Command* command) {
+    scoped_refptr<DevToolsProtocol::Command> command) {
   CommandHandlers::iterator it = command_handlers_.find(command->method());
   if (it == command_handlers_.end())
-    return scoped_ptr<DevToolsProtocol::Response>();
+    return NULL;
   return (it->second).Run(command);
 }
 
@@ -176,8 +181,9 @@
 void DevToolsProtocol::Handler::SendNotification(
     const std::string& method,
     base::DictionaryValue* params) {
-  DevToolsProtocol::Notification notification(method, params);
-  SendRawMessage(notification.Serialize());
+  scoped_refptr<DevToolsProtocol::Notification> notification =
+      new DevToolsProtocol::Notification(method, params);
+  SendRawMessage(notification->Serialize());
 }
 
 void DevToolsProtocol::Handler::SendRawMessage(const std::string& message) {
@@ -196,7 +202,7 @@
 }
 
 // static
-DevToolsProtocol::Command* DevToolsProtocol::ParseCommand(
+scoped_refptr<DevToolsProtocol::Command> DevToolsProtocol::ParseCommand(
     const std::string& json,
     std::string* error_response) {
   scoped_ptr<base::DictionaryValue> command_dict(
@@ -209,8 +215,9 @@
   bool ok = command_dict->GetInteger(kIdParam, &id) && id >= 0;
   ok = ok && ParseMethod(command_dict.get(), &method);
   if (!ok) {
-    Response response(kNoId, kErrorInvalidRequest, "No such method");
-    *error_response = response.Serialize();
+    scoped_refptr<Response> response =
+        new Response(kNoId, kErrorInvalidRequest, "No such method");
+    *error_response = response->Serialize();
     return NULL;
   }
 
@@ -220,7 +227,7 @@
 }
 
 // static
-DevToolsProtocol::Notification*
+scoped_refptr<DevToolsProtocol::Notification>
 DevToolsProtocol::ParseNotification(const std::string& json) {
   scoped_ptr<base::DictionaryValue> dict(ParseMessage(json, NULL));
   if (!dict)
@@ -237,7 +244,8 @@
 }
 
 //static
-DevToolsProtocol::Notification* DevToolsProtocol::CreateNotification(
+scoped_refptr<DevToolsProtocol::Notification>
+DevToolsProtocol::CreateNotification(
     const std::string& method,
     base::DictionaryValue* params) {
   return new Notification(method, params);
@@ -254,9 +262,10 @@
           json, 0, &parse_error_code, &error_message));
 
   if (!message || !message->IsType(Value::TYPE_DICTIONARY)) {
-    Response response(0, kErrorParseError, error_message);
+    scoped_refptr<Response> response =
+        new Response(0, kErrorParseError, error_message);
     if (error_response)
-      *error_response = response.Serialize();
+      *error_response = response->Serialize();
     return NULL;
   }
 
diff --git a/content/browser/devtools/devtools_protocol.h b/content/browser/devtools/devtools_protocol.h
index 71e8f58..0012947 100644
--- a/content/browser/devtools/devtools_protocol.h
+++ b/content/browser/devtools/devtools_protocol.h
@@ -11,6 +11,7 @@
 #include "base/basictypes.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
 #include "base/values.h"
 
 namespace content {
@@ -23,16 +24,16 @@
 
   class Response;
 
-  class Message {
+  class Message : public base::RefCountedThreadSafe<Message> {
    public:
-    virtual ~Message();
-
     std::string domain() { return domain_; }
     std::string method() { return method_; }
     base::DictionaryValue* params() { return params_.get(); }
     virtual std::string Serialize() = 0;
 
    protected:
+    friend class base::RefCountedThreadSafe<Message>;
+    virtual ~Message();
     Message(const std::string& method,
             base::DictionaryValue* params);
 
@@ -46,23 +47,27 @@
 
   class Command : public Message {
    public:
-    virtual  ~Command();
-
     int id() { return id_; }
 
     virtual std::string Serialize() OVERRIDE;
 
     // Creates success response. Takes ownership of |result|.
-    scoped_ptr<Response> SuccessResponse(base::DictionaryValue* result);
+    scoped_refptr<Response> SuccessResponse(base::DictionaryValue* result);
 
-    // Creates error response. Caller takes ownership of the return value.
-    scoped_ptr<Response> InternalErrorResponse(const std::string& message);
+    // Creates error response.
+    scoped_refptr<Response> InternalErrorResponse(const std::string& message);
 
-    // Creates error response. Caller takes ownership of the return value.
-    scoped_ptr<Response> InvalidParamResponse(const std::string& param);
+    // Creates error response.
+    scoped_refptr<Response> InvalidParamResponse(const std::string& param);
 
-    // Creates error response. Caller takes ownership of the return value.
-    scoped_ptr<Response> NoSuchMethodErrorResponse();
+    // Creates error response.
+    scoped_refptr<Response> NoSuchMethodErrorResponse();
+
+    // Creates async response promise.
+    scoped_refptr<Response> AsyncResponsePromise();
+
+   protected:
+    virtual  ~Command();
 
    private:
     friend class DevToolsProtocol;
@@ -74,15 +79,17 @@
     DISALLOW_COPY_AND_ASSIGN(Command);
   };
 
-  class Response {
+  class Response : public base::RefCountedThreadSafe<Response> {
    public:
-    ~Response();
-
     std::string Serialize();
 
+    bool is_async_promise() { return is_async_promise_; }
+
    private:
+    friend class base::RefCountedThreadSafe<Response>;
     friend class Command;
     friend class DevToolsProtocol;
+    virtual  ~Response();
 
     Response(int id, base::DictionaryValue* result);
     Response(int id, int error_code, const std::string& error_message);
@@ -91,18 +98,19 @@
     scoped_ptr<base::DictionaryValue> result_;
     int error_code_;
     std::string error_message_;
+    bool is_async_promise_;
 
     DISALLOW_COPY_AND_ASSIGN(Response);
   };
 
   class Notification : public Message {
    public:
-    virtual ~Notification();
 
     virtual std::string Serialize() OVERRIDE;
 
    private:
     friend class DevToolsProtocol;
+    virtual ~Notification();
 
     // Takes ownership of |params|.
     Notification(const std::string& method,
@@ -113,13 +121,13 @@
 
   class Handler {
    public:
-    typedef base::Callback<scoped_ptr<DevToolsProtocol::Response>(
-        DevToolsProtocol::Command* command)> CommandHandler;
+    typedef base::Callback<scoped_refptr<DevToolsProtocol::Response>(
+        scoped_refptr<DevToolsProtocol::Command> command)> CommandHandler;
 
     virtual ~Handler();
 
-    virtual scoped_ptr<DevToolsProtocol::Response> HandleCommand(
-        DevToolsProtocol::Command* command);
+    virtual scoped_refptr<DevToolsProtocol::Response> HandleCommand(
+        scoped_refptr<DevToolsProtocol::Command> command);
 
     void SetNotifier(const Notifier& notifier);
 
@@ -146,13 +154,14 @@
     DISALLOW_COPY_AND_ASSIGN(Handler);
   };
 
-  static Command* ParseCommand(const std::string& json,
-                               std::string* error_response);
+  static scoped_refptr<Command> ParseCommand(const std::string& json,
+                                             std::string* error_response);
 
-  static Notification* ParseNotification(const std::string& json);
+  static scoped_refptr<Notification> ParseNotification(
+      const std::string& json);
 
-  static Notification* CreateNotification(const std::string& method,
-                                          base::DictionaryValue* params);
+  static scoped_refptr<Notification> CreateNotification(
+      const std::string& method, base::DictionaryValue* params);
 
  private:
   static base::DictionaryValue* ParseMessage(const std::string& json,
diff --git a/content/browser/devtools/devtools_tracing_handler.cc b/content/browser/devtools/devtools_tracing_handler.cc
index 2b4fddc..0657b8e 100644
--- a/content/browser/devtools/devtools_tracing_handler.cc
+++ b/content/browser/devtools/devtools_tracing_handler.cc
@@ -82,8 +82,9 @@
   return static_cast<base::debug::TraceLog::Options>(ret);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
-DevToolsTracingHandler::OnStart(DevToolsProtocol::Command* command) {
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsTracingHandler::OnStart(
+    scoped_refptr<DevToolsProtocol::Command> command) {
   std::string categories;
   base::DictionaryValue* params = command->params();
   if (params)
@@ -102,8 +103,9 @@
   return command->SuccessResponse(NULL);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
-DevToolsTracingHandler::OnEnd(DevToolsProtocol::Command* command) {
+scoped_refptr<DevToolsProtocol::Response>
+DevToolsTracingHandler::OnEnd(
+    scoped_refptr<DevToolsProtocol::Command> command) {
   TraceController::GetInstance()->EndTracingAsync(this);
   return command->SuccessResponse(NULL);
 }
diff --git a/content/browser/devtools/devtools_tracing_handler.h b/content/browser/devtools/devtools_tracing_handler.h
index 0c528c5..43cd615 100644
--- a/content/browser/devtools/devtools_tracing_handler.h
+++ b/content/browser/devtools/devtools_tracing_handler.h
@@ -26,10 +26,10 @@
       const scoped_refptr<base::RefCountedString>& trace_fragment) OVERRIDE;
 
  private:
-  scoped_ptr<DevToolsProtocol::Response> OnStart(
-      DevToolsProtocol::Command* command);
-  scoped_ptr<DevToolsProtocol::Response> OnEnd(
-      DevToolsProtocol::Command* command);
+  scoped_refptr<DevToolsProtocol::Response> OnStart(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> OnEnd(
+      scoped_refptr<DevToolsProtocol::Command> command);
 
   base::debug::TraceLog::Options TraceOptionsFromString(
       const std::string& options);
diff --git a/content/browser/devtools/render_view_devtools_agent_host.cc b/content/browser/devtools/render_view_devtools_agent_host.cc
index 202589b..0c2d323 100644
--- a/content/browser/devtools/render_view_devtools_agent_host.cc
+++ b/content/browser/devtools/render_view_devtools_agent_host.cc
@@ -156,15 +156,17 @@
 void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend(
     const std::string& message) {
   std::string error_message;
-  scoped_ptr<DevToolsProtocol::Command> command(
-      DevToolsProtocol::ParseCommand(message, &error_message));
+  scoped_refptr<DevToolsProtocol::Command> command =
+      DevToolsProtocol::ParseCommand(message, &error_message);
+
   if (command) {
-    scoped_ptr<DevToolsProtocol::Response> overridden_response(
-        overrides_handler_->HandleCommand(command.get()));
+    scoped_refptr<DevToolsProtocol::Response> overridden_response =
+        overrides_handler_->HandleCommand(command);
     if (!overridden_response)
-      overridden_response = tracing_handler_->HandleCommand(command.get());
+      overridden_response = tracing_handler_->HandleCommand(command);
     if (overridden_response) {
-      OnDispatchOnInspectorFrontend(overridden_response->Serialize());
+      if (!overridden_response->is_async_promise())
+        OnDispatchOnInspectorFrontend(overridden_response->Serialize());
       return;
     }
   }
@@ -290,9 +292,9 @@
 }
 
 void RenderViewDevToolsAgentHost::RenderViewCrashed() {
-  scoped_ptr<DevToolsProtocol::Notification> notification(
+  scoped_refptr<DevToolsProtocol::Notification> notification =
       DevToolsProtocol::CreateNotification(
-          devtools::Inspector::targetCrashed::kName, NULL));
+          devtools::Inspector::targetCrashed::kName, NULL);
   DevToolsManagerImpl::GetInstance()->
       DispatchOnInspectorFrontend(this, notification->Serialize());
 }
diff --git a/content/browser/devtools/renderer_overrides_handler.cc b/content/browser/devtools/renderer_overrides_handler.cc
index cbc26f4..69fe055 100644
--- a/content/browser/devtools/renderer_overrides_handler.cc
+++ b/content/browser/devtools/renderer_overrides_handler.cc
@@ -16,6 +16,7 @@
 #include "content/browser/devtools/devtools_protocol_constants.h"
 #include "content/browser/devtools/devtools_tracing_handler.h"
 #include "content/browser/renderer_host/render_view_host_delegate.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/devtools_agent_host.h"
 #include "content/public/browser/javascript_dialog_manager.h"
 #include "content/public/browser/navigation_controller.h"
@@ -32,7 +33,8 @@
 namespace content {
 
 RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent)
-    : agent_(agent) {
+    : agent_(agent),
+      weak_factory_(this) {
   RegisterCommandHandler(
       devtools::DOM::setFileInputFiles::kName,
       base::Bind(
@@ -57,9 +59,9 @@
 
 RendererOverridesHandler::~RendererOverridesHandler() {}
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::GrantPermissionsForSetFileInputFiles(
-    DevToolsProtocol::Command* command) {
+    scoped_refptr<DevToolsProtocol::Command> command) {
   base::DictionaryValue* params = command->params();
   base::ListValue* file_list = NULL;
   const char* param =
@@ -68,7 +70,7 @@
     return command->InvalidParamResponse(param);
   RenderViewHost* host = agent_->GetRenderViewHost();
   if (!host)
-    return scoped_ptr<DevToolsProtocol::Response>();
+    return NULL;
 
   for (size_t i = 0; i < file_list->GetSize(); ++i) {
     base::FilePath::StringType file;
@@ -77,12 +79,12 @@
     ChildProcessSecurityPolicyImpl::GetInstance()->GrantReadFile(
         host->GetProcess()->GetID(), base::FilePath(file));
   }
-  return scoped_ptr<DevToolsProtocol::Response>();
+  return NULL;
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageHandleJavaScriptDialog(
-    DevToolsProtocol::Command* command) {
+    scoped_refptr<DevToolsProtocol::Command> command) {
   base::DictionaryValue* params = command->params();
   const char* paramAccept =
       devtools::Page::handleJavaScriptDialog::kParamAccept;
@@ -105,16 +107,16 @@
           web_contents->GetDelegate()->GetJavaScriptDialogManager();
       if (manager && manager->HandleJavaScriptDialog(
               web_contents, accept, prompt_override_ptr)) {
-        return scoped_ptr<DevToolsProtocol::Response>();
+        return NULL;
       }
     }
   }
   return command->InternalErrorResponse("No JavaScript dialog to handle");
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageNavigate(
-    DevToolsProtocol::Command* command) {
+    scoped_refptr<DevToolsProtocol::Command> command) {
   base::DictionaryValue* params = command->params();
   std::string url;
   const char* param = devtools::Page::navigate::kParamUrl;
@@ -136,34 +138,47 @@
   return command->InternalErrorResponse("No WebContents to navigate");
 }
 
-scoped_ptr<DevToolsProtocol::Response>
+scoped_refptr<DevToolsProtocol::Response>
 RendererOverridesHandler::PageCaptureScreenshot(
-    DevToolsProtocol::Command* command) {
-  std::string base_64_data;
-  if (!CaptureScreenshot(&base_64_data))
-    return command->InternalErrorResponse("Unable to capture a screenshot");
+    scoped_refptr<DevToolsProtocol::Command> command) {
+  // Emulate async processing.
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&RendererOverridesHandler::CaptureScreenshot,
+                 weak_factory_.GetWeakPtr(),
+                 command));
 
-  base::DictionaryValue* response = new base::DictionaryValue();
-  response->SetString(
-      devtools::Page::captureScreenshot::kResponseData, base_64_data);
-  return command->SuccessResponse(response);
+  return command->AsyncResponsePromise();
 }
 
-bool RendererOverridesHandler::CaptureScreenshot(std::string* base_64_data) {
+void RendererOverridesHandler::CaptureScreenshot(
+    scoped_refptr<DevToolsProtocol::Command> command) {
+
   RenderViewHost* host = agent_->GetRenderViewHost();
   gfx::Rect view_bounds = host->GetView()->GetViewBounds();
   gfx::Rect snapshot_bounds(view_bounds.size());
   gfx::Size snapshot_size = snapshot_bounds.size();
-  std::vector<unsigned char> png;
-  if (!ui::GrabViewSnapshot(host->GetView()->GetNativeView(),
-                            &png,
-                            snapshot_bounds))
-    return false;
 
-  return base::Base64Encode(base::StringPiece(
-                                reinterpret_cast<char*>(&*png.begin()),
-                                png.size()),
-                            base_64_data);
+  std::vector<unsigned char> png;
+  if (ui::GrabViewSnapshot(host->GetView()->GetNativeView(),
+                           &png,
+                           snapshot_bounds)) {
+    std::string base_64_data;
+    bool success = base::Base64Encode(
+        base::StringPiece(reinterpret_cast<char*>(&*png.begin()), png.size()),
+        &base_64_data);
+    if (success) {
+      base::DictionaryValue* result = new base::DictionaryValue();
+      result->SetString(
+          devtools::Page::captureScreenshot::kResponseData, base_64_data);
+      scoped_refptr<DevToolsProtocol::Response> response =
+          command->SuccessResponse(result);
+      SendRawMessage(response->Serialize());
+      return;
+    }
+  }
+  SendRawMessage(command->
+      InternalErrorResponse("Unable to capture a screenshot")->Serialize());
 }
 
 }  // namespace content
diff --git a/content/browser/devtools/renderer_overrides_handler.h b/content/browser/devtools/renderer_overrides_handler.h
index ca85af1..9a46c38 100644
--- a/content/browser/devtools/renderer_overrides_handler.h
+++ b/content/browser/devtools/renderer_overrides_handler.h
@@ -8,6 +8,7 @@
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "content/browser/devtools/devtools_protocol.h"
 
 namespace content {
@@ -24,19 +25,20 @@
   virtual ~RendererOverridesHandler();
 
  private:
-  scoped_ptr<DevToolsProtocol::Response> GrantPermissionsForSetFileInputFiles(
-      DevToolsProtocol::Command* command);
-  scoped_ptr<DevToolsProtocol::Response> PageHandleJavaScriptDialog(
-      DevToolsProtocol::Command* command);
-  scoped_ptr<DevToolsProtocol::Response> PageNavigate(
-      DevToolsProtocol::Command* command);
-  scoped_ptr<DevToolsProtocol::Response> PageCaptureScreenshot(
-      DevToolsProtocol::Command* command);
+  scoped_refptr<DevToolsProtocol::Response>
+      GrantPermissionsForSetFileInputFiles(
+          scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> PageHandleJavaScriptDialog(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> PageNavigate(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> PageCaptureScreenshot(
+      scoped_refptr<DevToolsProtocol::Command> command);
 
-  bool CaptureScreenshot(std::string* base_64_data);
+  void CaptureScreenshot(scoped_refptr<DevToolsProtocol::Command> command);
 
   DevToolsAgentHost* agent_;
-
+  base::WeakPtrFactory<RendererOverridesHandler> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(RendererOverridesHandler);
 };
 
diff --git a/content/browser/devtools/tethering_handler.cc b/content/browser/devtools/tethering_handler.cc
index fc25e63..711adcd 100644
--- a/content/browser/devtools/tethering_handler.cc
+++ b/content/browser/devtools/tethering_handler.cc
@@ -264,7 +264,7 @@
   SendNotification(kTetheringAccepted, params);
 }
 
-static int GetPort(DevToolsProtocol::Command* command) {
+static int GetPort(scoped_refptr<DevToolsProtocol::Command> command) {
   base::DictionaryValue* params = command->params();
   int port = 0;
   if (!params || !params->GetInteger(kPortParam, &port) ||
@@ -273,8 +273,8 @@
   return port;
 }
 
-scoped_ptr<DevToolsProtocol::Response>
-TetheringHandler::OnBind(DevToolsProtocol::Command* command) {
+scoped_refptr<DevToolsProtocol::Response>
+TetheringHandler::OnBind(scoped_refptr<DevToolsProtocol::Command> command) {
   int port = GetPort(command);
   if (port == 0)
     return command->InvalidParamResponse(kPortParam);
@@ -290,8 +290,8 @@
   return command->SuccessResponse(NULL);
 }
 
-scoped_ptr<DevToolsProtocol::Response>
-TetheringHandler::OnUnbind(DevToolsProtocol::Command* command) {
+scoped_refptr<DevToolsProtocol::Response>
+TetheringHandler::OnUnbind(scoped_refptr<DevToolsProtocol::Command> command) {
   int port = GetPort(command);
   if (port == 0)
     return command->InvalidParamResponse(kPortParam);
diff --git a/content/browser/devtools/tethering_handler.h b/content/browser/devtools/tethering_handler.h
index a9931cc..7086e17 100644
--- a/content/browser/devtools/tethering_handler.h
+++ b/content/browser/devtools/tethering_handler.h
@@ -25,10 +25,10 @@
 
  private:
   class BoundSocket;
-  scoped_ptr<DevToolsProtocol::Response> OnBind(
-      DevToolsProtocol::Command* command);
-  scoped_ptr<DevToolsProtocol::Response> OnUnbind(
-      DevToolsProtocol::Command* command);
+  scoped_refptr<DevToolsProtocol::Response> OnBind(
+      scoped_refptr<DevToolsProtocol::Command> command);
+  scoped_refptr<DevToolsProtocol::Response> OnUnbind(
+      scoped_refptr<DevToolsProtocol::Command>  command);
 
   typedef std::map<int, BoundSocket*> BoundSockets;
   BoundSockets bound_sockets_;
diff --git a/content/browser/dom_storage/DEPS b/content/browser/dom_storage/DEPS
index aabd9ff..743a2f3 100644
--- a/content/browser/dom_storage/DEPS
+++ b/content/browser/dom_storage/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+webkit/dom_storage",
+  "+third_party/leveldatabase",
 ]
diff --git a/content/browser/dom_storage/OWNERS b/content/browser/dom_storage/OWNERS
index 74fb7e1..e765c6f 100644
--- a/content/browser/dom_storage/OWNERS
+++ b/content/browser/dom_storage/OWNERS
@@ -1,4 +1,2 @@
 michaeln@chromium.org
-kinuko@chromium.org
-jsbell@chromium.org
-ericu@chromium.org
+marja@chromium.org
diff --git a/webkit/browser/dom_storage/dom_storage_area.cc b/content/browser/dom_storage/dom_storage_area.cc
similarity index 76%
rename from webkit/browser/dom_storage/dom_storage_area.cc
rename to content/browser/dom_storage/dom_storage_area.cc
index d0e2ac3..e358301 100644
--- a/webkit/browser/dom_storage/dom_storage_area.cc
+++ b/content/browser/dom_storage/dom_storage_area.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
 
 #include "base/bind.h"
 #include "base/location.h"
@@ -10,35 +10,35 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/local_storage_database_adapter.h"
+#include "content/browser/dom_storage/session_storage_database.h"
+#include "content/browser/dom_storage/session_storage_database_adapter.h"
+#include "content/common/dom_storage/dom_storage_map.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "webkit/browser/database/database_util.h"
-#include "webkit/browser/dom_storage/dom_storage_namespace.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-#include "webkit/browser/dom_storage/local_storage_database_adapter.h"
-#include "webkit/browser/dom_storage/session_storage_database.h"
-#include "webkit/browser/dom_storage/session_storage_database_adapter.h"
 #include "webkit/common/database/database_identifier.h"
-#include "webkit/common/dom_storage/dom_storage_map.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/common/fileapi/file_system_util.h"
 
 using webkit_database::DatabaseUtil;
 
-namespace dom_storage {
+namespace content {
 
 static const int kCommitTimerSeconds = 1;
 
-DomStorageArea::CommitBatch::CommitBatch()
+DOMStorageArea::CommitBatch::CommitBatch()
   : clear_all_first(false) {
 }
-DomStorageArea::CommitBatch::~CommitBatch() {}
+DOMStorageArea::CommitBatch::~CommitBatch() {}
 
 
 // static
-const base::FilePath::CharType DomStorageArea::kDatabaseFileExtension[] =
+const base::FilePath::CharType DOMStorageArea::kDatabaseFileExtension[] =
     FILE_PATH_LITERAL(".localstorage");
 
 // static
-base::FilePath DomStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) {
+base::FilePath DOMStorageArea::DatabaseFileNameFromOrigin(const GURL& origin) {
   std::string filename = webkit_database::GetIdentifierFromOrigin(origin);
   // There is no base::FilePath.AppendExtension() method, so start with just the
   // extension as the filename, and then InsertBeforeExtension the desired
@@ -48,19 +48,21 @@
 }
 
 // static
-GURL DomStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) {
+GURL DOMStorageArea::OriginFromDatabaseFileName(const base::FilePath& name) {
   DCHECK(name.MatchesExtension(kDatabaseFileExtension));
   std::string origin_id =
       name.BaseName().RemoveExtension().MaybeAsASCII();
   return webkit_database::GetOriginFromIdentifier(origin_id);
 }
 
-DomStorageArea::DomStorageArea(const GURL& origin, const base::FilePath& directory,
-                               DomStorageTaskRunner* task_runner)
+DOMStorageArea::DOMStorageArea(
+    const GURL& origin, const base::FilePath& directory,
+    DOMStorageTaskRunner* task_runner)
     : namespace_id_(kLocalStorageNamespaceId), origin_(origin),
       directory_(directory),
       task_runner_(task_runner),
-      map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)),
+      map_(new DOMStorageMap(kPerStorageAreaQuota +
+                             kPerStorageAreaOverQuotaAllowance)),
       is_initial_import_done_(true),
       is_shutdown_(false),
       commit_batches_in_flight_(0) {
@@ -71,17 +73,18 @@
   }
 }
 
-DomStorageArea::DomStorageArea(
+DOMStorageArea::DOMStorageArea(
     int64 namespace_id,
     const std::string& persistent_namespace_id,
     const GURL& origin,
     SessionStorageDatabase* session_storage_backing,
-    DomStorageTaskRunner* task_runner)
+    DOMStorageTaskRunner* task_runner)
     : namespace_id_(namespace_id),
       persistent_namespace_id_(persistent_namespace_id),
       origin_(origin),
       task_runner_(task_runner),
-      map_(new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance)),
+      map_(new DOMStorageMap(kPerStorageAreaQuota +
+                             kPerStorageAreaOverQuotaAllowance)),
       session_storage_backing_(session_storage_backing),
       is_initial_import_done_(true),
       is_shutdown_(false),
@@ -94,38 +97,38 @@
   }
 }
 
-DomStorageArea::~DomStorageArea() {
+DOMStorageArea::~DOMStorageArea() {
 }
 
-void DomStorageArea::ExtractValues(ValuesMap* map) {
+void DOMStorageArea::ExtractValues(DOMStorageValuesMap* map) {
   if (is_shutdown_)
     return;
   InitialImportIfNeeded();
   map_->ExtractValues(map);
 }
 
-unsigned DomStorageArea::Length() {
+unsigned DOMStorageArea::Length() {
   if (is_shutdown_)
     return 0;
   InitialImportIfNeeded();
   return map_->Length();
 }
 
-base::NullableString16 DomStorageArea::Key(unsigned index) {
+base::NullableString16 DOMStorageArea::Key(unsigned index) {
   if (is_shutdown_)
     return base::NullableString16();
   InitialImportIfNeeded();
   return map_->Key(index);
 }
 
-base::NullableString16 DomStorageArea::GetItem(const base::string16& key) {
+base::NullableString16 DOMStorageArea::GetItem(const base::string16& key) {
   if (is_shutdown_)
     return base::NullableString16();
   InitialImportIfNeeded();
   return map_->GetItem(key);
 }
 
-bool DomStorageArea::SetItem(const base::string16& key,
+bool DOMStorageArea::SetItem(const base::string16& key,
                              const base::string16& value,
                              base::NullableString16* old_value) {
   if (is_shutdown_)
@@ -141,7 +144,7 @@
   return success;
 }
 
-bool DomStorageArea::RemoveItem(const base::string16& key,
+bool DOMStorageArea::RemoveItem(const base::string16& key,
                                 base::string16* old_value) {
   if (is_shutdown_)
     return false;
@@ -156,14 +159,15 @@
   return success;
 }
 
-bool DomStorageArea::Clear() {
+bool DOMStorageArea::Clear() {
   if (is_shutdown_)
     return false;
   InitialImportIfNeeded();
   if (map_->Length() == 0)
     return false;
 
-  map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota +
+                           kPerStorageAreaOverQuotaAllowance);
 
   if (backing_) {
     CommitBatch* commit_batch = CreateCommitBatchIfNeeded();
@@ -174,14 +178,15 @@
   return true;
 }
 
-void DomStorageArea::FastClear() {
+void DOMStorageArea::FastClear() {
   // TODO(marja): Unify clearing localStorage and sessionStorage. The problem is
   // to make the following 3 to work together: 1) FastClear, 2) PurgeMemory and
   // 3) not creating events when clearing an empty area.
   if (is_shutdown_)
     return;
 
-  map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota +
+                           kPerStorageAreaOverQuotaAllowance);
   // This ensures no import will happen while we're waiting to clear the data
   // from the database. This mechanism fails if PurgeMemory is called.
   is_initial_import_done_ = true;
@@ -193,13 +198,13 @@
   }
 }
 
-DomStorageArea* DomStorageArea::ShallowCopy(
+DOMStorageArea* DOMStorageArea::ShallowCopy(
     int64 destination_namespace_id,
     const std::string& destination_persistent_namespace_id) {
   DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
   DCHECK_NE(kLocalStorageNamespaceId, destination_namespace_id);
 
-  DomStorageArea* copy = new DomStorageArea(
+  DOMStorageArea* copy = new DOMStorageArea(
       destination_namespace_id, destination_persistent_namespace_id, origin_,
       session_storage_backing_.get(), task_runner_.get());
   copy->map_ = map_;
@@ -215,12 +220,12 @@
   return copy;
 }
 
-bool DomStorageArea::HasUncommittedChanges() const {
+bool DOMStorageArea::HasUncommittedChanges() const {
   DCHECK(!is_shutdown_);
   return commit_batch_.get() || commit_batches_in_flight_;
 }
 
-void DomStorageArea::DeleteOrigin() {
+void DOMStorageArea::DeleteOrigin() {
   DCHECK(!is_shutdown_);
   // This function shouldn't be called for sessionStorage.
   DCHECK(!session_storage_backing_.get());
@@ -233,7 +238,8 @@
     Clear();
     return;
   }
-  map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota +
+                           kPerStorageAreaOverQuotaAllowance);
   if (backing_) {
     is_initial_import_done_ = false;
     backing_->Reset();
@@ -241,7 +247,7 @@
   }
 }
 
-void DomStorageArea::PurgeMemory() {
+void DOMStorageArea::PurgeMemory() {
   DCHECK(!is_shutdown_);
   // Purging sessionStorage is not supported; it won't work with FastClear.
   DCHECK(!session_storage_backing_.get());
@@ -252,14 +258,15 @@
 
   // Drop the in memory cache, we'll reload when needed.
   is_initial_import_done_ = false;
-  map_ = new DomStorageMap(kPerAreaQuota + kPerAreaOverQuotaAllowance);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota +
+                           kPerStorageAreaOverQuotaAllowance);
 
   // Recreate the database object, this frees up the open sqlite connection
   // and its page cache.
   backing_->Reset();
 }
 
-void DomStorageArea::Shutdown() {
+void DOMStorageArea::Shutdown() {
   DCHECK(!is_shutdown_);
   is_shutdown_ = true;
   map_ = NULL;
@@ -268,19 +275,19 @@
 
   bool success = task_runner_->PostShutdownBlockingTask(
       FROM_HERE,
-      DomStorageTaskRunner::COMMIT_SEQUENCE,
-      base::Bind(&DomStorageArea::ShutdownInCommitSequence, this));
+      DOMStorageTaskRunner::COMMIT_SEQUENCE,
+      base::Bind(&DOMStorageArea::ShutdownInCommitSequence, this));
   DCHECK(success);
 }
 
-void DomStorageArea::InitialImportIfNeeded() {
+void DOMStorageArea::InitialImportIfNeeded() {
   if (is_initial_import_done_)
     return;
 
   DCHECK(backing_.get());
 
   base::TimeTicks before = base::TimeTicks::Now();
-  ValuesMap initial_values;
+  DOMStorageValuesMap initial_values;
   backing_->ReadAllValues(&initial_values);
   map_->SwapValues(&initial_values);
   is_initial_import_done_ = true;
@@ -310,7 +317,7 @@
   }
 }
 
-DomStorageArea::CommitBatch* DomStorageArea::CreateCommitBatchIfNeeded() {
+DOMStorageArea::CommitBatch* DOMStorageArea::CreateCommitBatchIfNeeded() {
   DCHECK(!is_shutdown_);
   if (!commit_batch_) {
     commit_batch_.reset(new CommitBatch());
@@ -321,14 +328,14 @@
     if (!commit_batches_in_flight_) {
       task_runner_->PostDelayedTask(
           FROM_HERE,
-          base::Bind(&DomStorageArea::OnCommitTimer, this),
+          base::Bind(&DOMStorageArea::OnCommitTimer, this),
           base::TimeDelta::FromSeconds(kCommitTimerSeconds));
     }
   }
   return commit_batch_.get();
 }
 
-void DomStorageArea::OnCommitTimer() {
+void DOMStorageArea::OnCommitTimer() {
   if (is_shutdown_)
     return;
 
@@ -344,14 +351,14 @@
   DCHECK(task_runner_->IsRunningOnPrimarySequence());
   bool success = task_runner_->PostShutdownBlockingTask(
       FROM_HERE,
-      DomStorageTaskRunner::COMMIT_SEQUENCE,
-      base::Bind(&DomStorageArea::CommitChanges, this,
+      DOMStorageTaskRunner::COMMIT_SEQUENCE,
+      base::Bind(&DOMStorageArea::CommitChanges, this,
                  base::Owned(commit_batch_.release())));
   ++commit_batches_in_flight_;
   DCHECK(success);
 }
 
-void DomStorageArea::CommitChanges(const CommitBatch* commit_batch) {
+void DOMStorageArea::CommitChanges(const CommitBatch* commit_batch) {
   // This method executes on the commit sequence.
   DCHECK(task_runner_->IsRunningOnCommitSequence());
   bool success = backing_->CommitChanges(commit_batch->clear_all_first,
@@ -359,10 +366,10 @@
   DCHECK(success);  // TODO(michaeln): what if it fails?
   task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageArea::OnCommitComplete, this));
+      base::Bind(&DOMStorageArea::OnCommitComplete, this));
 }
 
-void DomStorageArea::OnCommitComplete() {
+void DOMStorageArea::OnCommitComplete() {
   // We're back on the primary sequence in this method.
   DCHECK(task_runner_->IsRunningOnPrimarySequence());
   --commit_batches_in_flight_;
@@ -372,12 +379,12 @@
     // More changes have accrued, restart the timer.
     task_runner_->PostDelayedTask(
         FROM_HERE,
-        base::Bind(&DomStorageArea::OnCommitTimer, this),
+        base::Bind(&DOMStorageArea::OnCommitTimer, this),
         base::TimeDelta::FromSeconds(kCommitTimerSeconds));
   }
 }
 
-void DomStorageArea::ShutdownInCommitSequence() {
+void DOMStorageArea::ShutdownInCommitSequence() {
   // This method executes on the commit sequence.
   DCHECK(task_runner_->IsRunningOnCommitSequence());
   DCHECK(backing_.get());
@@ -393,4 +400,4 @@
   session_storage_backing_ = NULL;
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_area.h b/content/browser/dom_storage/dom_storage_area.h
similarity index 66%
rename from webkit/browser/dom_storage/dom_storage_area.h
rename to content/browser/dom_storage/dom_storage_area.h
index 04923aa..ca28be1 100644
--- a/webkit/browser/dom_storage/dom_storage_area.h
+++ b/content/browser/dom_storage/dom_storage_area.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
 
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
@@ -11,22 +11,22 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "url/gurl.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
-class DomStorageDatabaseAdapter;
-class DomStorageMap;
-class DomStorageTaskRunner;
+class DOMStorageDatabaseAdapter;
+class DOMStorageMap;
+class DOMStorageTaskRunner;
 class SessionStorageDatabase;
 
 // Container for a per-origin Map of key/value pairs potentially
 // backed by storage on disk and lazily commits changes to disk.
-// See class comments for DomStorageContext for a larger overview.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageArea
-    : public base::RefCountedThreadSafe<DomStorageArea> {
+// See class comments for DOMStorageContextImpl for a larger overview.
+class CONTENT_EXPORT DOMStorageArea
+    : public base::RefCountedThreadSafe<DOMStorageArea> {
 
  public:
   static const base::FilePath::CharType kDatabaseFileExtension[];
@@ -34,22 +34,22 @@
   static GURL OriginFromDatabaseFileName(const base::FilePath& file_name);
 
   // Local storage. Backed on disk if directory is nonempty.
-  DomStorageArea(const GURL& origin,
+  DOMStorageArea(const GURL& origin,
                  const base::FilePath& directory,
-                 DomStorageTaskRunner* task_runner);
+                 DOMStorageTaskRunner* task_runner);
 
   // Session storage. Backed on disk if |session_storage_backing| is not NULL.
-  DomStorageArea(int64 namespace_id,
+  DOMStorageArea(int64 namespace_id,
                  const std::string& persistent_namespace_id,
                  const GURL& origin,
                  SessionStorageDatabase* session_storage_backing,
-                 DomStorageTaskRunner* task_runner);
+                 DOMStorageTaskRunner* task_runner);
 
   const GURL& origin() const { return origin_; }
   int64 namespace_id() const { return namespace_id_; }
 
   // Writes a copy of the current set of values in the area to the |map|.
-  void ExtractValues(ValuesMap* map);
+  void ExtractValues(DOMStorageValuesMap* map);
 
   unsigned Length();
   base::NullableString16 Key(unsigned index);
@@ -60,7 +60,7 @@
   bool Clear();
   void FastClear();
 
-  DomStorageArea* ShallowCopy(
+  DOMStorageArea* ShallowCopy(
       int64 destination_namespace_id,
       const std::string& destination_persistent_namespace_id);
 
@@ -84,25 +84,25 @@
   bool IsLoadedInMemory() const { return is_initial_import_done_; }
 
  private:
-  friend class DomStorageAreaTest;
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, DomStorageAreaBasics);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, BackingDatabaseOpened);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, TestDatabaseFilePath);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, CommitTasks);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, CommitChangesAtShutdown);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, DeleteOrigin);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, PurgeMemory);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageContextTest, PersistentIds);
-  friend class base::RefCountedThreadSafe<DomStorageArea>;
+  friend class DOMStorageAreaTest;
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DOMStorageAreaBasics);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, TestDatabaseFilePath);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitChangesAtShutdown);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DeleteOrigin);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, PersistentIds);
+  friend class base::RefCountedThreadSafe<DOMStorageArea>;
 
   struct CommitBatch {
     bool clear_all_first;
-    ValuesMap changed_values;
+    DOMStorageValuesMap changed_values;
     CommitBatch();
     ~CommitBatch();
   };
 
-  ~DomStorageArea();
+  ~DOMStorageArea();
 
   // If we haven't done so already and this is a local storage area,
   // will attempt to read any values for this origin currently
@@ -123,9 +123,9 @@
   std::string persistent_namespace_id_;
   GURL origin_;
   base::FilePath directory_;
-  scoped_refptr<DomStorageTaskRunner> task_runner_;
-  scoped_refptr<DomStorageMap> map_;
-  scoped_ptr<DomStorageDatabaseAdapter> backing_;
+  scoped_refptr<DOMStorageTaskRunner> task_runner_;
+  scoped_refptr<DOMStorageMap> map_;
+  scoped_ptr<DOMStorageDatabaseAdapter> backing_;
   scoped_refptr<SessionStorageDatabase> session_storage_backing_;
   bool is_initial_import_done_;
   bool is_shutdown_;
@@ -133,6 +133,6 @@
   int commit_batches_in_flight_;
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_AREA_H_
diff --git a/webkit/browser/dom_storage/dom_storage_area_unittest.cc b/content/browser/dom_storage/dom_storage_area_unittest.cc
similarity index 82%
rename from webkit/browser/dom_storage/dom_storage_area_unittest.cc
rename to content/browser/dom_storage/dom_storage_area_unittest.cc
index 68aff17..697f625 100644
--- a/webkit/browser/dom_storage/dom_storage_area_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_area_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -10,20 +10,20 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_database_adapter.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/local_storage_database_adapter.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_database.h"
-#include "webkit/browser/dom_storage/dom_storage_database_adapter.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-#include "webkit/browser/dom_storage/local_storage_database_adapter.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
 
-class DomStorageAreaTest : public testing::Test {
+class DOMStorageAreaTest : public testing::Test {
  public:
-  DomStorageAreaTest()
+  DOMStorageAreaTest()
     : kOrigin(GURL("http://dom_storage/")),
       kKey(ASCIIToUTF16("key")),
       kValue(ASCIIToUTF16("value")),
@@ -38,7 +38,7 @@
   const base::string16 kValue2;
 
   // Method used in the CommitTasks test case.
-  void InjectedCommitSequencingTask(DomStorageArea* area) {
+  void InjectedCommitSequencingTask(DOMStorageArea* area) {
     // At this point the OnCommitTimer has run.
     // Verify that it put a commit in flight.
     EXPECT_EQ(1, area->commit_batches_in_flight_);
@@ -54,13 +54,13 @@
   }
 
   // Class used in the CommitChangesAtShutdown test case.
-  class VerifyChangesCommittedDatabase : public DomStorageDatabase {
+  class VerifyChangesCommittedDatabase : public DOMStorageDatabase {
    public:
     VerifyChangesCommittedDatabase() {}
     virtual ~VerifyChangesCommittedDatabase() {
       const base::string16 kKey(ASCIIToUTF16("key"));
       const base::string16 kValue(ASCIIToUTF16("value"));
-      ValuesMap values;
+      DOMStorageValuesMap values;
       ReadAllValues(&values);
       EXPECT_EQ(1u, values.size());
       EXPECT_EQ(kValue, values[kKey].string());
@@ -71,14 +71,14 @@
   base::MessageLoop message_loop_;
 };
 
-TEST_F(DomStorageAreaTest, DomStorageAreaBasics) {
-  scoped_refptr<DomStorageArea> area(
-      new DomStorageArea(1, std::string(), kOrigin, NULL, NULL));
+TEST_F(DOMStorageAreaTest, DOMStorageAreaBasics) {
+  scoped_refptr<DOMStorageArea> area(
+      new DOMStorageArea(1, std::string(), kOrigin, NULL, NULL));
   base::string16 old_value;
   base::NullableString16 old_nullable_value;
-  scoped_refptr<DomStorageArea> copy;
+  scoped_refptr<DOMStorageArea> copy;
 
-  // We don't focus on the underlying DomStorageMap functionality
+  // We don't focus on the underlying DOMStorageMap functionality
   // since that's covered by seperate unit tests.
   EXPECT_EQ(kOrigin, area->origin());
   EXPECT_EQ(1, area->namespace_id());
@@ -122,17 +122,17 @@
   EXPECT_FALSE(area->Clear());
 }
 
-TEST_F(DomStorageAreaTest, BackingDatabaseOpened) {
+TEST_F(DOMStorageAreaTest, BackingDatabaseOpened) {
   const int64 kSessionStorageNamespaceId = kLocalStorageNamespaceId + 1;
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   const base::FilePath kExpectedOriginFilePath = temp_dir.path().Append(
-      DomStorageArea::DatabaseFileNameFromOrigin(kOrigin));
+      DOMStorageArea::DatabaseFileNameFromOrigin(kOrigin));
 
   // No directory, backing should be null.
   {
-    scoped_refptr<DomStorageArea> area(
-        new DomStorageArea(kOrigin, base::FilePath(), NULL));
+    scoped_refptr<DOMStorageArea> area(
+        new DOMStorageArea(kOrigin, base::FilePath(), NULL));
     EXPECT_EQ(NULL, area->backing_.get());
     EXPECT_TRUE(area->is_initial_import_done_);
     EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
@@ -141,8 +141,8 @@
   // Valid directory and origin but no session storage backing. Backing should
   // be null.
   {
-    scoped_refptr<DomStorageArea> area(
-        new DomStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
+    scoped_refptr<DOMStorageArea> area(
+        new DOMStorageArea(kSessionStorageNamespaceId, std::string(), kOrigin,
                            NULL, NULL));
     EXPECT_EQ(NULL, area->backing_.get());
     EXPECT_TRUE(area->is_initial_import_done_);
@@ -156,15 +156,15 @@
     EXPECT_FALSE(base::PathExists(kExpectedOriginFilePath));
   }
 
-  // This should set up a DomStorageArea that is correctly backed to disk.
+  // This should set up a DOMStorageArea that is correctly backed to disk.
   {
-    scoped_refptr<DomStorageArea> area(new DomStorageArea(
+    scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
         kOrigin,
         temp_dir.path(),
-        new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get())));
+        new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
 
     EXPECT_TRUE(area->backing_.get());
-    DomStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
+    DOMStorageDatabase* database = static_cast<LocalStorageDatabaseAdapter*>(
         area->backing_.get())->db_.get();
     EXPECT_FALSE(database->IsOpen());
     EXPECT_FALSE(area->is_initial_import_done_);
@@ -194,21 +194,21 @@
     EXPECT_EQ(kValue, area->GetItem(kKey).string());
 
     // Verify the content made it to the in memory database.
-    ValuesMap values;
+    DOMStorageValuesMap values;
     area->backing_->ReadAllValues(&values);
     EXPECT_EQ(1u, values.size());
     EXPECT_EQ(kValue, values[kKey].string());
   }
 }
 
-TEST_F(DomStorageAreaTest, CommitTasks) {
+TEST_F(DOMStorageAreaTest, CommitTasks) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
-  scoped_refptr<DomStorageArea> area(new DomStorageArea(
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin,
       temp_dir.path(),
-      new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
 
@@ -218,7 +218,7 @@
   EXPECT_EQ(0u, area->Length());
   EXPECT_TRUE(area->is_initial_import_done_);
 
-  ValuesMap values;
+  DOMStorageValuesMap values;
   base::NullableString16 old_value;
 
   // See that changes are batched up.
@@ -266,7 +266,7 @@
   // we'll make an additional SetItem() call.
   base::MessageLoop::current()->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageAreaTest::InjectedCommitSequencingTask,
+      base::Bind(&DOMStorageAreaTest::InjectedCommitSequencingTask,
                  base::Unretained(this),
                  area));
   base::MessageLoop::current()->RunUntilIdle();
@@ -280,20 +280,20 @@
   EXPECT_EQ(kValue2, values[kKey2].string());
 }
 
-TEST_F(DomStorageAreaTest, CommitChangesAtShutdown) {
+TEST_F(DOMStorageAreaTest, CommitChangesAtShutdown) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  scoped_refptr<DomStorageArea> area(new DomStorageArea(
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin,
       temp_dir.path(),
-      new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
 
   // Inject an in-memory db to speed up the test and also to verify
   // the final changes are commited in it's dtor.
   static_cast<LocalStorageDatabaseAdapter*>(area->backing_.get())->db_.reset(
       new VerifyChangesCommittedDatabase());
 
-  ValuesMap values;
+  DOMStorageValuesMap values;
   base::NullableString16 old_value;
   EXPECT_TRUE(area->SetItem(kKey, kValue, &old_value));
   EXPECT_TRUE(area->HasUncommittedChanges());
@@ -307,19 +307,19 @@
   // were committed.
 }
 
-TEST_F(DomStorageAreaTest, DeleteOrigin) {
+TEST_F(DOMStorageAreaTest, DeleteOrigin) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  scoped_refptr<DomStorageArea> area(new DomStorageArea(
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin,
       temp_dir.path(),
-      new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
 
   // This test puts files on disk.
   base::FilePath db_file_path = static_cast<LocalStorageDatabaseAdapter*>(
       area->backing_.get())->db_->file_path();
   base::FilePath db_journal_file_path =
-      DomStorageDatabase::GetJournalFilePath(db_file_path);
+      DOMStorageDatabase::GetJournalFilePath(db_file_path);
 
   // Nothing bad should happen when invoked w/o any files on disk.
   area->DeleteOrigin();
@@ -368,28 +368,28 @@
   EXPECT_FALSE(base::PathExists(db_file_path));
 }
 
-TEST_F(DomStorageAreaTest, PurgeMemory) {
+TEST_F(DOMStorageAreaTest, PurgeMemory) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
-  scoped_refptr<DomStorageArea> area(new DomStorageArea(
+  scoped_refptr<DOMStorageArea> area(new DOMStorageArea(
       kOrigin,
       temp_dir.path(),
-      new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get())));
+      new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get())));
 
   // Inject an in-memory db to speed up the test.
   area->backing_.reset(new LocalStorageDatabaseAdapter());
 
   // Unowned ptrs we use to verify that 'purge' has happened.
-  DomStorageDatabase* original_backing =
+  DOMStorageDatabase* original_backing =
       static_cast<LocalStorageDatabaseAdapter*>(
           area->backing_.get())->db_.get();
-  DomStorageMap* original_map = area->map_.get();
+  DOMStorageMap* original_map = area->map_.get();
 
   // Should do no harm when called on a newly constructed object.
   EXPECT_FALSE(area->is_initial_import_done_);
   area->PurgeMemory();
   EXPECT_FALSE(area->is_initial_import_done_);
-  DomStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
+  DOMStorageDatabase* new_backing = static_cast<LocalStorageDatabaseAdapter*>(
       area->backing_.get())->db_.get();
   EXPECT_EQ(original_backing, new_backing);
   EXPECT_EQ(original_map, area->map_.get());
@@ -425,7 +425,7 @@
   EXPECT_NE(original_map, area->map_.get());
 }
 
-TEST_F(DomStorageAreaTest, DatabaseFileNames) {
+TEST_F(DOMStorageAreaTest, DatabaseFileNames) {
   struct {
     const char* origin;
     const char* file_name;
@@ -444,30 +444,31 @@
 
   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kCases); ++i) {
     GURL origin = GURL(kCases[i].origin).GetOrigin();
-    base::FilePath file_name = base::FilePath().AppendASCII(kCases[i].file_name);
+    base::FilePath file_name =
+        base::FilePath().AppendASCII(kCases[i].file_name);
     base::FilePath journal_file_name =
         base::FilePath().AppendASCII(kCases[i].journal_file_name);
 
     EXPECT_EQ(file_name,
-              DomStorageArea::DatabaseFileNameFromOrigin(origin));
+              DOMStorageArea::DatabaseFileNameFromOrigin(origin));
     EXPECT_EQ(origin,
-              DomStorageArea::OriginFromDatabaseFileName(file_name));
+              DOMStorageArea::OriginFromDatabaseFileName(file_name));
     EXPECT_EQ(journal_file_name,
-              DomStorageDatabase::GetJournalFilePath(file_name));
+              DOMStorageDatabase::GetJournalFilePath(file_name));
   }
 
-  // Also test some DomStorageDatabase::GetJournalFilePath cases here.
+  // Also test some DOMStorageDatabase::GetJournalFilePath cases here.
   base::FilePath parent = base::FilePath().AppendASCII("a").AppendASCII("b");
   EXPECT_EQ(
       parent.AppendASCII("file-journal"),
-      DomStorageDatabase::GetJournalFilePath(parent.AppendASCII("file")));
+      DOMStorageDatabase::GetJournalFilePath(parent.AppendASCII("file")));
   EXPECT_EQ(
       base::FilePath().AppendASCII("-journal"),
-      DomStorageDatabase::GetJournalFilePath(base::FilePath()));
+      DOMStorageDatabase::GetJournalFilePath(base::FilePath()));
   EXPECT_EQ(
       base::FilePath().AppendASCII(".extensiononly-journal"),
-      DomStorageDatabase::GetJournalFilePath(
+      DOMStorageDatabase::GetJournalFilePath(
           base::FilePath().AppendASCII(".extensiononly")));
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_browsertest.cc b/content/browser/dom_storage/dom_storage_browsertest.cc
index d160dac..54da50a 100644
--- a/content/browser/dom_storage/dom_storage_browsertest.cc
+++ b/content/browser/dom_storage/dom_storage_browsertest.cc
@@ -4,21 +4,21 @@
 
 #include "base/path_service.h"
 #include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/shell/shell.h"
 #include "content/test/content_browser_test.h"
 #include "content/test/content_browser_test_utils.h"
 #include "net/base/net_util.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 namespace content {
 
-// This browser test is aimed towards exercising the DomStorage system
+// This browser test is aimed towards exercising the DOMStorage system
 // from end-to-end.
-class DomStorageBrowserTest : public ContentBrowserTest {
+class DOMStorageBrowserTest : public ContentBrowserTest {
  public:
-  DomStorageBrowserTest() {}
+  DOMStorageBrowserTest() {}
 
   void SimpleTest(const GURL& test_url, bool incognito) {
     // The test page will perform tests then navigate to either
@@ -40,11 +40,11 @@
 static const bool kIncognito = true;
 static const bool kNotIncognito = false;
 
-IN_PROC_BROWSER_TEST_F(DomStorageBrowserTest, SanityCheck) {
+IN_PROC_BROWSER_TEST_F(DOMStorageBrowserTest, SanityCheck) {
   SimpleTest(GetTestUrl("dom_storage", "sanity_check.html"), kNotIncognito);
 }
 
-IN_PROC_BROWSER_TEST_F(DomStorageBrowserTest, SanityCheckIncognito) {
+IN_PROC_BROWSER_TEST_F(DOMStorageBrowserTest, SanityCheckIncognito) {
   SimpleTest(GetTestUrl("dom_storage", "sanity_check.html"), kIncognito);
 }
 
diff --git a/content/browser/dom_storage/dom_storage_context_impl.cc b/content/browser/dom_storage/dom_storage_context_impl.cc
index f790ecd..dd1f33e 100644
--- a/content/browser/dom_storage/dom_storage_context_impl.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl.cc
@@ -6,171 +6,417 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/files/file_path.h"
-#include "base/message_loop/message_loop_proxy.h"
-#include "content/browser/dom_storage/session_storage_namespace_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-
-using dom_storage::DomStorageArea;
-using dom_storage::DomStorageContext;
-using dom_storage::DomStorageTaskRunner;
-using dom_storage::DomStorageWorkerPoolTaskRunner;
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/guid.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/session_storage_database.h"
+#include "content/common/dom_storage/dom_storage_types.h"
+#include "content/public/browser/dom_storage_context.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_usage_info.h"
+#include "webkit/browser/quota/special_storage_policy.h"
 
 namespace content {
-namespace {
 
-const char kLocalStorageDirectory[] = "Local Storage";
-const char kSessionStorageDirectory[] = "Session Storage";
-
-void InvokeLocalStorageUsageCallbackHelper(
-      const DOMStorageContext::GetLocalStorageUsageCallback& callback,
-      const std::vector<dom_storage::LocalStorageUsageInfo>* infos) {
-  callback.Run(*infos);
-}
-
-void GetLocalStorageUsageHelper(
-    base::MessageLoopProxy* reply_loop,
-    DomStorageContext* context,
-    const DOMStorageContext::GetLocalStorageUsageCallback& callback) {
-  std::vector<dom_storage::LocalStorageUsageInfo>* infos =
-      new std::vector<dom_storage::LocalStorageUsageInfo>;
-  context->GetLocalStorageUsage(infos, true);
-  reply_loop->PostTask(
-      FROM_HERE,
-      base::Bind(&InvokeLocalStorageUsageCallbackHelper,
-                 callback, base::Owned(infos)));
-}
-
-void InvokeSessionStorageUsageCallbackHelper(
-      const DOMStorageContext::GetSessionStorageUsageCallback& callback,
-      const std::vector<dom_storage::SessionStorageUsageInfo>* infos) {
-  callback.Run(*infos);
-}
-
-void GetSessionStorageUsageHelper(
-    base::MessageLoopProxy* reply_loop,
-    DomStorageContext* context,
-    const DOMStorageContext::GetSessionStorageUsageCallback& callback) {
-  std::vector<dom_storage::SessionStorageUsageInfo>* infos =
-      new std::vector<dom_storage::SessionStorageUsageInfo>;
-  context->GetSessionStorageUsage(infos);
-  reply_loop->PostTask(
-      FROM_HERE,
-      base::Bind(&InvokeSessionStorageUsageCallbackHelper,
-                 callback, base::Owned(infos)));
-}
-
-}  // namespace
+static const int kSessionStoraceScavengingSeconds = 60;
 
 DOMStorageContextImpl::DOMStorageContextImpl(
-    const base::FilePath& data_path,
-    quota::SpecialStoragePolicy* special_storage_policy) {
-  base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
-  context_ = new dom_storage::DomStorageContext(
-      data_path.empty() ? data_path
-                        : data_path.AppendASCII(kLocalStorageDirectory),
-      data_path.empty() ? data_path
-                        : data_path.AppendASCII(kSessionStorageDirectory),
-      special_storage_policy,
-      new DomStorageWorkerPoolTaskRunner(
-          worker_pool,
-          worker_pool->GetNamedSequenceToken("dom_storage_primary"),
-          worker_pool->GetNamedSequenceToken("dom_storage_commit"),
-          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)
-              .get()));
+    const base::FilePath& localstorage_directory,
+    const base::FilePath& sessionstorage_directory,
+    quota::SpecialStoragePolicy* special_storage_policy,
+    DOMStorageTaskRunner* task_runner)
+    : localstorage_directory_(localstorage_directory),
+      sessionstorage_directory_(sessionstorage_directory),
+      task_runner_(task_runner),
+      is_shutdown_(false),
+      force_keep_session_state_(false),
+      special_storage_policy_(special_storage_policy),
+      scavenging_started_(false) {
+  // AtomicSequenceNum starts at 0 but we want to start session
+  // namespace ids at one since zero is reserved for the
+  // kLocalStorageNamespaceId.
+  session_id_sequence_.GetNext();
 }
 
 DOMStorageContextImpl::~DOMStorageContextImpl() {
+  if (session_storage_database_.get()) {
+    // SessionStorageDatabase shouldn't be deleted right away: deleting it will
+    // potentially involve waiting in leveldb::DBImpl::~DBImpl, and waiting
+    // shouldn't happen on this thread.
+    SessionStorageDatabase* to_release = session_storage_database_.get();
+    to_release->AddRef();
+    session_storage_database_ = NULL;
+    task_runner_->PostShutdownBlockingTask(
+        FROM_HERE,
+        DOMStorageTaskRunner::COMMIT_SEQUENCE,
+        base::Bind(&SessionStorageDatabase::Release,
+                   base::Unretained(to_release)));
+  }
+}
+
+DOMStorageNamespace* DOMStorageContextImpl::GetStorageNamespace(
+    int64 namespace_id) {
+  if (is_shutdown_)
+    return NULL;
+  StorageNamespaceMap::iterator found = namespaces_.find(namespace_id);
+  if (found == namespaces_.end()) {
+    if (namespace_id == kLocalStorageNamespaceId) {
+      if (!localstorage_directory_.empty()) {
+        if (!file_util::CreateDirectory(localstorage_directory_)) {
+          LOG(ERROR) << "Failed to create 'Local Storage' directory,"
+                        " falling back to in-memory only.";
+          localstorage_directory_ = base::FilePath();
+        }
+      }
+      DOMStorageNamespace* local =
+          new DOMStorageNamespace(localstorage_directory_, task_runner_.get());
+      namespaces_[kLocalStorageNamespaceId] = local;
+      return local;
+    }
+    return NULL;
+  }
+  return found->second.get();
 }
 
 void DOMStorageContextImpl::GetLocalStorageUsage(
-    const GetLocalStorageUsageCallback& callback) {
-  DCHECK(context_.get());
-  context_->task_runner()
-      ->PostShutdownBlockingTask(FROM_HERE,
-                                 DomStorageTaskRunner::PRIMARY_SEQUENCE,
-                                 base::Bind(&GetLocalStorageUsageHelper,
-                                            base::MessageLoopProxy::current(),
-                                            context_,
-                                            callback));
+    std::vector<LocalStorageUsageInfo>* infos,
+    bool include_file_info) {
+  if (localstorage_directory_.empty())
+    return;
+  base::FileEnumerator enumerator(localstorage_directory_, false,
+                                  base::FileEnumerator::FILES);
+  for (base::FilePath path = enumerator.Next(); !path.empty();
+       path = enumerator.Next()) {
+    if (path.MatchesExtension(DOMStorageArea::kDatabaseFileExtension)) {
+      LocalStorageUsageInfo info;
+      info.origin = DOMStorageArea::OriginFromDatabaseFileName(path);
+      if (include_file_info) {
+        base::FileEnumerator::FileInfo find_info = enumerator.GetInfo();
+        info.data_size = find_info.GetSize();
+        info.last_modified = find_info.GetLastModifiedTime();
+      }
+      infos->push_back(info);
+    }
+  }
 }
 
 void DOMStorageContextImpl::GetSessionStorageUsage(
-    const GetSessionStorageUsageCallback& callback) {
-  DCHECK(context_.get());
-  context_->task_runner()
-      ->PostShutdownBlockingTask(FROM_HERE,
-                                 DomStorageTaskRunner::PRIMARY_SEQUENCE,
-                                 base::Bind(&GetSessionStorageUsageHelper,
-                                            base::MessageLoopProxy::current(),
-                                            context_,
-                                            callback));
+    std::vector<SessionStorageUsageInfo>* infos) {
+  if (!session_storage_database_.get())
+    return;
+  std::map<std::string, std::vector<GURL> > namespaces_and_origins;
+  session_storage_database_->ReadNamespacesAndOrigins(
+      &namespaces_and_origins);
+  for (std::map<std::string, std::vector<GURL> >::const_iterator it =
+           namespaces_and_origins.begin();
+       it != namespaces_and_origins.end(); ++it) {
+    for (std::vector<GURL>::const_iterator origin_it = it->second.begin();
+         origin_it != it->second.end(); ++origin_it) {
+      SessionStorageUsageInfo info;
+      info.persistent_namespace_id = it->first;
+      info.origin = *origin_it;
+      infos->push_back(info);
+    }
+  }
 }
 
 void DOMStorageContextImpl::DeleteLocalStorage(const GURL& origin) {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&DomStorageContext::DeleteLocalStorage, context_, origin));
+  DCHECK(!is_shutdown_);
+  DOMStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
+  local->DeleteLocalStorageOrigin(origin);
+  // Synthesize a 'cleared' event if the area is open so CachedAreas in
+  // renderers get emptied out too.
+  DOMStorageArea* area = local->GetOpenStorageArea(origin);
+  if (area)
+    NotifyAreaCleared(area, origin);
 }
 
 void DOMStorageContextImpl::DeleteSessionStorage(
-    const dom_storage::SessionStorageUsageInfo& usage_info) {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(
-          &DomStorageContext::DeleteSessionStorage, context_, usage_info));
-}
-
-void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() {
-  DCHECK(context_.get());
-  context_->SetSaveSessionStorageOnDisk();
-}
-
-scoped_refptr<SessionStorageNamespace>
-DOMStorageContextImpl::RecreateSessionStorage(
-    const std::string& persistent_id) {
-  return scoped_refptr<SessionStorageNamespace>(
-      new SessionStorageNamespaceImpl(this, persistent_id));
-}
-
-void DOMStorageContextImpl::StartScavengingUnusedSessionStorage() {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&DomStorageContext::StartScavengingUnusedSessionStorage,
-                 context_));
+    const SessionStorageUsageInfo& usage_info) {
+  DCHECK(!is_shutdown_);
+  DOMStorageNamespace* dom_storage_namespace = NULL;
+  std::map<std::string, int64>::const_iterator it =
+      persistent_namespace_id_to_namespace_id_.find(
+          usage_info.persistent_namespace_id);
+  if (it != persistent_namespace_id_to_namespace_id_.end()) {
+    dom_storage_namespace = GetStorageNamespace(it->second);
+  } else {
+    int64 namespace_id = AllocateSessionId();
+    CreateSessionNamespace(namespace_id, usage_info.persistent_namespace_id);
+    dom_storage_namespace = GetStorageNamespace(namespace_id);
+  }
+  dom_storage_namespace->DeleteSessionStorageOrigin(usage_info.origin);
+  // Synthesize a 'cleared' event if the area is open so CachedAreas in
+  // renderers get emptied out too.
+  DOMStorageArea* area =
+      dom_storage_namespace->GetOpenStorageArea(usage_info.origin);
+  if (area)
+    NotifyAreaCleared(area, usage_info.origin);
 }
 
 void DOMStorageContextImpl::PurgeMemory() {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&DomStorageContext::PurgeMemory, context_));
-}
-
-void DOMStorageContextImpl::SetForceKeepSessionState() {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&DomStorageContext::SetForceKeepSessionState, context_));
+  // We can only purge memory from the local storage namespace
+  // which is backed by disk.
+  // TODO(marja): Purge sessionStorage, too. (Requires changes to the FastClear
+  // functionality.)
+  StorageNamespaceMap::iterator found =
+      namespaces_.find(kLocalStorageNamespaceId);
+  if (found != namespaces_.end())
+    found->second->PurgeMemory(DOMStorageNamespace::PURGE_AGGRESSIVE);
 }
 
 void DOMStorageContextImpl::Shutdown() {
-  DCHECK(context_.get());
-  context_->task_runner()->PostShutdownBlockingTask(
-      FROM_HERE,
-      DomStorageTaskRunner::PRIMARY_SEQUENCE,
-      base::Bind(&DomStorageContext::Shutdown, context_));
+  is_shutdown_ = true;
+  StorageNamespaceMap::const_iterator it = namespaces_.begin();
+  for (; it != namespaces_.end(); ++it)
+    it->second->Shutdown();
+
+  if (localstorage_directory_.empty() && !session_storage_database_.get())
+    return;
+
+  // Respect the content policy settings about what to
+  // keep and what to discard.
+  if (force_keep_session_state_)
+    return;  // Keep everything.
+
+  bool has_session_only_origins =
+      special_storage_policy_.get() &&
+      special_storage_policy_->HasSessionOnlyOrigins();
+
+  if (has_session_only_origins) {
+    // We may have to delete something. We continue on the
+    // commit sequence after area shutdown tasks have cycled
+    // thru that sequence (and closed their database files).
+    bool success = task_runner_->PostShutdownBlockingTask(
+        FROM_HERE,
+        DOMStorageTaskRunner::COMMIT_SEQUENCE,
+        base::Bind(&DOMStorageContextImpl::ClearSessionOnlyOrigins, this));
+    DCHECK(success);
+  }
+}
+
+void DOMStorageContextImpl::AddEventObserver(EventObserver* observer) {
+  event_observers_.AddObserver(observer);
+}
+
+void DOMStorageContextImpl::RemoveEventObserver(EventObserver* observer) {
+  event_observers_.RemoveObserver(observer);
+}
+
+void DOMStorageContextImpl::NotifyItemSet(
+    const DOMStorageArea* area,
+    const base::string16& key,
+    const base::string16& new_value,
+    const base::NullableString16& old_value,
+    const GURL& page_url) {
+  FOR_EACH_OBSERVER(
+      EventObserver, event_observers_,
+      OnDOMStorageItemSet(area, key, new_value, old_value, page_url));
+}
+
+void DOMStorageContextImpl::NotifyItemRemoved(
+    const DOMStorageArea* area,
+    const base::string16& key,
+    const base::string16& old_value,
+    const GURL& page_url) {
+  FOR_EACH_OBSERVER(
+      EventObserver, event_observers_,
+      OnDOMStorageItemRemoved(area, key, old_value, page_url));
+}
+
+void DOMStorageContextImpl::NotifyAreaCleared(
+    const DOMStorageArea* area,
+    const GURL& page_url) {
+  FOR_EACH_OBSERVER(
+      EventObserver, event_observers_,
+      OnDOMStorageAreaCleared(area, page_url));
+}
+
+std::string DOMStorageContextImpl::AllocatePersistentSessionId() {
+  std::string guid = base::GenerateGUID();
+  std::replace(guid.begin(), guid.end(), '-', '_');
+  return guid;
+}
+
+void DOMStorageContextImpl::CreateSessionNamespace(
+    int64 namespace_id,
+    const std::string& persistent_namespace_id) {
+  if (is_shutdown_)
+    return;
+  DCHECK(namespace_id != kLocalStorageNamespaceId);
+  DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
+  namespaces_[namespace_id] = new DOMStorageNamespace(
+      namespace_id, persistent_namespace_id, session_storage_database_.get(),
+      task_runner_.get());
+  persistent_namespace_id_to_namespace_id_[persistent_namespace_id] =
+      namespace_id;
+}
+
+void DOMStorageContextImpl::DeleteSessionNamespace(
+    int64 namespace_id, bool should_persist_data) {
+  DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
+  StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
+  if (it == namespaces_.end())
+    return;
+  std::string persistent_namespace_id = it->second->persistent_namespace_id();
+  if (session_storage_database_.get()) {
+    if (!should_persist_data) {
+      task_runner_->PostShutdownBlockingTask(
+          FROM_HERE,
+          DOMStorageTaskRunner::COMMIT_SEQUENCE,
+          base::Bind(
+              base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
+              session_storage_database_,
+              persistent_namespace_id));
+    } else {
+      // Ensure that the data gets committed before we shut down.
+      it->second->Shutdown();
+      if (!scavenging_started_) {
+        // Protect the persistent namespace ID from scavenging.
+        protected_persistent_session_ids_.insert(persistent_namespace_id);
+      }
+    }
+  }
+  persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
+  namespaces_.erase(namespace_id);
+}
+
+void DOMStorageContextImpl::CloneSessionNamespace(
+    int64 existing_id, int64 new_id,
+    const std::string& new_persistent_id) {
+  if (is_shutdown_)
+    return;
+  DCHECK_NE(kLocalStorageNamespaceId, existing_id);
+  DCHECK_NE(kLocalStorageNamespaceId, new_id);
+  StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
+  if (found != namespaces_.end())
+    namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id);
+  else
+    CreateSessionNamespace(new_id, new_persistent_id);
+}
+
+void DOMStorageContextImpl::ClearSessionOnlyOrigins() {
+  if (!localstorage_directory_.empty()) {
+    std::vector<LocalStorageUsageInfo> infos;
+    const bool kDontIncludeFileInfo = false;
+    GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
+    for (size_t i = 0; i < infos.size(); ++i) {
+      const GURL& origin = infos[i].origin;
+      if (special_storage_policy_->IsStorageProtected(origin))
+        continue;
+      if (!special_storage_policy_->IsStorageSessionOnly(origin))
+        continue;
+
+      base::FilePath database_file_path = localstorage_directory_.Append(
+          DOMStorageArea::DatabaseFileNameFromOrigin(origin));
+      sql::Connection::Delete(database_file_path);
+    }
+  }
+  if (session_storage_database_.get()) {
+    std::vector<SessionStorageUsageInfo> infos;
+    GetSessionStorageUsage(&infos);
+    for (size_t i = 0; i < infos.size(); ++i) {
+      const GURL& origin = infos[i].origin;
+      if (special_storage_policy_->IsStorageProtected(origin))
+        continue;
+      if (!special_storage_policy_->IsStorageSessionOnly(origin))
+        continue;
+      session_storage_database_->DeleteArea(infos[i].persistent_namespace_id,
+                                            origin);
+    }
+  }
+}
+
+void DOMStorageContextImpl::SetSaveSessionStorageOnDisk() {
+  DCHECK(namespaces_.empty());
+  if (!sessionstorage_directory_.empty()) {
+    session_storage_database_ = new SessionStorageDatabase(
+        sessionstorage_directory_);
+  }
+}
+
+void DOMStorageContextImpl::StartScavengingUnusedSessionStorage() {
+  if (session_storage_database_.get()) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE, base::Bind(&DOMStorageContextImpl::FindUnusedNamespaces,
+                              this),
+        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+  }
+}
+
+void DOMStorageContextImpl::FindUnusedNamespaces() {
+  DCHECK(session_storage_database_.get());
+  if (scavenging_started_)
+    return;
+  scavenging_started_ = true;
+  std::set<std::string> namespace_ids_in_use;
+  for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
+       it != namespaces_.end(); ++it)
+    namespace_ids_in_use.insert(it->second->persistent_namespace_id());
+  std::set<std::string> protected_persistent_session_ids;
+  protected_persistent_session_ids.swap(protected_persistent_session_ids_);
+  task_runner_->PostShutdownBlockingTask(
+      FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
+      base::Bind(
+          &DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence,
+          this, namespace_ids_in_use, protected_persistent_session_ids));
+}
+
+void DOMStorageContextImpl::FindUnusedNamespacesInCommitSequence(
+    const std::set<std::string>& namespace_ids_in_use,
+    const std::set<std::string>& protected_persistent_session_ids) {
+  DCHECK(session_storage_database_.get());
+  // Delete all namespaces which don't have an associated DOMStorageNamespace
+  // alive.
+  std::map<std::string, std::vector<GURL> > namespaces_and_origins;
+  session_storage_database_->ReadNamespacesAndOrigins(&namespaces_and_origins);
+  for (std::map<std::string, std::vector<GURL> >::const_iterator it =
+           namespaces_and_origins.begin();
+       it != namespaces_and_origins.end(); ++it) {
+    if (namespace_ids_in_use.find(it->first) == namespace_ids_in_use.end() &&
+        protected_persistent_session_ids.find(it->first) ==
+        protected_persistent_session_ids.end()) {
+      deletable_persistent_namespace_ids_.push_back(it->first);
+    }
+  }
+  if (!deletable_persistent_namespace_ids_.empty()) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE, base::Bind(
+            &DOMStorageContextImpl::DeleteNextUnusedNamespace,
+            this),
+        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+  }
+}
+
+void DOMStorageContextImpl::DeleteNextUnusedNamespace() {
+  if (is_shutdown_)
+    return;
+  task_runner_->PostShutdownBlockingTask(
+        FROM_HERE, DOMStorageTaskRunner::COMMIT_SEQUENCE,
+        base::Bind(
+            &DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence,
+            this));
+}
+
+void DOMStorageContextImpl::DeleteNextUnusedNamespaceInCommitSequence() {
+  if (deletable_persistent_namespace_ids_.empty())
+    return;
+  const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
+  session_storage_database_->DeleteNamespace(persistent_id);
+  deletable_persistent_namespace_ids_.pop_back();
+  if (!deletable_persistent_namespace_ids_.empty()) {
+    task_runner_->PostDelayedTask(
+        FROM_HERE, base::Bind(
+            &DOMStorageContextImpl::DeleteNextUnusedNamespace,
+            this),
+        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
+  }
 }
 
 }  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_impl.h b/content/browser/dom_storage/dom_storage_context_impl.h
index a418ea3..8f55656 100644
--- a/content/browser/dom_storage/dom_storage_context_impl.h
+++ b/content/browser/dom_storage/dom_storage_context_impl.h
@@ -5,15 +5,24 @@
 #ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_IMPL_H_
 #define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_IMPL_H_
 
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/atomic_sequence_num.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
 #include "base/memory/ref_counted.h"
-#include "content/public/browser/dom_storage_context.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
 
 namespace base {
 class FilePath;
-}
-
-namespace dom_storage {
-class DomStorageContext;
+class NullableString16;
+class Time;
 }
 
 namespace quota {
@@ -22,52 +31,202 @@
 
 namespace content {
 
-// This is owned by BrowserContext (aka Profile) and encapsulates all
-// per-profile dom storage state.
-class CONTENT_EXPORT DOMStorageContextImpl :
-    NON_EXPORTED_BASE(public DOMStorageContext),
-    public base::RefCountedThreadSafe<DOMStorageContextImpl> {
+class DOMStorageArea;
+class DOMStorageNamespace;
+class DOMStorageSession;
+class DOMStorageTaskRunner;
+class SessionStorageDatabase;
+struct LocalStorageUsageInfo;
+struct SessionStorageUsageInfo;
+
+// The Context is the root of an object containment hierachy for
+// Namespaces and Areas related to the owning profile.
+// One instance is allocated in the main process for each profile,
+// instance methods should be called serially in the background as
+// determined by the task_runner. Specifcally not on chrome's non-blocking
+// IO thread since these methods can result in blocking file io.
+//
+// In general terms, the DOMStorage object relationships are...
+//   Contexts (per-profile) own Namespaces which own Areas which share Maps.
+//   Hosts(per-renderer) refer to Namespaces and Areas open in its renderer.
+//   Sessions (per-tab) cause the creation and deletion of session Namespaces.
+//
+// Session Namespaces are cloned by initially making a shallow copy of
+// all contained Areas, the shallow copies refer to the same refcounted Map,
+// and does a deep copy-on-write if needed.
+//
+// Classes intended to be used by an embedder are DOMStorageContextImpl,
+// DOMStorageHost, and DOMStorageSession. The other classes are for
+// internal consumption.
+class CONTENT_EXPORT DOMStorageContextImpl
+    : public base::RefCountedThreadSafe<DOMStorageContextImpl> {
  public:
-  // If |data_path| is empty, nothing will be saved to disk.
-  DOMStorageContextImpl(const base::FilePath& data_path,
-                        quota::SpecialStoragePolicy* special_storage_policy);
+  // An interface for observing Local and Session Storage events on the
+  // background thread.
+  class EventObserver {
+   public:
+    // |old_value| may be null on initial insert.
+    virtual void OnDOMStorageItemSet(
+        const DOMStorageArea* area,
+        const base::string16& key,
+        const base::string16& new_value,
+        const base::NullableString16& old_value,
+        const GURL& page_url) = 0;
+    virtual void OnDOMStorageItemRemoved(
+        const DOMStorageArea* area,
+        const base::string16& key,
+        const base::string16& old_value,
+        const GURL& page_url) = 0;
+    virtual void OnDOMStorageAreaCleared(
+        const DOMStorageArea* area,
+        const GURL& page_url) = 0;
 
-  // DOMStorageContext implementation.
-  virtual void GetLocalStorageUsage(
-      const GetLocalStorageUsageCallback& callback) OVERRIDE;
-  virtual void GetSessionStorageUsage(
-      const GetSessionStorageUsageCallback& callback) OVERRIDE;
-  virtual void DeleteLocalStorage(const GURL& origin) OVERRIDE;
-  virtual void DeleteSessionStorage(
-      const dom_storage::SessionStorageUsageInfo& usage_info) OVERRIDE;
-  virtual void SetSaveSessionStorageOnDisk() OVERRIDE;
-  virtual scoped_refptr<SessionStorageNamespace>
-      RecreateSessionStorage(const std::string& persistent_id) OVERRIDE;
-  virtual void StartScavengingUnusedSessionStorage() OVERRIDE;
+   protected:
+    virtual ~EventObserver() {}
+  };
 
-  // Called to free up memory that's not strictly needed.
+  // |localstorage_directory| and |sessionstorage_directory| may be empty
+  // for incognito browser contexts.
+  DOMStorageContextImpl(
+      const base::FilePath& localstorage_directory,
+      const base::FilePath& sessionstorage_directory,
+      quota::SpecialStoragePolicy* special_storage_policy,
+      DOMStorageTaskRunner* task_runner);
+
+  // Returns the directory path for localStorage, or an empty directory, if
+  // there is no backing on disk.
+  const base::FilePath& localstorage_directory() {
+    return localstorage_directory_;
+  }
+
+  // Returns the directory path for sessionStorage, or an empty directory, if
+  // there is no backing on disk.
+  const base::FilePath& sessionstorage_directory() {
+    return sessionstorage_directory_;
+  }
+
+  DOMStorageTaskRunner* task_runner() const { return task_runner_.get(); }
+  DOMStorageNamespace* GetStorageNamespace(int64 namespace_id);
+
+  void GetLocalStorageUsage(std::vector<LocalStorageUsageInfo>* infos,
+                            bool include_file_info);
+  void GetSessionStorageUsage(std::vector<SessionStorageUsageInfo>* infos);
+  void DeleteLocalStorage(const GURL& origin);
+  void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info);
   void PurgeMemory();
 
   // Used by content settings to alter the behavior around
   // what data to keep and what data to discard at shutdown.
   // The policy is not so straight forward to describe, see
   // the implementation for details.
-  void SetForceKeepSessionState();
+  void SetForceKeepSessionState() {
+    force_keep_session_state_ = true;
+  }
 
-  // Called when the BrowserContext/Profile is going away.
+  // Called when the owning BrowserContext is ending.
+  // Schedules the commit of any unsaved changes and will delete
+  // and keep data on disk per the content settings and special storage
+  // policies. Contained areas and namespaces will stop functioning after
+  // this method has been called.
   void Shutdown();
 
+  // Methods to add, remove, and notify EventObservers.
+  void AddEventObserver(EventObserver* observer);
+  void RemoveEventObserver(EventObserver* observer);
+  void NotifyItemSet(
+      const DOMStorageArea* area,
+      const base::string16& key,
+      const base::string16& new_value,
+      const base::NullableString16& old_value,
+      const GURL& page_url);
+  void NotifyItemRemoved(
+      const DOMStorageArea* area,
+      const base::string16& key,
+      const base::string16& old_value,
+      const GURL& page_url);
+  void NotifyAreaCleared(
+      const DOMStorageArea* area,
+      const GURL& page_url);
+
+  // May be called on any thread.
+  int64 AllocateSessionId() {
+    return session_id_sequence_.GetNext();
+  }
+
+  std::string AllocatePersistentSessionId();
+
+  // Must be called on the background thread.
+  void CreateSessionNamespace(int64 namespace_id,
+                              const std::string& persistent_namespace_id);
+  void DeleteSessionNamespace(int64 namespace_id, bool should_persist_data);
+  void CloneSessionNamespace(int64 existing_id, int64 new_id,
+                             const std::string& new_persistent_id);
+
+  // Starts backing sessionStorage on disk. This function must be called right
+  // after DOMStorageContextImpl is created, before it's used.
+  void SetSaveSessionStorageOnDisk();
+
+  // Deletes all namespaces which don't have an associated DOMStorageNamespace
+  // alive. This function is used for deleting possible leftover data after an
+  // unclean exit.
+  void StartScavengingUnusedSessionStorage();
+
  private:
-  friend class DOMStorageMessageFilter;  // for access to context()
-  friend class SessionStorageNamespaceImpl;  // ditto
+  friend class DOMStorageContextImplTest;
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageContextImplTest, Basics);
   friend class base::RefCountedThreadSafe<DOMStorageContextImpl>;
+  typedef std::map<int64, scoped_refptr<DOMStorageNamespace> >
+      StorageNamespaceMap;
 
-  virtual ~DOMStorageContextImpl();
-  dom_storage::DomStorageContext* context() const { return context_.get(); }
+  ~DOMStorageContextImpl();
 
-  scoped_refptr<dom_storage::DomStorageContext> context_;
+  void ClearSessionOnlyOrigins();
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContextImpl);
+  // For scavenging unused sessionStorages.
+  void FindUnusedNamespaces();
+  void FindUnusedNamespacesInCommitSequence(
+      const std::set<std::string>& namespace_ids_in_use,
+      const std::set<std::string>& protected_persistent_session_ids);
+  void DeleteNextUnusedNamespace();
+  void DeleteNextUnusedNamespaceInCommitSequence();
+
+  // Collection of namespaces keyed by id.
+  StorageNamespaceMap namespaces_;
+
+  // Where localstorage data is stored, maybe empty for the incognito use case.
+  base::FilePath localstorage_directory_;
+
+  // Where sessionstorage data is stored, maybe empty for the incognito use
+  // case. Always empty until the file-backed session storage feature is
+  // implemented.
+  base::FilePath sessionstorage_directory_;
+
+  // Used to schedule sequenced background tasks.
+  scoped_refptr<DOMStorageTaskRunner> task_runner_;
+
+  // List of objects observing local storage events.
+  ObserverList<EventObserver> event_observers_;
+
+  // We use a 32 bit identifier for per tab storage sessions.
+  // At a tab per second, this range is large enough for 68 years.
+  base::AtomicSequenceNumber session_id_sequence_;
+
+  bool is_shutdown_;
+  bool force_keep_session_state_;
+  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
+  scoped_refptr<SessionStorageDatabase> session_storage_database_;
+
+  // For cleaning up unused namespaces gradually.
+  bool scavenging_started_;
+  std::vector<std::string> deletable_persistent_namespace_ids_;
+
+  // Persistent namespace IDs to protect from gradual deletion (they will
+  // be needed for session restore).
+  std::set<std::string> protected_persistent_session_ids_;
+
+  // Mapping between persistent namespace IDs and namespace IDs for
+  // sessionStorage.
+  std::map<std::string, int64> persistent_namespace_id_to_namespace_id_;
 };
 
 }  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_context_unittest.cc b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
similarity index 77%
rename from webkit/browser/dom_storage/dom_storage_context_unittest.cc
rename to content/browser/dom_storage/dom_storage_context_impl_unittest.cc
index 8c0d155..27aaefb 100644
--- a/webkit/browser/dom_storage/dom_storage_context_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_context_impl_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
 
@@ -10,19 +10,20 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_usage_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/browser/dom_storage/dom_storage_namespace.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
 #include "webkit/browser/quota/mock_special_storage_policy.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
-class DomStorageContextTest : public testing::Test {
+class DOMStorageContextImplTest : public testing::Test {
  public:
-  DomStorageContextTest()
+  DOMStorageContextImplTest()
     : kOrigin(GURL("http://dom_storage/")),
       kKey(ASCIIToUTF16("key")),
       kValue(ASCIIToUTF16("value")),
@@ -40,11 +41,11 @@
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     storage_policy_ = new quota::MockSpecialStoragePolicy;
     task_runner_ =
-        new MockDomStorageTaskRunner(base::MessageLoopProxy::current().get());
-    context_ = new DomStorageContext(temp_dir_.path(),
-                                     base::FilePath(),
-                                     storage_policy_.get(),
-                                     task_runner_.get());
+        new MockDOMStorageTaskRunner(base::MessageLoopProxy::current().get());
+    context_ = new DOMStorageContextImpl(temp_dir_.path(),
+                                         base::FilePath(),
+                                         storage_policy_.get(),
+                                         task_runner_.get());
   }
 
   virtual void TearDown() {
@@ -53,8 +54,9 @@
 
   void VerifySingleOriginRemains(const GURL& origin) {
     // Use a new instance to examine the contexts of temp_dir_.
-    scoped_refptr<DomStorageContext> context =
-        new DomStorageContext(temp_dir_.path(), base::FilePath(), NULL, NULL);
+    scoped_refptr<DOMStorageContextImpl> context =
+        new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(),
+                                  NULL, NULL);
     std::vector<LocalStorageUsageInfo> infos;
     context->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
     ASSERT_EQ(1u, infos.size());
@@ -65,12 +67,12 @@
   base::MessageLoop message_loop_;
   base::ScopedTempDir temp_dir_;
   scoped_refptr<quota::MockSpecialStoragePolicy> storage_policy_;
-  scoped_refptr<MockDomStorageTaskRunner> task_runner_;
-  scoped_refptr<DomStorageContext> context_;
-  DISALLOW_COPY_AND_ASSIGN(DomStorageContextTest);
+  scoped_refptr<MockDOMStorageTaskRunner> task_runner_;
+  scoped_refptr<DOMStorageContextImpl> context_;
+  DISALLOW_COPY_AND_ASSIGN(DOMStorageContextImplTest);
 };
 
-TEST_F(DomStorageContextTest, Basics) {
+TEST_F(DOMStorageContextImplTest, Basics) {
   // This test doesn't do much, checks that the constructor
   // initializes members properly and that invoking methods
   // on a newly created object w/o any data on disk do no harm.
@@ -89,7 +91,7 @@
   context_->Shutdown();
 }
 
-TEST_F(DomStorageContextTest, UsageInfo) {
+TEST_F(DOMStorageContextImplTest, UsageInfo) {
   // Should be empty initially
   std::vector<LocalStorageUsageInfo> infos;
   context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
@@ -108,7 +110,8 @@
 
   // Create a new context that points to the same directory, see that
   // it knows about the origin that we stored data for.
-  context_ = new DomStorageContext(temp_dir_.path(), base::FilePath(), NULL, NULL);
+  context_ = new DOMStorageContextImpl(temp_dir_.path(), base::FilePath(),
+                                       NULL, NULL);
   context_->GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
   EXPECT_EQ(1u, infos.size());
   EXPECT_EQ(kOrigin, infos[0].origin);
@@ -122,7 +125,7 @@
   EXPECT_NE(base::Time(), infos[0].last_modified);
 }
 
-TEST_F(DomStorageContextTest, SessionOnly) {
+TEST_F(DOMStorageContextImplTest, SessionOnly) {
   const GURL kSessionOnlyOrigin("http://www.sessiononly.com/");
   storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
 
@@ -142,7 +145,7 @@
   VerifySingleOriginRemains(kOrigin);
 }
 
-TEST_F(DomStorageContextTest, SetForceKeepSessionState) {
+TEST_F(DOMStorageContextImplTest, SetForceKeepSessionState) {
   const GURL kSessionOnlyOrigin("http://www.sessiononly.com/");
   storage_policy_->AddSessionOnly(kSessionOnlyOrigin);
 
@@ -159,17 +162,17 @@
   VerifySingleOriginRemains(kSessionOnlyOrigin);
 }
 
-TEST_F(DomStorageContextTest, PersistentIds) {
+TEST_F(DOMStorageContextImplTest, PersistentIds) {
   const int kFirstSessionStorageNamespaceId = 1;
   const std::string kPersistentId = "persistent";
   context_->CreateSessionNamespace(kFirstSessionStorageNamespaceId,
                                    kPersistentId);
-  DomStorageNamespace* dom_namespace =
+  DOMStorageNamespace* dom_namespace =
       context_->GetStorageNamespace(kFirstSessionStorageNamespaceId);
   ASSERT_TRUE(dom_namespace);
   EXPECT_EQ(kPersistentId, dom_namespace->persistent_namespace_id());
   // Verify that the areas inherit the persistent ID.
-  DomStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
+  DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
   EXPECT_EQ(kPersistentId, area->persistent_namespace_id_);
 
   // Verify that the persistent IDs are handled correctly when cloning.
@@ -178,22 +181,22 @@
   context_->CloneSessionNamespace(kFirstSessionStorageNamespaceId,
                                   kClonedSessionStorageNamespaceId,
                                   kClonedPersistentId);
-  DomStorageNamespace* cloned_dom_namespace =
+  DOMStorageNamespace* cloned_dom_namespace =
       context_->GetStorageNamespace(kClonedSessionStorageNamespaceId);
   ASSERT_TRUE(dom_namespace);
   EXPECT_EQ(kClonedPersistentId,
             cloned_dom_namespace->persistent_namespace_id());
   // Verify that the areas inherit the persistent ID.
-  DomStorageArea* cloned_area = cloned_dom_namespace->OpenStorageArea(kOrigin);
+  DOMStorageArea* cloned_area = cloned_dom_namespace->OpenStorageArea(kOrigin);
   EXPECT_EQ(kClonedPersistentId, cloned_area->persistent_namespace_id_);
 }
 
-TEST_F(DomStorageContextTest, DeleteSessionStorage) {
-  // Create a DomStorageContext which will save sessionStorage on disk.
-  context_ = new DomStorageContext(temp_dir_.path(),
-                                   temp_dir_.path(),
-                                   storage_policy_.get(),
-                                   task_runner_.get());
+TEST_F(DOMStorageContextImplTest, DeleteSessionStorage) {
+  // Create a DOMStorageContextImpl which will save sessionStorage on disk.
+  context_ = new DOMStorageContextImpl(temp_dir_.path(),
+                                       temp_dir_.path(),
+                                       storage_policy_.get(),
+                                       task_runner_.get());
   context_->SetSaveSessionStorageOnDisk();
   ASSERT_EQ(temp_dir_.path(), context_->sessionstorage_directory());
 
@@ -202,20 +205,20 @@
   const std::string kPersistentId = "persistent";
   context_->CreateSessionNamespace(kSessionStorageNamespaceId,
                                    kPersistentId);
-  DomStorageNamespace* dom_namespace =
+  DOMStorageNamespace* dom_namespace =
       context_->GetStorageNamespace(kSessionStorageNamespaceId);
-  DomStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
+  DOMStorageArea* area = dom_namespace->OpenStorageArea(kOrigin);
   const base::string16 kKey(ASCIIToUTF16("foo"));
   const base::string16 kValue(ASCIIToUTF16("bar"));
   base::NullableString16 old_nullable_value;
   area->SetItem(kKey, kValue, &old_nullable_value);
   dom_namespace->CloseStorageArea(area);
 
-  // Destroy and recreate the DomStorageContext.
+  // Destroy and recreate the DOMStorageContextImpl.
   context_->Shutdown();
   context_ = NULL;
   base::MessageLoop::current()->RunUntilIdle();
-  context_ = new DomStorageContext(
+  context_ = new DOMStorageContextImpl(
       temp_dir_.path(), temp_dir_.path(),
       storage_policy_.get(), task_runner_.get());
   context_->SetSaveSessionStorageOnDisk();
@@ -239,7 +242,7 @@
   context_->Shutdown();
   context_ = NULL;
   base::MessageLoop::current()->RunUntilIdle();
-  context_ = new DomStorageContext(
+  context_ = new DOMStorageContextImpl(
       temp_dir_.path(), temp_dir_.path(),
       storage_policy_.get(), task_runner_.get());
   context_->SetSaveSessionStorageOnDisk();
@@ -257,4 +260,4 @@
   base::MessageLoop::current()->RunUntilIdle();
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
new file mode 100644
index 0000000..56ea51e
--- /dev/null
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -0,0 +1,173 @@
+// 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 "content/browser/dom_storage/dom_storage_context_wrapper.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/session_storage_namespace_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_usage_info.h"
+
+namespace content {
+namespace {
+
+const char kLocalStorageDirectory[] = "Local Storage";
+const char kSessionStorageDirectory[] = "Session Storage";
+
+void InvokeLocalStorageUsageCallbackHelper(
+      const DOMStorageContext::GetLocalStorageUsageCallback& callback,
+      const std::vector<LocalStorageUsageInfo>* infos) {
+  callback.Run(*infos);
+}
+
+void GetLocalStorageUsageHelper(
+    base::MessageLoopProxy* reply_loop,
+    DOMStorageContextImpl* context,
+    const DOMStorageContext::GetLocalStorageUsageCallback& callback) {
+  std::vector<LocalStorageUsageInfo>* infos =
+      new std::vector<LocalStorageUsageInfo>;
+  context->GetLocalStorageUsage(infos, true);
+  reply_loop->PostTask(
+      FROM_HERE,
+      base::Bind(&InvokeLocalStorageUsageCallbackHelper,
+                 callback, base::Owned(infos)));
+}
+
+void InvokeSessionStorageUsageCallbackHelper(
+      const DOMStorageContext::GetSessionStorageUsageCallback& callback,
+      const std::vector<SessionStorageUsageInfo>* infos) {
+  callback.Run(*infos);
+}
+
+void GetSessionStorageUsageHelper(
+    base::MessageLoopProxy* reply_loop,
+    DOMStorageContextImpl* context,
+    const DOMStorageContext::GetSessionStorageUsageCallback& callback) {
+  std::vector<SessionStorageUsageInfo>* infos =
+      new std::vector<SessionStorageUsageInfo>;
+  context->GetSessionStorageUsage(infos);
+  reply_loop->PostTask(
+      FROM_HERE,
+      base::Bind(&InvokeSessionStorageUsageCallbackHelper,
+                 callback, base::Owned(infos)));
+}
+
+}  // namespace
+
+DOMStorageContextWrapper::DOMStorageContextWrapper(
+    const base::FilePath& data_path,
+    quota::SpecialStoragePolicy* special_storage_policy) {
+  base::SequencedWorkerPool* worker_pool = BrowserThread::GetBlockingPool();
+  context_ = new DOMStorageContextImpl(
+      data_path.empty() ? data_path
+                        : data_path.AppendASCII(kLocalStorageDirectory),
+      data_path.empty() ? data_path
+                        : data_path.AppendASCII(kSessionStorageDirectory),
+      special_storage_policy,
+      new DOMStorageWorkerPoolTaskRunner(
+          worker_pool,
+          worker_pool->GetNamedSequenceToken("dom_storage_primary"),
+          worker_pool->GetNamedSequenceToken("dom_storage_commit"),
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)
+              .get()));
+}
+
+DOMStorageContextWrapper::~DOMStorageContextWrapper() {
+}
+
+void DOMStorageContextWrapper::GetLocalStorageUsage(
+    const GetLocalStorageUsageCallback& callback) {
+  DCHECK(context_.get());
+  context_->task_runner()
+      ->PostShutdownBlockingTask(FROM_HERE,
+                                 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+                                 base::Bind(&GetLocalStorageUsageHelper,
+                                            base::MessageLoopProxy::current(),
+                                            context_,
+                                            callback));
+}
+
+void DOMStorageContextWrapper::GetSessionStorageUsage(
+    const GetSessionStorageUsageCallback& callback) {
+  DCHECK(context_.get());
+  context_->task_runner()
+      ->PostShutdownBlockingTask(FROM_HERE,
+                                 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+                                 base::Bind(&GetSessionStorageUsageHelper,
+                                            base::MessageLoopProxy::current(),
+                                            context_,
+                                            callback));
+}
+
+void DOMStorageContextWrapper::DeleteLocalStorage(const GURL& origin) {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::DeleteLocalStorage, context_, origin));
+}
+
+void DOMStorageContextWrapper::DeleteSessionStorage(
+    const SessionStorageUsageInfo& usage_info) {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::DeleteSessionStorage,
+                 context_, usage_info));
+}
+
+void DOMStorageContextWrapper::SetSaveSessionStorageOnDisk() {
+  DCHECK(context_.get());
+  context_->SetSaveSessionStorageOnDisk();
+}
+
+scoped_refptr<SessionStorageNamespace>
+DOMStorageContextWrapper::RecreateSessionStorage(
+    const std::string& persistent_id) {
+  return scoped_refptr<SessionStorageNamespace>(
+      new SessionStorageNamespaceImpl(this, persistent_id));
+}
+
+void DOMStorageContextWrapper::StartScavengingUnusedSessionStorage() {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::StartScavengingUnusedSessionStorage,
+                 context_));
+}
+
+void DOMStorageContextWrapper::PurgeMemory() {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::PurgeMemory, context_));
+}
+
+void DOMStorageContextWrapper::SetForceKeepSessionState() {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::SetForceKeepSessionState, context_));
+}
+
+void DOMStorageContextWrapper::Shutdown() {
+  DCHECK(context_.get());
+  context_->task_runner()->PostShutdownBlockingTask(
+      FROM_HERE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
+      base::Bind(&DOMStorageContextImpl::Shutdown, context_));
+}
+
+}  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
new file mode 100644
index 0000000..0971f88
--- /dev/null
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -0,0 +1,74 @@
+// 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 CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/dom_storage_context.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace quota {
+class SpecialStoragePolicy;
+}
+
+namespace content {
+
+class DOMStorageContextImpl;
+
+// This is owned by BrowserContext (aka Profile) and encapsulates all
+// per-profile dom storage state.
+class CONTENT_EXPORT DOMStorageContextWrapper :
+    NON_EXPORTED_BASE(public DOMStorageContext),
+    public base::RefCountedThreadSafe<DOMStorageContextWrapper> {
+ public:
+  // If |data_path| is empty, nothing will be saved to disk.
+  DOMStorageContextWrapper(const base::FilePath& data_path,
+                        quota::SpecialStoragePolicy* special_storage_policy);
+
+  // DOMStorageContext implementation.
+  virtual void GetLocalStorageUsage(
+      const GetLocalStorageUsageCallback& callback) OVERRIDE;
+  virtual void GetSessionStorageUsage(
+      const GetSessionStorageUsageCallback& callback) OVERRIDE;
+  virtual void DeleteLocalStorage(const GURL& origin) OVERRIDE;
+  virtual void DeleteSessionStorage(
+      const SessionStorageUsageInfo& usage_info) OVERRIDE;
+  virtual void SetSaveSessionStorageOnDisk() OVERRIDE;
+  virtual scoped_refptr<SessionStorageNamespace>
+      RecreateSessionStorage(const std::string& persistent_id) OVERRIDE;
+  virtual void StartScavengingUnusedSessionStorage() OVERRIDE;
+
+  // Called to free up memory that's not strictly needed.
+  void PurgeMemory();
+
+  // Used by content settings to alter the behavior around
+  // what data to keep and what data to discard at shutdown.
+  // The policy is not so straight forward to describe, see
+  // the implementation for details.
+  void SetForceKeepSessionState();
+
+  // Called when the BrowserContext/Profile is going away.
+  void Shutdown();
+
+ private:
+  friend class DOMStorageMessageFilter;  // for access to context()
+  friend class SessionStorageNamespaceImpl;  // ditto
+  friend class base::RefCountedThreadSafe<DOMStorageContextWrapper>;
+
+  virtual ~DOMStorageContextWrapper();
+  DOMStorageContextImpl* context() const { return context_.get(); }
+
+  scoped_refptr<DOMStorageContextImpl> context_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageContextWrapper);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_WRAPPER_H_
diff --git a/webkit/browser/dom_storage/dom_storage_database.cc b/content/browser/dom_storage/dom_storage_database.cc
similarity index 88%
rename from webkit/browser/dom_storage/dom_storage_database.cc
rename to content/browser/dom_storage/dom_storage_database.cc
index f3199b6..690d02a 100644
--- a/webkit/browser/dom_storage/dom_storage_database.cc
+++ b/content/browser/dom_storage/dom_storage_database.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
 
 #include "base/bind.h"
 #include "base/file_util.h"
@@ -17,17 +17,17 @@
 
 }  // anon namespace
 
-namespace dom_storage {
+namespace content {
 
 // static
-base::FilePath DomStorageDatabase::GetJournalFilePath(
+base::FilePath DOMStorageDatabase::GetJournalFilePath(
     const base::FilePath& database_path) {
   base::FilePath::StringType journal_file_name =
       database_path.BaseName().value() + kJournal;
   return database_path.DirName().Append(journal_file_name);
 }
 
-DomStorageDatabase::DomStorageDatabase(const base::FilePath& file_path)
+DOMStorageDatabase::DOMStorageDatabase(const base::FilePath& file_path)
     : file_path_(file_path) {
   // Note: in normal use we should never get an empty backing path here.
   // However, the unit test for this class can contruct an instance
@@ -35,17 +35,17 @@
   Init();
 }
 
-DomStorageDatabase::DomStorageDatabase() {
+DOMStorageDatabase::DOMStorageDatabase() {
   Init();
 }
 
-void DomStorageDatabase::Init() {
+void DOMStorageDatabase::Init() {
   failed_to_open_ = false;
   tried_to_recreate_ = false;
   known_to_be_empty_ = false;
 }
 
-DomStorageDatabase::~DomStorageDatabase() {
+DOMStorageDatabase::~DOMStorageDatabase() {
   if (known_to_be_empty_ && !file_path_.empty()) {
     // Delete the db and any lingering journal file from disk.
     Close();
@@ -53,7 +53,7 @@
   }
 }
 
-void DomStorageDatabase::ReadAllValues(ValuesMap* result) {
+void DOMStorageDatabase::ReadAllValues(DOMStorageValuesMap* result) {
   if (!LazyOpen(false))
     return;
 
@@ -70,8 +70,8 @@
   known_to_be_empty_ = result->empty();
 }
 
-bool DomStorageDatabase::CommitChanges(bool clear_all_first,
-                                       const ValuesMap& changes) {
+bool DOMStorageDatabase::CommitChanges(bool clear_all_first,
+                                       const DOMStorageValuesMap& changes) {
   if (!LazyOpen(!changes.empty())) {
     // If we're being asked to commit changes that will result in an
     // empty database, we return true if the database file doesn't exist.
@@ -92,7 +92,7 @@
 
   bool did_delete = false;
   bool did_insert = false;
-  ValuesMap::const_iterator it = changes.begin();
+  DOMStorageValuesMap::const_iterator it = changes.begin();
   for(; it != changes.end(); ++it) {
     sql::Statement statement;
     base::string16 key = it->first;
@@ -128,7 +128,7 @@
   return success;
 }
 
-bool DomStorageDatabase::LazyOpen(bool create_if_needed) {
+bool DOMStorageDatabase::LazyOpen(bool create_if_needed) {
   if (failed_to_open_) {
     // Don't try to open a database that we know has failed
     // already.
@@ -149,7 +149,7 @@
   }
 
   db_.reset(new sql::Connection());
-  db_->set_histogram_tag("DomStorageDatabase");
+  db_->set_histogram_tag("DOMStorageDatabase");
 
   if (file_path_.empty()) {
     // This code path should only be triggered by unit tests.
@@ -197,7 +197,7 @@
   return DeleteFileAndRecreate();
 }
 
-DomStorageDatabase::SchemaVersion DomStorageDatabase::DetectSchemaVersion() {
+DOMStorageDatabase::SchemaVersion DOMStorageDatabase::DetectSchemaVersion() {
   DCHECK(IsOpen());
 
   // Connection::Open() may succeed even if the file we try and open is not a
@@ -233,7 +233,7 @@
   return INVALID;
 }
 
-bool DomStorageDatabase::CreateTableV2() {
+bool DOMStorageDatabase::CreateTableV2() {
   DCHECK(IsOpen());
 
   return db_->Execute(
@@ -242,7 +242,7 @@
       "value BLOB NOT NULL ON CONFLICT FAIL)");
 }
 
-bool DomStorageDatabase::DeleteFileAndRecreate() {
+bool DOMStorageDatabase::DeleteFileAndRecreate() {
   DCHECK(!IsOpen());
   DCHECK(base::PathExists(file_path_));
 
@@ -262,7 +262,7 @@
   return false;
 }
 
-bool DomStorageDatabase::UpgradeVersion1To2() {
+bool DOMStorageDatabase::UpgradeVersion1To2() {
   DCHECK(IsOpen());
   DCHECK(DetectSchemaVersion() == V1);
 
@@ -273,7 +273,7 @@
   // Need to migrate from TEXT value column to BLOB.
   // Store the current database content so we can re-insert
   // the data into the new V2 table.
-  ValuesMap values;
+  DOMStorageValuesMap values;
   while (statement.Step()) {
     base::string16 key = statement.ColumnString16(0);
     base::NullableString16 value(statement.ColumnString16(1), false);
@@ -288,8 +288,8 @@
       migration.Commit();
 }
 
-void DomStorageDatabase::Close() {
+void DOMStorageDatabase::Close() {
   db_.reset(NULL);
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_database.h b/content/browser/dom_storage/dom_storage_database.h
similarity index 68%
rename from webkit/browser/dom_storage/dom_storage_database.h
rename to content/browser/dom_storage/dom_storage_database.h
index 1f1d501..72f5d73 100644
--- a/webkit/browser/dom_storage/dom_storage_database.h
+++ b/content/browser/dom_storage/dom_storage_database.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
 
 #include <map>
 
@@ -12,60 +12,60 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "sql/connection.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
 // Represents a SQLite based backing for DOM storage data. This
 // class is designed to be used on a single thread.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageDatabase {
+class CONTENT_EXPORT DOMStorageDatabase {
  public:
   static base::FilePath GetJournalFilePath(const base::FilePath& database_path);
 
-  explicit DomStorageDatabase(const base::FilePath& file_path);
-  virtual ~DomStorageDatabase();  // virtual for unit testing
+  explicit DOMStorageDatabase(const base::FilePath& file_path);
+  virtual ~DOMStorageDatabase();  // virtual for unit testing
 
   // Reads all the key, value pairs stored in the database and returns
   // them. |result| is assumed to be empty and any duplicate keys will
   // be overwritten. If the database exists on disk then it will be
   // opened. If it does not exist then it will not be created and
   // |result| will be unmodified.
-  void ReadAllValues(ValuesMap* result);
+  void ReadAllValues(DOMStorageValuesMap* result);
 
   // Updates the backing database. Will remove all keys before updating
   // the database if |clear_all_first| is set. Then all entries in
   // |changes| will be examined - keys mapped to a null NullableString16
   // will be removed and all others will be inserted/updated as appropriate.
-  bool CommitChanges(bool clear_all_first, const ValuesMap& changes);
+  bool CommitChanges(bool clear_all_first, const DOMStorageValuesMap& changes);
 
   // Simple getter for the path we were constructed with.
   const base::FilePath& file_path() const { return file_path_; }
 
  protected:
   // Constructor that uses an in-memory sqlite database, for testing.
-  DomStorageDatabase();
+  DOMStorageDatabase();
 
  private:
   friend class LocalStorageDatabaseAdapter;
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, SimpleOpenAndClose);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, TestLazyOpenIsLazy);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, TestDetectSchemaVersion);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest,
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, SimpleOpenAndClose);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, TestLazyOpenIsLazy);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, TestDetectSchemaVersion);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest,
                            TestLazyOpenUpgradesDatabase);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, SimpleWriteAndReadBack);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, WriteWithClear);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest,
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, SimpleWriteAndReadBack);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, WriteWithClear);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest,
                            UpgradeFromV1ToV2WithData);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest, TestSimpleRemoveOneValue);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest,
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest, TestSimpleRemoveOneValue);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest,
                            TestCanOpenAndReadWebCoreDatabase);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageDatabaseTest,
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageDatabaseTest,
                            TestCanOpenFileThatIsNotADatabase);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, BackingDatabaseOpened);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, CommitTasks);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, PurgeMemory);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
 
   enum SchemaVersion {
     INVALID,
@@ -114,6 +114,6 @@
   bool known_to_be_empty_;
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_H_
diff --git a/content/browser/dom_storage/dom_storage_database_adapter.h b/content/browser/dom_storage/dom_storage_database_adapter.h
new file mode 100644
index 0000000..9068af2
--- /dev/null
+++ b/content/browser/dom_storage/dom_storage_database_adapter.h
@@ -0,0 +1,29 @@
+// 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 CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
+
+// Database interface used by DOMStorageArea. Abstracts the differences between
+// the per-origin DOMStorageDatabases for localStorage and
+// SessionStorageDatabase which stores multiple origins.
+
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
+
+namespace content {
+
+class CONTENT_EXPORT DOMStorageDatabaseAdapter {
+ public:
+  virtual ~DOMStorageDatabaseAdapter() {}
+  virtual void ReadAllValues(DOMStorageValuesMap* result) = 0;
+  virtual bool CommitChanges(
+      bool clear_all_first, const DOMStorageValuesMap& changes) = 0;
+  virtual void DeleteFiles() {}
+  virtual void Reset() {}
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/dom_storage/dom_storage_database_unittest.cc b/content/browser/dom_storage/dom_storage_database_unittest.cc
similarity index 78%
rename from webkit/browser/dom_storage/dom_storage_database_unittest.cc
rename to content/browser/dom_storage/dom_storage_database_unittest.cc
index d1be10b..f3ba0b6 100644
--- a/webkit/browser/dom_storage/dom_storage_database_unittest.cc
+++ b/content/browser/dom_storage/dom_storage_database_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_database.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
 
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -14,7 +14,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/sqlite/sqlite3.h"
 
-namespace dom_storage {
+namespace content {
 
 void CreateV1Table(sql::Connection* db) {
   ASSERT_TRUE(db->is_open());
@@ -66,13 +66,13 @@
   statement.Run();
 }
 
-void CheckValuesMatch(DomStorageDatabase* db,
-                      const ValuesMap& expected) {
-  ValuesMap values_read;
+void CheckValuesMatch(DOMStorageDatabase* db,
+                      const DOMStorageValuesMap& expected) {
+  DOMStorageValuesMap values_read;
   db->ReadAllValues(&values_read);
   EXPECT_EQ(expected.size(), values_read.size());
 
-  ValuesMap::const_iterator it = values_read.begin();
+  DOMStorageValuesMap::const_iterator it = values_read.begin();
   for (; it != values_read.end(); ++it) {
     base::string16 key = it->first;
     base::NullableString16 value = it->second;
@@ -82,7 +82,7 @@
   }
 }
 
-void CreateMapWithValues(ValuesMap* values) {
+void CreateMapWithValues(DOMStorageValuesMap* values) {
   base::string16 kCannedKeys[] = {
       ASCIIToUTF16("test"),
       ASCIIToUTF16("company"),
@@ -99,28 +99,28 @@
     (*values)[kCannedKeys[i]] = kCannedValues[i];
 }
 
-TEST(DomStorageDatabaseTest, SimpleOpenAndClose) {
-  DomStorageDatabase db;
+TEST(DOMStorageDatabaseTest, SimpleOpenAndClose) {
+  DOMStorageDatabase db;
   EXPECT_FALSE(db.IsOpen());
   ASSERT_TRUE(db.LazyOpen(true));
   EXPECT_TRUE(db.IsOpen());
-  EXPECT_EQ(DomStorageDatabase::V2, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
   db.Close();
   EXPECT_FALSE(db.IsOpen());
 }
 
-TEST(DomStorageDatabaseTest, CloseEmptyDatabaseDeletesFile) {
+TEST(DOMStorageDatabaseTest, CloseEmptyDatabaseDeletesFile) {
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath file_name =
-      temp_dir.path().AppendASCII("TestDomStorageDatabase.db");
-  ValuesMap storage;
+      temp_dir.path().AppendASCII("TestDOMStorageDatabase.db");
+  DOMStorageValuesMap storage;
   CreateMapWithValues(&storage);
 
   // First test the case that explicitly clearing the database will
   // trigger its deletion from disk.
   {
-    DomStorageDatabase db(file_name);
+    DOMStorageDatabase db(file_name);
     EXPECT_EQ(file_name, db.file_path());
     ASSERT_TRUE(db.CommitChanges(false, storage));
   }
@@ -129,8 +129,8 @@
   {
     // Check that reading an existing db with data in it
     // keeps the DB on disk on close.
-    DomStorageDatabase db(file_name);
-    ValuesMap values;
+    DOMStorageDatabase db(file_name);
+    DOMStorageValuesMap values;
     db.ReadAllValues(&values);
     EXPECT_EQ(storage.size(), values.size());
   }
@@ -139,7 +139,7 @@
   storage.clear();
 
   {
-    DomStorageDatabase db(file_name);
+    DOMStorageDatabase db(file_name);
     ASSERT_TRUE(db.CommitChanges(true, storage));
   }
   EXPECT_FALSE(base::PathExists(file_name));
@@ -148,16 +148,16 @@
   // is an empty database also triggers deletion.
   CreateMapWithValues(&storage);
   {
-    DomStorageDatabase db(file_name);
+    DOMStorageDatabase db(file_name);
     ASSERT_TRUE(db.CommitChanges(false, storage));
   }
 
   EXPECT_TRUE(base::PathExists(file_name));
 
   {
-    DomStorageDatabase db(file_name);
+    DOMStorageDatabase db(file_name);
     ASSERT_TRUE(db.CommitChanges(false, storage));
-    ValuesMap::iterator it = storage.begin();
+    DOMStorageValuesMap::iterator it = storage.begin();
     for (; it != storage.end(); ++it)
       it->second = base::NullableString16();
     ASSERT_TRUE(db.CommitChanges(false, storage));
@@ -165,17 +165,17 @@
   EXPECT_FALSE(base::PathExists(file_name));
 }
 
-TEST(DomStorageDatabaseTest, TestLazyOpenIsLazy) {
+TEST(DOMStorageDatabaseTest, TestLazyOpenIsLazy) {
   // This test needs to operate with a file on disk to ensure that we will
   // open a file that already exists when only invoking ReadAllValues.
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath file_name =
-      temp_dir.path().AppendASCII("TestDomStorageDatabase.db");
+      temp_dir.path().AppendASCII("TestDOMStorageDatabase.db");
 
-  DomStorageDatabase db(file_name);
+  DOMStorageDatabase db(file_name);
   EXPECT_FALSE(db.IsOpen());
-  ValuesMap values;
+  DOMStorageValuesMap values;
   db.ReadAllValues(&values);
   // Reading an empty db should not open the database.
   EXPECT_FALSE(db.IsOpen());
@@ -194,25 +194,25 @@
   EXPECT_TRUE(db.IsOpen());
 }
 
-TEST(DomStorageDatabaseTest, TestDetectSchemaVersion) {
-  DomStorageDatabase db;
+TEST(DOMStorageDatabaseTest, TestDetectSchemaVersion) {
+  DOMStorageDatabase db;
   db.db_.reset(new sql::Connection());
   ASSERT_TRUE(db.db_->OpenInMemory());
 
   CreateInvalidValueColumnTable(db.db_.get());
-  EXPECT_EQ(DomStorageDatabase::INVALID, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::INVALID, db.DetectSchemaVersion());
 
   CreateInvalidKeyColumnTable(db.db_.get());
-  EXPECT_EQ(DomStorageDatabase::INVALID, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::INVALID, db.DetectSchemaVersion());
 
   CreateV1Table(db.db_.get());
-  EXPECT_EQ(DomStorageDatabase::V1, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::V1, db.DetectSchemaVersion());
 
   CreateV2Table(db.db_.get());
-  EXPECT_EQ(DomStorageDatabase::V2, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
 }
 
-TEST(DomStorageDatabaseTest, TestLazyOpenUpgradesDatabase) {
+TEST(DOMStorageDatabaseTest, TestLazyOpenUpgradesDatabase) {
   // This test needs to operate with a file on disk so that we
   // can create a table at version 1 and then close it again
   // so that LazyOpen sees there is work to do (LazyOpen will return
@@ -220,32 +220,32 @@
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath file_name =
-      temp_dir.path().AppendASCII("TestDomStorageDatabase.db");
+      temp_dir.path().AppendASCII("TestDOMStorageDatabase.db");
 
-  DomStorageDatabase db(file_name);
+  DOMStorageDatabase db(file_name);
   db.db_.reset(new sql::Connection());
   ASSERT_TRUE(db.db_->Open(file_name));
   CreateV1Table(db.db_.get());
   db.Close();
 
   EXPECT_TRUE(db.LazyOpen(true));
-  EXPECT_EQ(DomStorageDatabase::V2, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
 }
 
-TEST(DomStorageDatabaseTest, SimpleWriteAndReadBack) {
-  DomStorageDatabase db;
+TEST(DOMStorageDatabaseTest, SimpleWriteAndReadBack) {
+  DOMStorageDatabase db;
 
-  ValuesMap storage;
+  DOMStorageValuesMap storage;
   CreateMapWithValues(&storage);
 
   EXPECT_TRUE(db.CommitChanges(false, storage));
   CheckValuesMatch(&db, storage);
 }
 
-TEST(DomStorageDatabaseTest, WriteWithClear) {
-  DomStorageDatabase db;
+TEST(DOMStorageDatabaseTest, WriteWithClear) {
+  DOMStorageDatabase db;
 
-  ValuesMap storage;
+  DOMStorageValuesMap storage;
   CreateMapWithValues(&storage);
 
   ASSERT_TRUE(db.CommitChanges(false, storage));
@@ -264,13 +264,13 @@
   CheckValuesMatch(&db, storage);
 }
 
-TEST(DomStorageDatabaseTest, UpgradeFromV1ToV2WithData) {
+TEST(DOMStorageDatabaseTest, UpgradeFromV1ToV2WithData) {
   const base::string16 kCannedKey = ASCIIToUTF16("foo");
   const base::NullableString16 kCannedValue(ASCIIToUTF16("bar"), false);
-  ValuesMap expected;
+  DOMStorageValuesMap expected;
   expected[kCannedKey] = kCannedValue;
 
-  DomStorageDatabase db;
+  DOMStorageDatabase db;
   db.db_.reset(new sql::Connection());
   ASSERT_TRUE(db.db_->OpenInMemory());
   CreateV1Table(db.db_.get());
@@ -278,25 +278,25 @@
 
   ASSERT_TRUE(db.UpgradeVersion1To2());
 
-  EXPECT_EQ(DomStorageDatabase::V2, db.DetectSchemaVersion());
+  EXPECT_EQ(DOMStorageDatabase::V2, db.DetectSchemaVersion());
 
   CheckValuesMatch(&db, expected);
 }
 
-TEST(DomStorageDatabaseTest, TestSimpleRemoveOneValue) {
-  DomStorageDatabase db;
+TEST(DOMStorageDatabaseTest, TestSimpleRemoveOneValue) {
+  DOMStorageDatabase db;
 
   ASSERT_TRUE(db.LazyOpen(true));
   const base::string16 kCannedKey = ASCIIToUTF16("test");
   const base::NullableString16 kCannedValue(ASCIIToUTF16("data"), false);
-  ValuesMap expected;
+  DOMStorageValuesMap expected;
   expected[kCannedKey] = kCannedValue;
 
   // First write some data into the database.
   ASSERT_TRUE(db.CommitChanges(false, expected));
   CheckValuesMatch(&db, expected);
 
-  ValuesMap values;
+  DOMStorageValuesMap values;
   // A null string in the map should mean that that key gets
   // removed.
   values[kCannedKey] = base::NullableString16();
@@ -306,7 +306,7 @@
   CheckValuesMatch(&db, expected);
 }
 
-TEST(DomStorageDatabaseTest, TestCanOpenAndReadWebCoreDatabase) {
+TEST(DOMStorageDatabaseTest, TestCanOpenAndReadWebCoreDatabase) {
   base::FilePath webcore_database;
   PathService::Get(base::DIR_SOURCE_ROOT, &webcore_database);
   webcore_database = webcore_database.AppendASCII("webkit");
@@ -317,13 +317,13 @@
 
   ASSERT_TRUE(base::PathExists(webcore_database));
 
-  DomStorageDatabase db(webcore_database);
-  ValuesMap values;
+  DOMStorageDatabase db(webcore_database);
+  DOMStorageValuesMap values;
   db.ReadAllValues(&values);
   EXPECT_TRUE(db.IsOpen());
   EXPECT_EQ(2u, values.size());
 
-  ValuesMap::const_iterator it =
+  DOMStorageValuesMap::const_iterator it =
       values.find(ASCIIToUTF16("value"));
   EXPECT_TRUE(it != values.end());
   EXPECT_EQ(ASCIIToUTF16("I am in local storage!"), it->second.string());
@@ -336,12 +336,12 @@
   EXPECT_TRUE(it == values.end());
 }
 
-TEST(DomStorageDatabaseTest, TestCanOpenFileThatIsNotADatabase) {
+TEST(DOMStorageDatabaseTest, TestCanOpenFileThatIsNotADatabase) {
   // Write into the temporary file first.
   base::ScopedTempDir temp_dir;
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
   base::FilePath file_name =
-      temp_dir.path().AppendASCII("TestDomStorageDatabase.db");
+      temp_dir.path().AppendASCII("TestDOMStorageDatabase.db");
 
   const char kData[] = "I am not a database.";
   file_util::WriteFile(file_name, kData, strlen(kData));
@@ -353,8 +353,8 @@
     // Try and open the file. As it's not a database, we should end up deleting
     // it and creating a new, valid file, so everything should actually
     // succeed.
-    DomStorageDatabase db(file_name);
-    ValuesMap values;
+    DOMStorageDatabase db(file_name);
+    DOMStorageValuesMap values;
     CreateMapWithValues(&values);
     EXPECT_TRUE(db.CommitChanges(true, values));
     EXPECT_TRUE(db.CommitChanges(false, values));
@@ -371,8 +371,8 @@
 
     // Try to open a directory, we should fail gracefully and not attempt
     // to delete it.
-    DomStorageDatabase db(temp_dir.path());
-    ValuesMap values;
+    DOMStorageDatabase db(temp_dir.path());
+    DOMStorageValuesMap values;
     CreateMapWithValues(&values);
     EXPECT_FALSE(db.CommitChanges(true, values));
     EXPECT_FALSE(db.CommitChanges(false, values));
@@ -390,4 +390,4 @@
   }
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_host.cc b/content/browser/dom_storage/dom_storage_host.cc
similarity index 64%
rename from webkit/browser/dom_storage/dom_storage_host.cc
rename to content/browser/dom_storage/dom_storage_host.cc
index 9b6da67..296d52e 100644
--- a/webkit/browser/dom_storage/dom_storage_host.cc
+++ b/content/browser/dom_storage/dom_storage_host.cc
@@ -1,29 +1,29 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_host.h"
+#include "content/browser/dom_storage/dom_storage_host.h"
 
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "url/gurl.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/browser/dom_storage/dom_storage_namespace.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
-DomStorageHost::DomStorageHost(DomStorageContext* context)
+DOMStorageHost::DOMStorageHost(DOMStorageContextImpl* context)
     : context_(context) {
 }
 
-DomStorageHost::~DomStorageHost() {
+DOMStorageHost::~DOMStorageHost() {
   AreaMap::const_iterator it = connections_.begin();
   for (; it != connections_.end(); ++it)
     it->second.namespace_->CloseStorageArea(it->second.area_.get());
   connections_.clear();  // Clear prior to releasing the context_
 }
 
-bool DomStorageHost::OpenStorageArea(int connection_id, int namespace_id,
+bool DOMStorageHost::OpenStorageArea(int connection_id, int namespace_id,
                                      const GURL& origin) {
   DCHECK(!GetOpenArea(connection_id));
   if (GetOpenArea(connection_id))
@@ -42,7 +42,7 @@
   return true;
 }
 
-void DomStorageHost::CloseStorageArea(int connection_id) {
+void DOMStorageHost::CloseStorageArea(int connection_id) {
   AreaMap::iterator found = connections_.find(connection_id);
   if (found == connections_.end())
     return;
@@ -50,10 +50,10 @@
   connections_.erase(found);
 }
 
-bool DomStorageHost::ExtractAreaValues(
-    int connection_id, ValuesMap* map) {
+bool DOMStorageHost::ExtractAreaValues(
+    int connection_id, DOMStorageValuesMap* map) {
   map->clear();
-  DomStorageArea* area = GetOpenArea(connection_id);
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area) {
     // TODO(michaeln): Fix crbug/134003 and return false here.
     // Until then return true to avoid crashing the renderer
@@ -61,46 +61,46 @@
     return true;
   }
   if (!area->IsLoadedInMemory()) {
-    DomStorageNamespace* ns = GetNamespace(connection_id);
+    DOMStorageNamespace* ns = GetNamespace(connection_id);
     DCHECK(ns);
-    if (ns->CountInMemoryAreas() > kMaxInMemoryAreas) {
-      ns->PurgeMemory(DomStorageNamespace::PURGE_UNOPENED);
-      if (ns->CountInMemoryAreas() > kMaxInMemoryAreas)
-        ns->PurgeMemory(DomStorageNamespace::PURGE_AGGRESSIVE);
+    if (ns->CountInMemoryAreas() > kMaxInMemoryStorageAreas) {
+      ns->PurgeMemory(DOMStorageNamespace::PURGE_UNOPENED);
+      if (ns->CountInMemoryAreas() > kMaxInMemoryStorageAreas)
+        ns->PurgeMemory(DOMStorageNamespace::PURGE_AGGRESSIVE);
     }
   }
   area->ExtractValues(map);
   return true;
 }
 
-unsigned DomStorageHost::GetAreaLength(int connection_id) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+unsigned DOMStorageHost::GetAreaLength(int connection_id) {
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return 0;
   return area->Length();
 }
 
-base::NullableString16 DomStorageHost::GetAreaKey(int connection_id,
+base::NullableString16 DOMStorageHost::GetAreaKey(int connection_id,
                                                   unsigned index) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return base::NullableString16();
   return area->Key(index);
 }
 
-base::NullableString16 DomStorageHost::GetAreaItem(int connection_id,
+base::NullableString16 DOMStorageHost::GetAreaItem(int connection_id,
                                                    const base::string16& key) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return base::NullableString16();
   return area->GetItem(key);
 }
 
-bool DomStorageHost::SetAreaItem(
+bool DOMStorageHost::SetAreaItem(
     int connection_id, const base::string16& key,
     const base::string16& value, const GURL& page_url,
     base::NullableString16* old_value) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area) {
     // TODO(michaeln): Fix crbug/134003 and return false here.
     // Until then return true to allow the renderer to operate
@@ -114,10 +114,10 @@
   return true;
 }
 
-bool DomStorageHost::RemoveAreaItem(
+bool DOMStorageHost::RemoveAreaItem(
     int connection_id, const base::string16& key, const GURL& page_url,
     base::string16* old_value) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return false;
   if (!area->RemoveItem(key, old_value))
@@ -126,8 +126,8 @@
   return true;
 }
 
-bool DomStorageHost::ClearArea(int connection_id, const GURL& page_url) {
-  DomStorageArea* area = GetOpenArea(connection_id);
+bool DOMStorageHost::ClearArea(int connection_id, const GURL& page_url) {
+  DOMStorageArea* area = GetOpenArea(connection_id);
   if (!area)
     return false;
   if (!area->Clear())
@@ -136,7 +136,7 @@
   return true;
 }
 
-bool DomStorageHost::HasAreaOpen(
+bool DOMStorageHost::HasAreaOpen(
     int namespace_id, const GURL& origin) const {
   AreaMap::const_iterator it = connections_.begin();
   for (; it != connections_.end(); ++it) {
@@ -148,14 +148,14 @@
   return false;
 }
 
-DomStorageArea* DomStorageHost::GetOpenArea(int connection_id) {
+DOMStorageArea* DOMStorageHost::GetOpenArea(int connection_id) {
   AreaMap::iterator found = connections_.find(connection_id);
   if (found == connections_.end())
     return NULL;
   return found->second.area_.get();
 }
 
-DomStorageNamespace* DomStorageHost::GetNamespace(int connection_id) {
+DOMStorageNamespace* DOMStorageHost::GetNamespace(int connection_id) {
   AreaMap::iterator found = connections_.find(connection_id);
   if (found == connections_.end())
     return NULL;
@@ -164,7 +164,7 @@
 
 // NamespaceAndArea
 
-DomStorageHost::NamespaceAndArea::NamespaceAndArea() {}
-DomStorageHost::NamespaceAndArea::~NamespaceAndArea() {}
+DOMStorageHost::NamespaceAndArea::NamespaceAndArea() {}
+DOMStorageHost::NamespaceAndArea::~NamespaceAndArea() {}
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_host.h b/content/browser/dom_storage/dom_storage_host.h
similarity index 60%
rename from webkit/browser/dom_storage/dom_storage_host.h
rename to content/browser/dom_storage/dom_storage_host.h
index 31e1962..3aa9d80 100644
--- a/webkit/browser/dom_storage/dom_storage_host.h
+++ b/content/browser/dom_storage/dom_storage_host.h
@@ -1,41 +1,41 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
 
 #include <map>
 
 #include "base/memory/ref_counted.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string16.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 
 class GURL;
 
-namespace dom_storage {
+namespace content {
 
-class DomStorageContext;
-class DomStorageHost;
-class DomStorageNamespace;
-class DomStorageArea;
+class DOMStorageContextImpl;
+class DOMStorageHost;
+class DOMStorageNamespace;
+class DOMStorageArea;
 
 // One instance is allocated in the main process for each client process.
-// Used by DomStorageMessageFilter in Chrome and by SimpleDomStorage in DRT.
+// Used by DOMStorageMessageFilter in Chrome and by SimpleDOMStorage in DRT.
 // This class is single threaded, and performs blocking file reads/writes,
 // so it shouldn't be used on chrome's IO thread.
-// See class comments for DomStorageContext for a larger overview.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageHost {
+// See class comments for DOMStorageContextImpl for a larger overview.
+class CONTENT_EXPORT DOMStorageHost {
  public:
-  explicit DomStorageHost(DomStorageContext* context);
-  ~DomStorageHost();
+  explicit DOMStorageHost(DOMStorageContextImpl* context);
+  ~DOMStorageHost();
 
   bool OpenStorageArea(int connection_id, int namespace_id,
                        const GURL& origin);
   void CloseStorageArea(int connection_id);
-  bool ExtractAreaValues(int connection_id, ValuesMap* map);
+  bool ExtractAreaValues(int connection_id, DOMStorageValuesMap* map);
   unsigned GetAreaLength(int connection_id);
   base::NullableString16 GetAreaKey(int connection_id, unsigned index);
   base::NullableString16 GetAreaItem(int connection_id,
@@ -53,20 +53,20 @@
   // Struct to hold references needed for areas that are open
   // within our associated client process.
   struct NamespaceAndArea {
-    scoped_refptr<DomStorageNamespace> namespace_;
-    scoped_refptr<DomStorageArea> area_;
+    scoped_refptr<DOMStorageNamespace> namespace_;
+    scoped_refptr<DOMStorageArea> area_;
     NamespaceAndArea();
     ~NamespaceAndArea();
   };
   typedef std::map<int, NamespaceAndArea > AreaMap;
 
-  DomStorageArea* GetOpenArea(int connection_id);
-  DomStorageNamespace* GetNamespace(int connection_id);
+  DOMStorageArea* GetOpenArea(int connection_id);
+  DOMStorageNamespace* GetNamespace(int connection_id);
 
-  scoped_refptr<DomStorageContext> context_;
+  scoped_refptr<DOMStorageContextImpl> context_;
   AreaMap connections_;
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_HOST_H_
diff --git a/content/browser/dom_storage/dom_storage_message_filter.cc b/content/browser/dom_storage/dom_storage_message_filter.cc
index 8649ebe..52aabe1 100644
--- a/content/browser/dom_storage/dom_storage_message_filter.cc
+++ b/content/browser/dom_storage/dom_storage_message_filter.cc
@@ -9,19 +9,20 @@
 #include "base/strings/nullable_string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
-#include "content/common/dom_storage_messages.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include "content/browser/dom_storage/dom_storage_host.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
 #include "content/public/browser/user_metrics.h"
 #include "url/gurl.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_host.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
 
 namespace content {
 
 DOMStorageMessageFilter::DOMStorageMessageFilter(
     int unused,
-    DOMStorageContextImpl* context)
+    DOMStorageContextWrapper* context)
     : context_(context->context()),
       connection_dispatching_message_for_(0) {
 }
@@ -32,7 +33,7 @@
 
 void DOMStorageMessageFilter::InitializeInSequence() {
   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
-  host_.reset(new dom_storage::DomStorageHost(context_.get()));
+  host_.reset(new DOMStorageHost(context_.get()));
   context_->AddEventObserver(this);
 }
 
@@ -49,7 +50,7 @@
   BrowserMessageFilter::OnFilterAdded(channel);
   context_->task_runner()->PostShutdownBlockingTask(
       FROM_HERE,
-      dom_storage::DomStorageTaskRunner::PRIMARY_SEQUENCE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
       base::Bind(&DOMStorageMessageFilter::InitializeInSequence, this));
 }
 
@@ -58,7 +59,7 @@
   BrowserMessageFilter::OnFilterRemoved();
   context_->task_runner()->PostShutdownBlockingTask(
       FROM_HERE,
-      dom_storage::DomStorageTaskRunner::PRIMARY_SEQUENCE,
+      DOMStorageTaskRunner::PRIMARY_SEQUENCE,
       base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this));
 }
 
@@ -106,7 +107,7 @@
 }
 
 void DOMStorageMessageFilter::OnLoadStorageArea(int connection_id,
-                                                dom_storage::ValuesMap* map) {
+                                                DOMStorageValuesMap* map) {
   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
   if (!host_->ExtractAreaValues(connection_id, map)) {
     RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_2"));
@@ -154,40 +155,40 @@
   // Intentionally empty method body.
 }
 
-void DOMStorageMessageFilter::OnDomStorageItemSet(
-    const dom_storage::DomStorageArea* area,
+void DOMStorageMessageFilter::OnDOMStorageItemSet(
+    const DOMStorageArea* area,
     const string16& key,
     const string16& new_value,
     const base::NullableString16& old_value,
     const GURL& page_url) {
-  SendDomStorageEvent(area, page_url,
+  SendDOMStorageEvent(area, page_url,
                       base::NullableString16(key, false),
                       base::NullableString16(new_value, false),
                       old_value);
 }
 
-void DOMStorageMessageFilter::OnDomStorageItemRemoved(
-    const dom_storage::DomStorageArea* area,
+void DOMStorageMessageFilter::OnDOMStorageItemRemoved(
+    const DOMStorageArea* area,
     const string16& key,
     const string16& old_value,
     const GURL& page_url) {
-  SendDomStorageEvent(area, page_url,
+  SendDOMStorageEvent(area, page_url,
                       base::NullableString16(key, false),
                       base::NullableString16(),
                       base::NullableString16(old_value, false));
 }
 
-void DOMStorageMessageFilter::OnDomStorageAreaCleared(
-    const dom_storage::DomStorageArea* area,
+void DOMStorageMessageFilter::OnDOMStorageAreaCleared(
+    const DOMStorageArea* area,
     const GURL& page_url) {
-  SendDomStorageEvent(area, page_url,
+  SendDOMStorageEvent(area, page_url,
                       base::NullableString16(),
                       base::NullableString16(),
                       base::NullableString16());
 }
 
-void DOMStorageMessageFilter::SendDomStorageEvent(
-    const dom_storage::DomStorageArea* area,
+void DOMStorageMessageFilter::SendDOMStorageEvent(
+    const DOMStorageArea* area,
     const GURL& page_url,
     const base::NullableString16& key,
     const base::NullableString16& new_value,
diff --git a/content/browser/dom_storage/dom_storage_message_filter.h b/content/browser/dom_storage/dom_storage_message_filter.h
index cc6ec35..2ec928a 100644
--- a/content/browser/dom_storage/dom_storage_message_filter.h
+++ b/content/browser/dom_storage/dom_storage_message_filter.h
@@ -7,9 +7,9 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/browser/browser_message_filter.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 class GURL;
 
@@ -17,22 +17,21 @@
 class NullableString16;
 }
 
-namespace dom_storage {
-class DomStorageArea;
-class DomStorageContext;
-class DomStorageHost;
-}
-
 namespace content {
+
+class DOMStorageArea;
 class DOMStorageContextImpl;
+class DOMStorageContextWrapper;
+class DOMStorageHost;
 
 // This class handles the logistics of DOM Storage within the browser process.
 // It mostly ferries information between IPCs and the dom_storage classes.
 class DOMStorageMessageFilter
     : public BrowserMessageFilter,
-      public dom_storage::DomStorageContext::EventObserver {
+      public DOMStorageContextImpl::EventObserver {
  public:
-  explicit DOMStorageMessageFilter(int unused, DOMStorageContextImpl* context);
+  explicit DOMStorageMessageFilter(int unused,
+                                   DOMStorageContextWrapper* context);
 
  private:
   virtual ~DOMStorageMessageFilter();
@@ -52,7 +51,7 @@
   void OnOpenStorageArea(int connection_id, int64 namespace_id,
                          const GURL& origin);
   void OnCloseStorageArea(int connection_id);
-  void OnLoadStorageArea(int connection_id, dom_storage::ValuesMap* map);
+  void OnLoadStorageArea(int connection_id, DOMStorageValuesMap* map);
   void OnSetItem(int connection_id, const string16& key,
                  const string16& value, const GURL& page_url);
   void OnRemoveItem(int connection_id, const string16& key,
@@ -60,32 +59,32 @@
   void OnClear(int connection_id, const GURL& page_url);
   void OnFlushMessages();
 
-  // DomStorageContext::EventObserver implementation which
+  // DOMStorageContextImpl::EventObserver implementation which
   // sends events back to our renderer process.
-  virtual void OnDomStorageItemSet(
-      const dom_storage::DomStorageArea* area,
+  virtual void OnDOMStorageItemSet(
+      const DOMStorageArea* area,
       const string16& key,
       const string16& new_value,
       const base::NullableString16& old_value,
       const GURL& page_url) OVERRIDE;
-  virtual void OnDomStorageItemRemoved(
-      const dom_storage::DomStorageArea* area,
+  virtual void OnDOMStorageItemRemoved(
+      const DOMStorageArea* area,
       const string16& key,
       const string16& old_value,
       const GURL& page_url) OVERRIDE;
-  virtual void OnDomStorageAreaCleared(
-      const dom_storage::DomStorageArea* area,
+  virtual void OnDOMStorageAreaCleared(
+      const DOMStorageArea* area,
       const GURL& page_url) OVERRIDE;
 
-  void SendDomStorageEvent(
-      const dom_storage::DomStorageArea* area,
+  void SendDOMStorageEvent(
+      const DOMStorageArea* area,
       const GURL& page_url,
       const base::NullableString16& key,
       const base::NullableString16& new_value,
       const base::NullableString16& old_value);
 
-  scoped_refptr<dom_storage::DomStorageContext> context_;
-  scoped_ptr<dom_storage::DomStorageHost> host_;
+  scoped_refptr<DOMStorageContextImpl> context_;
+  scoped_ptr<DOMStorageHost> host_;
   int connection_dispatching_message_for_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageMessageFilter);
diff --git a/webkit/browser/dom_storage/dom_storage_namespace.cc b/content/browser/dom_storage/dom_storage_namespace.cc
similarity index 68%
rename from webkit/browser/dom_storage/dom_storage_namespace.cc
rename to content/browser/dom_storage/dom_storage_namespace.cc
index fe3195b..75bfdaa 100644
--- a/webkit/browser/dom_storage/dom_storage_namespace.cc
+++ b/content/browser/dom_storage/dom_storage_namespace.cc
@@ -1,33 +1,33 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_namespace.h"
+#include "content/browser/dom_storage/dom_storage_namespace.h"
 
 #include "base/basictypes.h"
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-#include "webkit/browser/dom_storage/session_storage_database.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
+#include "content/browser/dom_storage/dom_storage_area.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/session_storage_database.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
-DomStorageNamespace::DomStorageNamespace(
+DOMStorageNamespace::DOMStorageNamespace(
     const base::FilePath& directory,
-    DomStorageTaskRunner* task_runner)
+    DOMStorageTaskRunner* task_runner)
     : namespace_id_(kLocalStorageNamespaceId),
       directory_(directory),
       task_runner_(task_runner) {
 }
 
-DomStorageNamespace::DomStorageNamespace(
+DOMStorageNamespace::DOMStorageNamespace(
     int64 namespace_id,
     const std::string& persistent_namespace_id,
     SessionStorageDatabase* session_storage_database,
-    DomStorageTaskRunner* task_runner)
+    DOMStorageTaskRunner* task_runner)
     : namespace_id_(namespace_id),
       persistent_namespace_id_(persistent_namespace_id),
       task_runner_(task_runner),
@@ -35,19 +35,19 @@
   DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
 }
 
-DomStorageNamespace::~DomStorageNamespace() {
+DOMStorageNamespace::~DOMStorageNamespace() {
 }
 
-DomStorageArea* DomStorageNamespace::OpenStorageArea(const GURL& origin) {
+DOMStorageArea* DOMStorageNamespace::OpenStorageArea(const GURL& origin) {
   if (AreaHolder* holder = GetAreaHolder(origin)) {
     ++(holder->open_count_);
     return holder->area_.get();
   }
-  DomStorageArea* area;
+  DOMStorageArea* area;
   if (namespace_id_ == kLocalStorageNamespaceId) {
-    area = new DomStorageArea(origin, directory_, task_runner_.get());
+    area = new DOMStorageArea(origin, directory_, task_runner_.get());
   } else {
-    area = new DomStorageArea(
+    area = new DOMStorageArea(
         namespace_id_, persistent_namespace_id_, origin,
         session_storage_database_.get(), task_runner_.get());
   }
@@ -55,7 +55,7 @@
   return area;
 }
 
-void DomStorageNamespace::CloseStorageArea(DomStorageArea* area) {
+void DOMStorageNamespace::CloseStorageArea(DOMStorageArea* area) {
   AreaHolder* holder = GetAreaHolder(area->origin());
   DCHECK(holder);
   DCHECK_EQ(holder->area_.get(), area);
@@ -64,25 +64,25 @@
   // The in-process-webkit based impl didn't do this either, but would be nice.
 }
 
-DomStorageArea* DomStorageNamespace::GetOpenStorageArea(const GURL& origin) {
+DOMStorageArea* DOMStorageNamespace::GetOpenStorageArea(const GURL& origin) {
   AreaHolder* holder = GetAreaHolder(origin);
   if (holder && holder->open_count_)
     return holder->area_.get();
   return NULL;
 }
 
-DomStorageNamespace* DomStorageNamespace::Clone(
+DOMStorageNamespace* DOMStorageNamespace::Clone(
     int64 clone_namespace_id,
     const std::string& clone_persistent_namespace_id) {
   DCHECK_NE(kLocalStorageNamespaceId, namespace_id_);
   DCHECK_NE(kLocalStorageNamespaceId, clone_namespace_id);
-  DomStorageNamespace* clone = new DomStorageNamespace(
+  DOMStorageNamespace* clone = new DOMStorageNamespace(
       clone_namespace_id, clone_persistent_namespace_id,
       session_storage_database_.get(), task_runner_.get());
   AreaMap::const_iterator it = areas_.begin();
   // Clone the in-memory structures.
   for (; it != areas_.end(); ++it) {
-    DomStorageArea* area = it->second.area_->ShallowCopy(
+    DOMStorageArea* area = it->second.area_->ShallowCopy(
         clone_namespace_id, clone_persistent_namespace_id);
     clone->areas_[it->first] = AreaHolder(area, 0);
   }
@@ -90,7 +90,7 @@
   if (session_storage_database_.get()) {
     task_runner_->PostShutdownBlockingTask(
         FROM_HERE,
-        DomStorageTaskRunner::COMMIT_SEQUENCE,
+        DOMStorageTaskRunner::COMMIT_SEQUENCE,
         base::Bind(base::IgnoreResult(&SessionStorageDatabase::CloneNamespace),
                    session_storage_database_.get(), persistent_namespace_id_,
                    clone_persistent_namespace_id));
@@ -98,7 +98,7 @@
   return clone;
 }
 
-void DomStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
+void DOMStorageNamespace::DeleteLocalStorageOrigin(const GURL& origin) {
   DCHECK(!session_storage_database_.get());
   AreaHolder* holder = GetAreaHolder(origin);
   if (holder) {
@@ -106,19 +106,19 @@
     return;
   }
   if (!directory_.empty()) {
-    scoped_refptr<DomStorageArea> area =
-        new DomStorageArea(origin, directory_, task_runner_.get());
+    scoped_refptr<DOMStorageArea> area =
+        new DOMStorageArea(origin, directory_, task_runner_.get());
     area->DeleteOrigin();
   }
 }
 
-void DomStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
-  DomStorageArea* area = OpenStorageArea(origin);
+void DOMStorageNamespace::DeleteSessionStorageOrigin(const GURL& origin) {
+  DOMStorageArea* area = OpenStorageArea(origin);
   area->FastClear();
   CloseStorageArea(area);
 }
 
-void DomStorageNamespace::PurgeMemory(PurgeOption option) {
+void DOMStorageNamespace::PurgeMemory(PurgeOption option) {
   if (directory_.empty())
     return;  // We can't purge w/o backing on disk.
   AreaMap::iterator it = areas_.begin();
@@ -147,13 +147,13 @@
   }
 }
 
-void DomStorageNamespace::Shutdown() {
+void DOMStorageNamespace::Shutdown() {
   AreaMap::const_iterator it = areas_.begin();
   for (; it != areas_.end(); ++it)
     it->second.area_->Shutdown();
 }
 
-unsigned int DomStorageNamespace::CountInMemoryAreas() const {
+unsigned int DOMStorageNamespace::CountInMemoryAreas() const {
   unsigned int area_count = 0;
   for (AreaMap::const_iterator it = areas_.begin(); it != areas_.end(); ++it) {
     if (it->second.area_->IsLoadedInMemory())
@@ -162,8 +162,8 @@
   return area_count;
 }
 
-DomStorageNamespace::AreaHolder*
-DomStorageNamespace::GetAreaHolder(const GURL& origin) {
+DOMStorageNamespace::AreaHolder*
+DOMStorageNamespace::GetAreaHolder(const GURL& origin) {
   AreaMap::iterator found = areas_.find(origin);
   if (found == areas_.end())
     return NULL;
@@ -172,16 +172,16 @@
 
 // AreaHolder
 
-DomStorageNamespace::AreaHolder::AreaHolder()
+DOMStorageNamespace::AreaHolder::AreaHolder()
     : open_count_(0) {
 }
 
-DomStorageNamespace::AreaHolder::AreaHolder(
-    DomStorageArea* area, int count)
+DOMStorageNamespace::AreaHolder::AreaHolder(
+    DOMStorageArea* area, int count)
     : area_(area), open_count_(count) {
 }
 
-DomStorageNamespace::AreaHolder::~AreaHolder() {
+DOMStorageNamespace::AreaHolder::~AreaHolder() {
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_namespace.h b/content/browser/dom_storage/dom_storage_namespace.h
similarity index 64%
rename from webkit/browser/dom_storage/dom_storage_namespace.h
rename to content/browser/dom_storage/dom_storage_namespace.h
index 758ca2e..f33042f 100644
--- a/webkit/browser/dom_storage/dom_storage_namespace.h
+++ b/content/browser/dom_storage/dom_storage_namespace.h
@@ -1,29 +1,29 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
 
 #include <map>
 
 #include "base/basictypes.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
+#include "content/common/content_export.h"
 
 class GURL;
 
-namespace dom_storage {
+namespace content {
 
-class DomStorageArea;
-class DomStorageTaskRunner;
+class DOMStorageArea;
+class DOMStorageTaskRunner;
 class SessionStorageDatabase;
 
 // Container for the set of per-origin Areas.
-// See class comments for DomStorageContext for a larger overview.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageNamespace
-    : public base::RefCountedThreadSafe<DomStorageNamespace> {
+// See class comments for DOMStorageContextImpl for a larger overview.
+class CONTENT_EXPORT DOMStorageNamespace
+    : public base::RefCountedThreadSafe<DOMStorageNamespace> {
  public:
   // Option for PurgeMemory.
   enum PurgeOption {
@@ -37,15 +37,15 @@
 
   // Constructor for a LocalStorage namespace with id of 0
   // and an optional backing directory on disk.
-  DomStorageNamespace(const base::FilePath& directory,  // may be empty
-                      DomStorageTaskRunner* task_runner);
+  DOMStorageNamespace(const base::FilePath& directory,  // may be empty
+                      DOMStorageTaskRunner* task_runner);
 
   // Constructor for a SessionStorage namespace with a non-zero id and an
   // optional backing on disk via |session_storage_database| (may be NULL).
-  DomStorageNamespace(int64 namespace_id,
+  DOMStorageNamespace(int64 namespace_id,
                       const std::string& persistent_namespace_id,
                       SessionStorageDatabase* session_storage_database,
-                      DomStorageTaskRunner* task_runner);
+                      DOMStorageTaskRunner* task_runner);
 
   int64 namespace_id() const { return namespace_id_; }
   const std::string& persistent_namespace_id() const {
@@ -55,16 +55,16 @@
   // Returns the storage area for the given origin,
   // creating instance if needed. Each call to open
   // must be balanced with a call to CloseStorageArea.
-  DomStorageArea* OpenStorageArea(const GURL& origin);
-  void CloseStorageArea(DomStorageArea* area);
+  DOMStorageArea* OpenStorageArea(const GURL& origin);
+  void CloseStorageArea(DOMStorageArea* area);
 
   // Returns the area for |origin| if it's open, otherwise NULL.
-  DomStorageArea* GetOpenStorageArea(const GURL& origin);
+  DOMStorageArea* GetOpenStorageArea(const GURL& origin);
 
   // Creates a clone of |this| namespace including
   // shallow copies of all contained areas.
   // Should only be called for session storage namespaces.
-  DomStorageNamespace* Clone(int64 clone_namespace_id,
+  DOMStorageNamespace* Clone(int64 clone_namespace_id,
                              const std::string& clone_persistent_namespace_id);
 
   void DeleteLocalStorageOrigin(const GURL& origin);
@@ -75,20 +75,20 @@
   unsigned int CountInMemoryAreas() const;
 
  private:
-  friend class base::RefCountedThreadSafe<DomStorageNamespace>;
+  friend class base::RefCountedThreadSafe<DOMStorageNamespace>;
 
   // Struct to hold references to our contained areas and
   // to keep track of how many tabs have a given area open.
   struct AreaHolder {
-    scoped_refptr<DomStorageArea> area_;
+    scoped_refptr<DOMStorageArea> area_;
     int open_count_;
     AreaHolder();
-    AreaHolder(DomStorageArea* area, int count);
+    AreaHolder(DOMStorageArea* area, int count);
     ~AreaHolder();
   };
   typedef std::map<GURL, AreaHolder> AreaMap;
 
-  ~DomStorageNamespace();
+  ~DOMStorageNamespace();
 
   // Returns a pointer to the area holder in our map or NULL.
   AreaHolder* GetAreaHolder(const GURL& origin);
@@ -97,11 +97,11 @@
   std::string persistent_namespace_id_;
   base::FilePath directory_;
   AreaMap areas_;
-  scoped_refptr<DomStorageTaskRunner> task_runner_;
+  scoped_refptr<DOMStorageTaskRunner> task_runner_;
   scoped_refptr<SessionStorageDatabase> session_storage_database_;
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_NAMESPACE_H_
diff --git a/webkit/browser/dom_storage/dom_storage_session.cc b/content/browser/dom_storage/dom_storage_session.cc
similarity index 61%
rename from webkit/browser/dom_storage/dom_storage_session.cc
rename to content/browser/dom_storage/dom_storage_session.cc
index 2c33ed3..7706ec8 100644
--- a/webkit/browser/dom_storage/dom_storage_session.cc
+++ b/content/browser/dom_storage/dom_storage_session.cc
@@ -1,30 +1,30 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_session.h"
+#include "content/browser/dom_storage/dom_storage_session.h"
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
 #include "base/tracked_objects.h"
-#include "webkit/browser/dom_storage/dom_storage_context.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
 
-namespace dom_storage {
+namespace content {
 
-DomStorageSession::DomStorageSession(DomStorageContext* context)
+DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context)
     : context_(context),
       namespace_id_(context->AllocateSessionId()),
       persistent_namespace_id_(context->AllocatePersistentSessionId()),
       should_persist_(false) {
   context->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageContext::CreateSessionNamespace,
+      base::Bind(&DOMStorageContextImpl::CreateSessionNamespace,
                  context_, namespace_id_, persistent_namespace_id_));
 }
 
-DomStorageSession::DomStorageSession(DomStorageContext* context,
+DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context,
                                      const std::string& persistent_namespace_id)
     : context_(context),
       namespace_id_(context->AllocateSessionId()),
@@ -32,39 +32,39 @@
       should_persist_(false) {
   context->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageContext::CreateSessionNamespace,
+      base::Bind(&DOMStorageContextImpl::CreateSessionNamespace,
                  context_, namespace_id_, persistent_namespace_id_));
 }
 
-void DomStorageSession::SetShouldPersist(bool should_persist) {
+void DOMStorageSession::SetShouldPersist(bool should_persist) {
   should_persist_ = should_persist;
 }
 
-bool DomStorageSession::should_persist() const {
+bool DOMStorageSession::should_persist() const {
   return should_persist_;
 }
 
-bool DomStorageSession::IsFromContext(DomStorageContext* context) {
+bool DOMStorageSession::IsFromContext(DOMStorageContextImpl* context) {
   return context_.get() == context;
 }
 
-DomStorageSession* DomStorageSession::Clone() {
+DOMStorageSession* DOMStorageSession::Clone() {
   return CloneFrom(context_.get(), namespace_id_);
 }
 
 // static
-DomStorageSession* DomStorageSession::CloneFrom(DomStorageContext* context,
+DOMStorageSession* DOMStorageSession::CloneFrom(DOMStorageContextImpl* context,
                                                 int64 namepace_id_to_clone) {
   int64 clone_id = context->AllocateSessionId();
   std::string persistent_clone_id = context->AllocatePersistentSessionId();
   context->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageContext::CloneSessionNamespace,
+      base::Bind(&DOMStorageContextImpl::CloneSessionNamespace,
                  context, namepace_id_to_clone, clone_id, persistent_clone_id));
-  return new DomStorageSession(context, clone_id, persistent_clone_id);
+  return new DOMStorageSession(context, clone_id, persistent_clone_id);
 }
 
-DomStorageSession::DomStorageSession(DomStorageContext* context,
+DOMStorageSession::DOMStorageSession(DOMStorageContextImpl* context,
                                      int64 namespace_id,
                                      const std::string& persistent_namespace_id)
     : context_(context),
@@ -74,11 +74,11 @@
   // This ctor is intended for use by the Clone() method.
 }
 
-DomStorageSession::~DomStorageSession() {
+DOMStorageSession::~DOMStorageSession() {
   context_->task_runner()->PostTask(
       FROM_HERE,
-      base::Bind(&DomStorageContext::DeleteSessionNamespace,
+      base::Bind(&DOMStorageContextImpl::DeleteSessionNamespace,
                  context_, namespace_id_, should_persist_));
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/browser/dom_storage/dom_storage_session.h b/content/browser/dom_storage/dom_storage_session.h
new file mode 100644
index 0000000..62c6d97
--- /dev/null
+++ b/content/browser/dom_storage/dom_storage_session.h
@@ -0,0 +1,65 @@
+// 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 CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+
+namespace content {
+
+class DOMStorageContextImpl;
+
+// This refcounted class determines the lifetime of a session
+// storage namespace and provides an interface to Clone() an
+// existing session storage namespace. It may be used on any thread.
+// See class comments for DOMStorageContextImpl for a larger overview.
+class CONTENT_EXPORT DOMStorageSession
+    : public base::RefCountedThreadSafe<DOMStorageSession> {
+ public:
+  // Constructs a |DOMStorageSession| and allocates new IDs for it.
+  explicit DOMStorageSession(DOMStorageContextImpl* context);
+
+  // Constructs a |DOMStorageSession| and assigns |persistent_namespace_id|
+  // to it. Allocates a new non-persistent ID.
+  DOMStorageSession(DOMStorageContextImpl* context,
+                    const std::string& persistent_namespace_id);
+
+  int64 namespace_id() const { return namespace_id_; }
+  const std::string& persistent_namespace_id() const {
+    return persistent_namespace_id_;
+  }
+  void SetShouldPersist(bool should_persist);
+  bool should_persist() const;
+  bool IsFromContext(DOMStorageContextImpl* context);
+  DOMStorageSession* Clone();
+
+  // Constructs a |DOMStorageSession| by cloning
+  // |namespace_id_to_clone|. Allocates new IDs for it.
+  static DOMStorageSession* CloneFrom(DOMStorageContextImpl* context,
+                                      int64 namepace_id_to_clone);
+
+ private:
+  friend class base::RefCountedThreadSafe<DOMStorageSession>;
+
+  DOMStorageSession(DOMStorageContextImpl* context,
+                    int64 namespace_id,
+                    const std::string& persistent_namespace_id);
+  ~DOMStorageSession();
+
+  scoped_refptr<DOMStorageContextImpl> context_;
+  int64 namespace_id_;
+  std::string persistent_namespace_id_;
+  bool should_persist_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DOMStorageSession);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
diff --git a/webkit/browser/dom_storage/dom_storage_task_runner.cc b/content/browser/dom_storage/dom_storage_task_runner.cc
similarity index 70%
rename from webkit/browser/dom_storage/dom_storage_task_runner.cc
rename to content/browser/dom_storage/dom_storage_task_runner.cc
index e1cc2f4..aa75c3c 100644
--- a/webkit/browser/dom_storage/dom_storage_task_runner.cc
+++ b/content/browser/dom_storage/dom_storage_task_runner.cc
@@ -1,25 +1,25 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/dom_storage_task_runner.h"
+#include "content/browser/dom_storage/dom_storage_task_runner.h"
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/tracked_objects.h"
 
-namespace dom_storage {
+namespace content {
 
-// DomStorageTaskRunner
+// DOMStorageTaskRunner
 
-bool DomStorageTaskRunner::RunsTasksOnCurrentThread() const {
+bool DOMStorageTaskRunner::RunsTasksOnCurrentThread() const {
   return IsRunningOnSequence(PRIMARY_SEQUENCE);
 }
 
-// DomStorageWorkerPoolTaskRunner
+// DOMStorageWorkerPoolTaskRunner
 
-DomStorageWorkerPoolTaskRunner::DomStorageWorkerPoolTaskRunner(
+DOMStorageWorkerPoolTaskRunner::DOMStorageWorkerPoolTaskRunner(
     base::SequencedWorkerPool* sequenced_worker_pool,
     base::SequencedWorkerPool::SequenceToken primary_sequence_token,
     base::SequencedWorkerPool::SequenceToken commit_sequence_token,
@@ -30,10 +30,10 @@
       commit_sequence_token_(commit_sequence_token) {
 }
 
-DomStorageWorkerPoolTaskRunner::~DomStorageWorkerPoolTaskRunner() {
+DOMStorageWorkerPoolTaskRunner::~DOMStorageWorkerPoolTaskRunner() {
 }
 
-bool DomStorageWorkerPoolTaskRunner::PostDelayedTask(
+bool DOMStorageWorkerPoolTaskRunner::PostDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
@@ -48,12 +48,12 @@
   // Post a task to call this->PostTask() after the delay.
   return message_loop_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(base::IgnoreResult(&DomStorageWorkerPoolTaskRunner::PostTask),
+      base::Bind(base::IgnoreResult(&DOMStorageWorkerPoolTaskRunner::PostTask),
                  this, from_here, task),
       delay);
 }
 
-bool DomStorageWorkerPoolTaskRunner::PostShutdownBlockingTask(
+bool DOMStorageWorkerPoolTaskRunner::PostShutdownBlockingTask(
     const tracked_objects::Location& from_here,
     SequenceID sequence_id,
     const base::Closure& task) {
@@ -62,46 +62,46 @@
       base::SequencedWorkerPool::BLOCK_SHUTDOWN);
 }
 
-bool DomStorageWorkerPoolTaskRunner::IsRunningOnSequence(
+bool DOMStorageWorkerPoolTaskRunner::IsRunningOnSequence(
     SequenceID sequence_id) const {
   return sequenced_worker_pool_->IsRunningSequenceOnCurrentThread(
       IDtoToken(sequence_id));
 }
 
 base::SequencedWorkerPool::SequenceToken
-DomStorageWorkerPoolTaskRunner::IDtoToken(SequenceID id) const {
+DOMStorageWorkerPoolTaskRunner::IDtoToken(SequenceID id) const {
   if (id == PRIMARY_SEQUENCE)
     return primary_sequence_token_;
   DCHECK_EQ(COMMIT_SEQUENCE, id);
   return commit_sequence_token_;
 }
 
-// MockDomStorageTaskRunner
+// MockDOMStorageTaskRunner
 
-MockDomStorageTaskRunner::MockDomStorageTaskRunner(
+MockDOMStorageTaskRunner::MockDOMStorageTaskRunner(
     base::MessageLoopProxy* message_loop)
     : message_loop_(message_loop) {
 }
 
-MockDomStorageTaskRunner::~MockDomStorageTaskRunner() {
+MockDOMStorageTaskRunner::~MockDOMStorageTaskRunner() {
 }
 
-bool MockDomStorageTaskRunner::PostDelayedTask(
+bool MockDOMStorageTaskRunner::PostDelayedTask(
     const tracked_objects::Location& from_here,
     const base::Closure& task,
     base::TimeDelta delay) {
   return message_loop_->PostTask(from_here, task);
 }
 
-bool MockDomStorageTaskRunner::PostShutdownBlockingTask(
+bool MockDOMStorageTaskRunner::PostShutdownBlockingTask(
     const tracked_objects::Location& from_here,
     SequenceID sequence_id,
     const base::Closure& task) {
   return message_loop_->PostTask(from_here, task);
 }
 
-bool MockDomStorageTaskRunner::IsRunningOnSequence(SequenceID) const {
+bool MockDOMStorageTaskRunner::IsRunningOnSequence(SequenceID) const {
   return message_loop_->RunsTasksOnCurrentThread();
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/dom_storage_task_runner.h b/content/browser/dom_storage/dom_storage_task_runner.h
similarity index 81%
rename from webkit/browser/dom_storage/dom_storage_task_runner.h
rename to content/browser/dom_storage/dom_storage_task_runner.h
index a18bedf..1fb8a19 100644
--- a/webkit/browser/dom_storage/dom_storage_task_runner.h
+++ b/content/browser/dom_storage/dom_storage_task_runner.h
@@ -1,23 +1,23 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
+#define CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
 
 #include "base/memory/ref_counted.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/time/time.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
+#include "content/common/content_export.h"
 
 namespace base {
 class MessageLoopProxy;
 }
 
-namespace dom_storage {
+namespace content {
 
-// DomStorage uses two task sequences (primary vs commit) to avoid
+// DOMStorage uses two task sequences (primary vs commit) to avoid
 // primary access from queuing up behind commits to disk.
 // * Initialization, shutdown, and administrative tasks are performed as
 //   shutdown-blocking primary sequence tasks.
@@ -26,7 +26,7 @@
 //   TODO(michaeln): Skip tasks for reading during shutdown.
 // * Internal tasks related to committing changes to disk are performed as
 //   shutdown-blocking commit sequence tasks.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageTaskRunner
+class CONTENT_EXPORT DOMStorageTaskRunner
     : public base::TaskRunner {
  public:
   enum SequenceID {
@@ -61,16 +61,16 @@
   }
 
  protected:
-  virtual ~DomStorageTaskRunner() {}
+  virtual ~DOMStorageTaskRunner() {}
 };
 
 // A derived class used in chromium that utilizes a SequenceWorkerPool
 // under dom_storage specific SequenceTokens. The |delayed_task_loop|
 // is used to delay scheduling on the worker pool.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageWorkerPoolTaskRunner :
-      public DomStorageTaskRunner {
+class CONTENT_EXPORT DOMStorageWorkerPoolTaskRunner :
+      public DOMStorageTaskRunner {
  public:
-  DomStorageWorkerPoolTaskRunner(
+  DOMStorageWorkerPoolTaskRunner(
       base::SequencedWorkerPool* sequenced_worker_pool,
       base::SequencedWorkerPool::SequenceToken primary_sequence_token,
       base::SequencedWorkerPool::SequenceToken commit_sequence_token,
@@ -89,7 +89,7 @@
   virtual bool IsRunningOnSequence(SequenceID sequence_id) const OVERRIDE;
 
  protected:
-  virtual ~DomStorageWorkerPoolTaskRunner();
+  virtual ~DOMStorageWorkerPoolTaskRunner();
 
  private:
 
@@ -106,10 +106,10 @@
 // There is no distinction between [non]-shutdown-blocking or
 // the primary sequence vs the commit sequence in the mock,
 // all tasks are scheduled on |message_loop| with zero delay.
-class WEBKIT_STORAGE_BROWSER_EXPORT MockDomStorageTaskRunner :
-      public DomStorageTaskRunner {
+class CONTENT_EXPORT MockDOMStorageTaskRunner :
+      public DOMStorageTaskRunner {
  public:
-  explicit MockDomStorageTaskRunner(base::MessageLoopProxy* message_loop);
+  explicit MockDOMStorageTaskRunner(base::MessageLoopProxy* message_loop);
 
   virtual bool PostDelayedTask(
       const tracked_objects::Location& from_here,
@@ -124,12 +124,12 @@
   virtual bool IsRunningOnSequence(SequenceID sequence_id) const OVERRIDE;
 
  protected:
-  virtual ~MockDomStorageTaskRunner();
+  virtual ~MockDOMStorageTaskRunner();
 
  private:
   const scoped_refptr<base::MessageLoopProxy> message_loop_;
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_DOM_STORAGE_TASK_RUNNER_
diff --git a/content/browser/dom_storage/local_storage_database_adapter.cc b/content/browser/dom_storage/local_storage_database_adapter.cc
new file mode 100644
index 0000000..f5d87e3
--- /dev/null
+++ b/content/browser/dom_storage/local_storage_database_adapter.cc
@@ -0,0 +1,40 @@
+// 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 "content/browser/dom_storage/local_storage_database_adapter.h"
+
+#include "base/file_util.h"
+#include "content/browser/dom_storage/dom_storage_database.h"
+
+namespace content {
+
+LocalStorageDatabaseAdapter::LocalStorageDatabaseAdapter(
+    const base::FilePath& path)
+    : db_(new DOMStorageDatabase(path)) {
+}
+
+LocalStorageDatabaseAdapter::~LocalStorageDatabaseAdapter() { }
+
+void LocalStorageDatabaseAdapter::ReadAllValues(DOMStorageValuesMap* result) {
+  db_->ReadAllValues(result);
+}
+
+bool LocalStorageDatabaseAdapter::CommitChanges(
+    bool clear_all_first, const DOMStorageValuesMap& changes) {
+  return db_->CommitChanges(clear_all_first, changes);
+}
+
+void LocalStorageDatabaseAdapter::DeleteFiles() {
+  sql::Connection::Delete(db_->file_path());
+}
+
+void LocalStorageDatabaseAdapter::Reset() {
+  db_.reset(new DOMStorageDatabase(db_->file_path()));
+}
+
+LocalStorageDatabaseAdapter::LocalStorageDatabaseAdapter()
+    : db_(new DOMStorageDatabase()) {
+}
+
+}  // namespace content
diff --git a/content/browser/dom_storage/local_storage_database_adapter.h b/content/browser/dom_storage/local_storage_database_adapter.h
new file mode 100644
index 0000000..1298d9c
--- /dev/null
+++ b/content/browser/dom_storage/local_storage_database_adapter.h
@@ -0,0 +1,50 @@
+// 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 CONTENT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
+#define CONTENT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/browser/dom_storage/dom_storage_database_adapter.h"
+#include "content/common/content_export.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+
+class DOMStorageDatabase;
+
+class CONTENT_EXPORT LocalStorageDatabaseAdapter :
+      public DOMStorageDatabaseAdapter {
+ public:
+  explicit LocalStorageDatabaseAdapter(const base::FilePath& path);
+  virtual ~LocalStorageDatabaseAdapter();
+  virtual void ReadAllValues(DOMStorageValuesMap* result) OVERRIDE;
+  virtual bool CommitChanges(bool clear_all_first,
+                             const DOMStorageValuesMap& changes) OVERRIDE;
+  virtual void DeleteFiles() OVERRIDE;
+  virtual void Reset() OVERRIDE;
+
+ protected:
+  // Constructor that uses an in-memory sqlite database, for testing.
+  LocalStorageDatabaseAdapter();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, BackingDatabaseOpened);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitChangesAtShutdown);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, CommitTasks);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, DeleteOrigin);
+  FRIEND_TEST_ALL_PREFIXES(DOMStorageAreaTest, PurgeMemory);
+
+  scoped_ptr<DOMStorageDatabase> db_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalStorageDatabaseAdapter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/dom_storage/session_storage_database.cc b/content/browser/dom_storage/session_storage_database.cc
similarity index 96%
rename from webkit/browser/dom_storage/session_storage_database.cc
rename to content/browser/dom_storage/session_storage_database.cc
index 8352a9c..bac3df7 100644
--- a/webkit/browser/dom_storage/session_storage_database.cc
+++ b/content/browser/dom_storage/session_storage_database.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/session_storage_database.h"
+#include "content/browser/dom_storage/session_storage_database.h"
 
 #include "base/file_util.h"
 #include "base/logging.h"
@@ -49,7 +49,7 @@
 // | namespace-3-origin2            | 2 (shallow copy)                   |
 // | next-map-id                    | 4                                  |
 
-namespace dom_storage {
+namespace content {
 
 SessionStorageDatabase::SessionStorageDatabase(const base::FilePath& file_path)
     : file_path_(file_path),
@@ -62,7 +62,7 @@
 
 void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id,
                                             const GURL& origin,
-                                            ValuesMap* result) {
+                                            DOMStorageValuesMap* result) {
   // We don't create a database if it doesn't exist. In that case, there is
   // nothing to be added to the result.
   if (!LazyOpen(false))
@@ -83,10 +83,11 @@
   db_->ReleaseSnapshot(options.snapshot);
 }
 
-bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id,
-                                               const GURL& origin,
-                                               bool clear_all_first,
-                                               const ValuesMap& changes) {
+bool SessionStorageDatabase::CommitAreaChanges(
+    const std::string& namespace_id,
+    const GURL& origin,
+    bool clear_all_first,
+    const DOMStorageValuesMap& changes) {
   // Even if |changes| is empty, we need to write the appropriate placeholders
   // in the database, so that it can be later shallow-copied succssfully.
   if (!LazyOpen(true))
@@ -502,7 +503,7 @@
 
 bool SessionStorageDatabase::ReadMap(const std::string& map_id,
                                      const leveldb::ReadOptions& options,
-                                     ValuesMap* result,
+                                     DOMStorageValuesMap* result,
                                      bool only_keys) {
   scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
   std::string map_start_key = MapRefCountKey(map_id);
@@ -539,9 +540,10 @@
 }
 
 void SessionStorageDatabase::WriteValuesToMap(const std::string& map_id,
-                                              const ValuesMap& values,
+                                              const DOMStorageValuesMap& values,
                                               leveldb::WriteBatch* batch) {
-  for (ValuesMap::const_iterator it = values.begin(); it != values.end();
+  for (DOMStorageValuesMap::const_iterator it = values.begin();
+       it != values.end();
        ++it) {
     base::NullableString16 value = it->second;
     std::string key = MapKey(map_id, UTF16ToUTF8(it->first));
@@ -601,10 +603,11 @@
 
 bool SessionStorageDatabase::ClearMap(const std::string& map_id,
                                       leveldb::WriteBatch* batch) {
-  ValuesMap values;
+  DOMStorageValuesMap values;
   if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true))
     return false;
-  for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it)
+  for (DOMStorageValuesMap::const_iterator it = values.begin();
+       it != values.end(); ++it)
     batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first)));
   return true;
 }
@@ -632,7 +635,7 @@
 
   // Read the values from the old map here. If we don't need to copy the data,
   // this can stay empty.
-  ValuesMap values;
+  DOMStorageValuesMap values;
   if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false))
     return false;
   if (!DecreaseMapRefCount(*map_id, 1, batch))
@@ -674,4 +677,4 @@
   return "next-map-id";
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/webkit/browser/dom_storage/session_storage_database.h b/content/browser/dom_storage/session_storage_database.h
similarity index 91%
rename from webkit/browser/dom_storage/session_storage_database.h
rename to content/browser/dom_storage/session_storage_database.h
index c442504..09d4773 100644
--- a/webkit/browser/dom_storage/session_storage_database.h
+++ b/content/browser/dom_storage/session_storage_database.h
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
+#ifndef CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
+#define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
 
 #include <map>
 #include <string>
@@ -12,9 +12,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/synchronization/lock.h"
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "third_party/leveldatabase/src/include/leveldb/status.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 class GURL;
 
@@ -24,16 +24,16 @@
 class WriteBatch;
 }  // namespace leveldb
 
-namespace dom_storage {
+namespace content {
 
 // SessionStorageDatabase holds the data from multiple namespaces and multiple
-// origins. All DomStorageAreas for session storage share the same
+// origins. All DOMStorageAreas for session storage share the same
 // SessionStorageDatabase.
 
 // Only one thread is allowed to call the public functions other than
 // ReadAreaValues and ReadNamespacesAndOrigins. Other threads are allowed to
 // call ReadAreaValues and ReadNamespacesAndOrigins.
-class WEBKIT_STORAGE_BROWSER_EXPORT SessionStorageDatabase :
+class CONTENT_EXPORT SessionStorageDatabase :
     public base::RefCountedThreadSafe<SessionStorageDatabase> {
  public:
   explicit SessionStorageDatabase(const base::FilePath& file_path);
@@ -44,7 +44,7 @@
   // it will not be created and |result| will be unmodified.
   void ReadAreaValues(const std::string& namespace_id,
                       const GURL& origin,
-                      ValuesMap* result);
+                      DOMStorageValuesMap* result);
 
   // Updates the data for |namespace_id| and |origin|. Will remove all keys
   // before updating the database if |clear_all_first| is set. Then all entries
@@ -55,7 +55,7 @@
   bool CommitAreaChanges(const std::string& namespace_id,
                          const GURL& origin,
                          bool clear_all_first,
-                         const ValuesMap& changes);
+                         const DOMStorageValuesMap& changes);
 
   // Creates shallow copies of the areas for |namespace_id| and associates them
   // with |new_namespace_id|.
@@ -149,11 +149,11 @@
   // be empty.
   bool ReadMap(const std::string& map_id,
                const leveldb::ReadOptions& options,
-               ValuesMap* result,
+               DOMStorageValuesMap* result,
                bool only_keys);
   // Writes |values| into the map |map_id|.
   void WriteValuesToMap(const std::string& map_id,
-                        const ValuesMap& values,
+                        const DOMStorageValuesMap& values,
                         leveldb::WriteBatch* batch);
 
   bool GetMapRefCount(const std::string& map_id, int64* ref_count);
@@ -200,6 +200,6 @@
   DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabase);
 };
 
-}  // namespace dom_storage
+}  // namespace content
 
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
+#endif  // CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_H_
diff --git a/webkit/browser/dom_storage/session_storage_database_adapter.cc b/content/browser/dom_storage/session_storage_database_adapter.cc
similarity index 63%
rename from webkit/browser/dom_storage/session_storage_database_adapter.cc
rename to content/browser/dom_storage/session_storage_database_adapter.cc
index 766f1cb..69f5bcd 100644
--- a/webkit/browser/dom_storage/session_storage_database_adapter.cc
+++ b/content/browser/dom_storage/session_storage_database_adapter.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/session_storage_database_adapter.h"
+#include "content/browser/dom_storage/session_storage_database_adapter.h"
 
-#include "webkit/browser/dom_storage/session_storage_database.h"
+#include "content/browser/dom_storage/session_storage_database.h"
 
-namespace dom_storage {
+namespace content {
 
 SessionStorageDatabaseAdapter::SessionStorageDatabaseAdapter(
     SessionStorageDatabase* db,
@@ -19,14 +19,14 @@
 
 SessionStorageDatabaseAdapter::~SessionStorageDatabaseAdapter() { }
 
-void SessionStorageDatabaseAdapter::ReadAllValues(ValuesMap* result) {
+void SessionStorageDatabaseAdapter::ReadAllValues(DOMStorageValuesMap* result) {
   db_->ReadAreaValues(permanent_namespace_id_, origin_, result);
 }
 
 bool SessionStorageDatabaseAdapter::CommitChanges(
-    bool clear_all_first, const ValuesMap& changes) {
+    bool clear_all_first, const DOMStorageValuesMap& changes) {
   return db_->CommitAreaChanges(permanent_namespace_id_, origin_,
                                 clear_all_first, changes);
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/browser/dom_storage/session_storage_database_adapter.h b/content/browser/dom_storage/session_storage_database_adapter.h
new file mode 100644
index 0000000..9db5f17
--- /dev/null
+++ b/content/browser/dom_storage/session_storage_database_adapter.h
@@ -0,0 +1,35 @@
+// 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 CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
+#define CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
+
+#include "base/memory/ref_counted.h"
+#include "content/browser/dom_storage/dom_storage_database_adapter.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class SessionStorageDatabase;
+
+class SessionStorageDatabaseAdapter : public DOMStorageDatabaseAdapter {
+ public:
+  SessionStorageDatabaseAdapter(SessionStorageDatabase* db,
+                                const std::string& permanent_namespace_id,
+                                const GURL& origin);
+  virtual ~SessionStorageDatabaseAdapter();
+  virtual void ReadAllValues(DOMStorageValuesMap* result) OVERRIDE;
+  virtual bool CommitChanges(bool clear_all_first,
+                             const DOMStorageValuesMap& changes) OVERRIDE;
+ private:
+  scoped_refptr<SessionStorageDatabase> db_;
+  std::string permanent_namespace_id_;
+  GURL origin_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseAdapter);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/dom_storage/session_storage_database_unittest.cc b/content/browser/dom_storage/session_storage_database_unittest.cc
similarity index 92%
rename from webkit/browser/dom_storage/session_storage_database_unittest.cc
rename to content/browser/dom_storage/session_storage_database_unittest.cc
index 127b183..9722d72 100644
--- a/webkit/browser/dom_storage/session_storage_database_unittest.cc
+++ b/content/browser/dom_storage/session_storage_database_unittest.cc
@@ -1,9 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/browser/dom_storage/session_storage_database.h"
+#include "content/browser/dom_storage/session_storage_database.h"
 
 #include <algorithm>
 #include <map>
@@ -14,14 +14,14 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/iterator.h"
 #include "third_party/leveldatabase/src/include/leveldb/options.h"
 #include "url/gurl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
-namespace dom_storage {
+namespace content {
 
 class SessionStorageDatabaseTest : public testing::Test {
  public:
@@ -48,8 +48,9 @@
   void DumpData() const;
   void CheckAreaData(const std::string& namespace_id,
                      const GURL& origin,
-                     const ValuesMap& reference) const;
-  void CompareValuesMaps(const ValuesMap& map1, const ValuesMap& map2) const;
+                     const DOMStorageValuesMap& reference) const;
+  void CompareValuesMaps(const DOMStorageValuesMap& map1,
+                         const DOMStorageValuesMap& map2) const;
   void CheckNamespaceIds(
       const std::set<std::string>& expected_namespace_ids) const;
   void CheckOrigins(
@@ -316,17 +317,18 @@
 
 void SessionStorageDatabaseTest::CheckAreaData(
     const std::string& namespace_id, const GURL& origin,
-    const ValuesMap& reference) const {
-  ValuesMap values;
+    const DOMStorageValuesMap& reference) const {
+  DOMStorageValuesMap values;
   db_->ReadAreaValues(namespace_id, origin, &values);
   CompareValuesMaps(values, reference);
 }
 
 void SessionStorageDatabaseTest::CompareValuesMaps(
-    const ValuesMap& map1,
-    const ValuesMap& map2) const {
+    const DOMStorageValuesMap& map1,
+    const DOMStorageValuesMap& map2) const {
   ASSERT_EQ(map2.size(), map1.size());
-  for (ValuesMap::const_iterator it = map1.begin(); it != map1.end(); ++it) {
+  for (DOMStorageValuesMap::const_iterator it = map1.begin();
+       it != map1.end(); ++it) {
     base::string16 key = it->first;
     ASSERT_TRUE(map2.find(key) != map2.end());
     base::NullableString16 val1 = it->second;
@@ -386,10 +388,10 @@
 
 TEST_F(SessionStorageDatabaseTest, WriteDataForOneOrigin) {
   // Keep track on what the values should look like.
-  ValuesMap reference;
+  DOMStorageValuesMap reference;
   // Write data.
   {
-    ValuesMap changes;
+    DOMStorageValuesMap changes;
     changes[kKey1] = kValue1;
     changes[kKey2] = kValue2;
     changes[kKey3] = kValue3;
@@ -403,7 +405,7 @@
 
   // Overwrite and delete values.
   {
-    ValuesMap changes;
+    DOMStorageValuesMap changes;
     changes[kKey1] = kValue4;
     changes[kKey3] = kValueNull;
     reference[kKey1] = kValue4;
@@ -415,7 +417,7 @@
 
   // Clear data before writing.
   {
-    ValuesMap changes;
+    DOMStorageValuesMap changes;
     changes[kKey2] = kValue2;
     reference.erase(kKey1);
     reference[kKey2] = kValue2;
@@ -427,13 +429,13 @@
 
 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoOrigins) {
   // Write data.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
 
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue4;
   data2[kKey2] = kValue1;
   data2[kKey3] = kValue2;
@@ -446,20 +448,20 @@
 
 TEST_F(SessionStorageDatabaseTest, WriteDataForTwoNamespaces) {
   // Write data.
-  ValuesMap data11;
+  DOMStorageValuesMap data11;
   data11[kKey1] = kValue1;
   data11[kKey2] = kValue2;
   data11[kKey3] = kValue3;
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data11));
-  ValuesMap data12;
+  DOMStorageValuesMap data12;
   data12[kKey2] = kValue4;
   data12[kKey3] = kValue3;
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data12));
-  ValuesMap data21;
+  DOMStorageValuesMap data21;
   data21[kKey1] = kValue2;
   data21[kKey2] = kValue4;
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin1, false, data21));
-  ValuesMap data22;
+  DOMStorageValuesMap data22;
   data22[kKey2] = kValue1;
   data22[kKey3] = kValue2;
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace2, kOrigin2, false, data22));
@@ -472,12 +474,12 @@
 
 TEST_F(SessionStorageDatabaseTest, ShallowCopy) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -499,15 +501,15 @@
 }
 
 TEST_F(SessionStorageDatabaseTest, WriteIntoShallowCopy) {
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
   EXPECT_TRUE(db_->CloneNamespace(kNamespace1, kNamespaceClone));
 
   // Write data into a shallow copy.
-  ValuesMap changes;
-  ValuesMap reference;
+  DOMStorageValuesMap changes;
+  DOMStorageValuesMap reference;
   changes[kKey1] = kValueNull;
   changes[kKey2] = kValue4;
   changes[kKey3] = kValue4;
@@ -530,12 +532,12 @@
 
 TEST_F(SessionStorageDatabaseTest, ManyShallowCopies) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -580,7 +582,7 @@
 }
 
 TEST_F(SessionStorageDatabaseTest, DisassociateShallowCopy) {
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
@@ -591,8 +593,8 @@
   CheckDatabaseConsistency();
 
   // Now new data can be written to that map.
-  ValuesMap reference;
-  ValuesMap changes;
+  DOMStorageValuesMap reference;
+  DOMStorageValuesMap changes;
   changes[kKey1] = kValueNull;
   changes[kKey2] = kValue4;
   changes[kKey3] = kValue4;
@@ -609,12 +611,12 @@
 }
 
 TEST_F(SessionStorageDatabaseTest, DeleteNamespace) {
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey2] = kValue4;
   data2[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -625,12 +627,12 @@
 
 TEST_F(SessionStorageDatabaseTest, DeleteNamespaceWithShallowCopy) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -641,8 +643,8 @@
 
   // The original namespace has no data.
   CheckDatabaseConsistency();
-  CheckAreaData(kNamespace1, kOrigin1, ValuesMap());
-  CheckAreaData(kNamespace1, kOrigin2, ValuesMap());
+  CheckAreaData(kNamespace1, kOrigin1, DOMStorageValuesMap());
+  CheckAreaData(kNamespace1, kOrigin2, DOMStorageValuesMap());
   // But the copy persists.
   CheckAreaData(kNamespaceClone, kOrigin1, data1);
   CheckAreaData(kNamespaceClone, kOrigin2, data2);
@@ -650,12 +652,12 @@
 
 TEST_F(SessionStorageDatabaseTest, DeleteArea) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -665,17 +667,17 @@
   // The data for the non-deleted origin persists.
   CheckAreaData(kNamespace1, kOrigin1, data1);
   // The data for the deleted origin is gone.
-  CheckAreaData(kNamespace1, kOrigin2, ValuesMap());
+  CheckAreaData(kNamespace1, kOrigin2, DOMStorageValuesMap());
 }
 
 TEST_F(SessionStorageDatabaseTest, DeleteAreaWithShallowCopy) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   data2[kKey3] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
@@ -686,7 +688,7 @@
   CheckDatabaseConsistency();
 
   // The original namespace has data for only the non-deleted origin.
-  CheckAreaData(kNamespace1, kOrigin1, ValuesMap());
+  CheckAreaData(kNamespace1, kOrigin1, DOMStorageValuesMap());
   CheckAreaData(kNamespace1, kOrigin2, data2);
   // But the copy persists.
   CheckAreaData(kNamespaceClone, kOrigin1, data1);
@@ -696,13 +698,13 @@
 TEST_F(SessionStorageDatabaseTest, WriteRawBytes) {
   // Write data which is not valid utf8 and contains null bytes.
   unsigned char raw_data[10] = {255, 0, 0, 0, 1, 2, 3, 4, 5, 0};
-  ValuesMap changes;
+  DOMStorageValuesMap changes;
   base::string16 string_with_raw_data;
   string_with_raw_data.assign(reinterpret_cast<char16*>(raw_data), 5);
   changes[kKey1] = base::NullableString16(string_with_raw_data, false);
   EXPECT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, changes));
   CheckDatabaseConsistency();
-  ValuesMap values;
+  DOMStorageValuesMap values;
   db_->ReadAreaValues(kNamespace1, kOrigin1, &values);
   const unsigned char* data =
       reinterpret_cast<const unsigned char*>(values[kKey1].string().data());
@@ -714,7 +716,7 @@
   // Regression test for a bug where a namespace with id 10 prevented deleting
   // the namespace with id 1.
 
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges("foobar", kOrigin1, false, data1));
   ASSERT_TRUE(db_->CommitAreaChanges("foobarbaz", kOrigin1, false, data1));
@@ -724,7 +726,7 @@
 }
 
 TEST_F(SessionStorageDatabaseTest, ReadNamespaceIds) {
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
@@ -751,7 +753,7 @@
 }
 
 TEST_F(SessionStorageDatabaseTest, ReadOriginsInNamespace) {
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   data1[kKey2] = kValue2;
   data1[kKey3] = kValue3;
@@ -780,10 +782,10 @@
 
 TEST_F(SessionStorageDatabaseTest, DeleteAllOrigins) {
   // Write data for a namespace, for 2 origins.
-  ValuesMap data1;
+  DOMStorageValuesMap data1;
   data1[kKey1] = kValue1;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin1, false, data1));
-  ValuesMap data2;
+  DOMStorageValuesMap data2;
   data2[kKey1] = kValue2;
   ASSERT_TRUE(db_->CommitAreaChanges(kNamespace1, kOrigin2, false, data2));
 
@@ -794,4 +796,4 @@
 }
 
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/browser/dom_storage/session_storage_namespace_impl.cc b/content/browser/dom_storage/session_storage_namespace_impl.cc
index fb46a31..a1f7f2d 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl.cc
+++ b/content/browser/dom_storage/session_storage_namespace_impl.cc
@@ -4,28 +4,25 @@
 
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
-#include "webkit/browser/dom_storage/dom_storage_session.h"
-
-using dom_storage::DomStorageContext;
-using dom_storage::DomStorageSession;
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
+#include "content/browser/dom_storage/dom_storage_session.h"
 
 namespace content {
 
 SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
-    DOMStorageContextImpl* context)
-    : session_(new DomStorageSession(context->context())) {
+    DOMStorageContextWrapper* context)
+    : session_(new DOMStorageSession(context->context())) {
 }
 
 SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
-    DOMStorageContextImpl* context, int64 namepace_id_to_clone)
-    : session_(DomStorageSession::CloneFrom(context->context(),
+    DOMStorageContextWrapper* context, int64 namepace_id_to_clone)
+    : session_(DOMStorageSession::CloneFrom(context->context(),
                                             namepace_id_to_clone)) {
 }
 
 SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
-    DOMStorageContextImpl* context, const std::string& persistent_id)
-    : session_(new DomStorageSession(context->context(), persistent_id)) {
+    DOMStorageContextWrapper* context, const std::string& persistent_id)
+    : session_(new DOMStorageSession(context->context(), persistent_id)) {
 }
 
 int64 SessionStorageNamespaceImpl::id() const {
@@ -49,12 +46,12 @@
 }
 
 bool SessionStorageNamespaceImpl::IsFromContext(
-    DOMStorageContextImpl* context) {
+    DOMStorageContextWrapper* context) {
   return session_->IsFromContext(context->context());
 }
 
 SessionStorageNamespaceImpl::SessionStorageNamespaceImpl(
-    DomStorageSession* clone)
+    DOMStorageSession* clone)
     : session_(clone) {
 }
 
diff --git a/content/browser/dom_storage/session_storage_namespace_impl.h b/content/browser/dom_storage/session_storage_namespace_impl.h
index edae801..d741848 100644
--- a/content/browser/dom_storage/session_storage_namespace_impl.h
+++ b/content/browser/dom_storage/session_storage_namespace_impl.h
@@ -10,12 +10,10 @@
 #include "content/common/content_export.h"
 #include "content/public/browser/session_storage_namespace.h"
 
-namespace dom_storage {
-class DomStorageSession;
-}
-
 namespace content {
-class DOMStorageContextImpl;
+
+class DOMStorageContextWrapper;
+class DOMStorageSession;
 
 class SessionStorageNamespaceImpl
     : NON_EXPORTED_BASE(public SessionStorageNamespace) {
@@ -24,16 +22,16 @@
   //
   // The CONTENT_EXPORT allows TestRenderViewHost to instantiate these.
   CONTENT_EXPORT explicit SessionStorageNamespaceImpl(
-      DOMStorageContextImpl* context);
+      DOMStorageContextWrapper* context);
 
   // Constructs a |SessionStorageNamespaceImpl| by cloning
   // |namespace_to_clone|. Allocates new IDs for it.
-  SessionStorageNamespaceImpl(DOMStorageContextImpl* context,
+  SessionStorageNamespaceImpl(DOMStorageContextWrapper* context,
                               int64 namepace_id_to_clone);
 
   // Constructs a |SessionStorageNamespaceImpl| and assigns |persistent_id|
   // to it. Allocates a new non-persistent ID.
-  SessionStorageNamespaceImpl(DOMStorageContextImpl* context,
+  SessionStorageNamespaceImpl(DOMStorageContextWrapper* context,
                               const std::string& persistent_id);
 
   // SessionStorageNamespace implementation.
@@ -43,13 +41,13 @@
   virtual bool should_persist() const OVERRIDE;
 
   SessionStorageNamespaceImpl* Clone();
-  bool IsFromContext(DOMStorageContextImpl* context);
+  bool IsFromContext(DOMStorageContextWrapper* context);
 
  private:
-  explicit SessionStorageNamespaceImpl(dom_storage::DomStorageSession* clone);
+  explicit SessionStorageNamespaceImpl(DOMStorageSession* clone);
   virtual ~SessionStorageNamespaceImpl();
 
-  scoped_refptr<dom_storage::DomStorageSession> session_;
+  scoped_refptr<DOMStorageSession> session_;
 
   DISALLOW_COPY_AND_ASSIGN(SessionStorageNamespaceImpl);
 };
diff --git a/content/browser/media/webrtc_browsertest.cc b/content/browser/media/webrtc_browsertest.cc
index 8ab977d..58b3d3f 100644
--- a/content/browser/media/webrtc_browsertest.cc
+++ b/content/browser/media/webrtc_browsertest.cc
@@ -282,4 +282,14 @@
     ExpectTitle("OK");
   }
 }
+
+IN_PROC_BROWSER_TEST_F(WebrtcBrowserTest, AddTwoMediaStreamsToOnePC) {
+  GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
+  NavigateToURL(shell(), url);
+
+  EXPECT_TRUE(
+      ExecuteJavascript("addTwoMediaStreamsToOneConnection();"));
+  ExpectTitle("OK");
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc b/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
index eeb8d96..95a1c6a 100644
--- a/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
+++ b/content/browser/renderer_host/java/java_bridge_dispatcher_host.cc
@@ -4,9 +4,9 @@
 
 #include "content/browser/renderer_host/java/java_bridge_dispatcher_host.h"
 
+#include "base/android/java_handler_thread.h"
 #include "base/bind.h"
 #include "base/lazy_instance.h"
-#include "base/threading/thread.h"
 #include "content/browser/renderer_host/java/java_bridge_channel_host.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/child/child_process.h"
@@ -17,12 +17,18 @@
 #include "content/public/browser/render_process_host.h"
 #include "third_party/WebKit/public/web/WebBindings.h"
 
+#if !defined(OS_ANDROID)
+#error "JavaBridge currently only supports OS_ANDROID"
+#endif
+
 namespace content {
 
 namespace {
-class JavaBridgeThread : public base::Thread {
+// The JavaBridge needs to use a Java thread so the callback
+// will happen on a thread with a prepared Looper.
+class JavaBridgeThread : public base::android::JavaHandlerThread {
  public:
-  JavaBridgeThread() : base::Thread("JavaBridge") {
+  JavaBridgeThread() : base::android::JavaHandlerThread("JavaBridge") {
     Start();
   }
   virtual ~JavaBridgeThread() {
diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc
index 37d93ef..4a2f731 100644
--- a/content/browser/renderer_host/media/audio_input_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc
@@ -15,10 +15,6 @@
 #include "content/browser/renderer_host/media/web_contents_capture_util.h"
 #include "media/audio/audio_manager_base.h"
 
-#if defined(USE_CRAS)
-#include "media/audio/cras/audio_manager_cras.h"
-#endif
-
 namespace content {
 
 struct AudioInputRendererHost::AudioEntry {
@@ -241,18 +237,7 @@
       return;
     }
 
-    if (info->device.type == content::MEDIA_SYSTEM_AUDIO_CAPTURE) {
-#if defined(USE_CRAS)
-      // Use the special loopback device ID for system audio capture.
-      device_id = media::AudioManagerCras::kLoopbackDeviceId;
-#else
-      SendErrorMessage(stream_id);
-      DLOG(WARNING) << "Loopback device is not supported on this platform";
-      return;
-#endif
-    } else {
-      device_id = info->device.id;
-    }
+    device_id = info->device.id;
   }
 
   // Create a new AudioEntry structure.
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 98959a8..e4cb17c 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -16,7 +16,7 @@
 #include "base/threading/worker_pool.h"
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
@@ -295,7 +295,7 @@
     RenderWidgetHelper* render_widget_helper,
     media::AudioManager* audio_manager,
     MediaInternals* media_internals,
-    DOMStorageContextImpl* dom_storage_context)
+    DOMStorageContextWrapper* dom_storage_context)
     : resource_dispatcher_host_(ResourceDispatcherHostImpl::Get()),
       plugin_service_(plugin_service),
       profile_data_directory_(browser_context->GetPath()),
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 3037c07..4eb9864 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -66,7 +66,7 @@
 
 namespace content {
 class BrowserContext;
-class DOMStorageContextImpl;
+class DOMStorageContextWrapper;
 class MediaInternals;
 class PluginServiceImpl;
 class RenderWidgetHelper;
@@ -88,7 +88,7 @@
                       RenderWidgetHelper* render_widget_helper,
                       media::AudioManager* audio_manager,
                       MediaInternals* media_internals,
-                      DOMStorageContextImpl* dom_storage_context);
+                      DOMStorageContextWrapper* dom_storage_context);
 
   // IPC::ChannelProxy::MessageFilter methods:
   virtual void OnChannelClosing() OVERRIDE;
@@ -284,7 +284,7 @@
   // Initialized to 0, accessed on FILE thread only.
   base::TimeTicks last_plugin_refresh_time_;
 
-  scoped_refptr<DOMStorageContextImpl> dom_storage_context_;
+  scoped_refptr<DOMStorageContextWrapper> dom_storage_context_;
 
   int render_process_id_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 36acbd9..d3ba06e 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -46,7 +46,7 @@
 #include "content/browser/device_orientation/device_motion_message_filter.h"
 #include "content/browser/device_orientation/device_orientation_message_filter.h"
 #include "content/browser/device_orientation/orientation_message_filter.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/dom_storage_message_filter.h"
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
@@ -977,9 +977,6 @@
     switches::kDefaultTileHeight,
     switches::kMaxUntiledLayerWidth,
     switches::kMaxUntiledLayerHeight,
-#if defined(OS_CHROMEOS)
-    switches::kEnableEncodedScreenCapture,
-#endif
     switches::kEnableViewport,
     switches::kEnableInbandTextTracks,
     switches::kEnableOpusPlayback,
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 647f4cf..56801c0 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -1520,16 +1520,15 @@
     const string16& message,
     int32 line_no,
     const string16& source_id) {
-  if (!delegate_->AddMessageToConsole(level, message, line_no, source_id)) {
-    // Pass through log level only on WebUI pages to limit console spew.
-    int32 resolved_level = HasWebUIScheme(delegate_->GetURL()) ? level : 0;
-    if (resolved_level >= ::logging::GetMinLogLevel()) {
-      logging::LogMessage("CONSOLE", line_no, resolved_level).stream() <<
-          "\"" << message << "\", source: " << source_id <<
-          " (" << line_no << ")";
-    }
+  if (delegate_->AddMessageToConsole(level, message, line_no, source_id))
+    return;
+  // Pass through log level only on WebUI pages to limit console spew.
+  int32 resolved_level = HasWebUIScheme(delegate_->GetURL()) ? level : 0;
+
+  if (resolved_level >= ::logging::GetMinLogLevel()) {
+    logging::LogMessage("CONSOLE", line_no, resolved_level).stream() << "\"" <<
+        message << "\", source: " << source_id << " (" << line_no << ")";
   }
-  Send(new ViewMsg_AddMessageToConsole_ACK(GetRoutingID()));
 }
 
 void RenderViewHostImpl::AddObserver(RenderViewHostObserver* observer) {
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index a395093..56be05c 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -4,10 +4,11 @@
 
 #include "content/browser/renderer_host/test_render_view_host.h"
 
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/renderer_host/test_backing_store.h"
 #include "content/browser/site_instance_impl.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/navigation_controller.h"
@@ -18,7 +19,6 @@
 #include "content/test/test_web_contents.h"
 #include "media/base/video_frame.h"
 #include "ui/gfx/rect.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/common/webpreferences.h"
 
 namespace content {
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc
index 31f0e62..2081b2f 100644
--- a/content/browser/speech/speech_recognizer_impl.cc
+++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -511,7 +511,6 @@
 
   int chunk_duration_ms = recognition_engine_->GetDesiredAudioChunkDurationMs();
 
-  // TODO(xians): use the correct input device here.
   AudioParameters in_params = audio_manager->GetInputStreamParameters(
       device_id_);
   if (!in_params.IsValid() && !unit_test_is_active) {
@@ -564,7 +563,6 @@
   audio_converter_.reset(
       new OnDataConverter(input_parameters, output_parameters));
 
-  // TODO(xians): use the correct input device here.
   audio_controller_ = AudioInputController::Create(
       audio_manager, this, input_parameters, device_id_);
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index e58ac42..1775b5f 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -9,10 +9,13 @@
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
 #include "content/browser/gpu/shader_disk_cache.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/dom_storage_context.h"
 #include "content/public/browser/indexed_db_context.h"
+#include "content/public/browser/local_storage_usage_info.h"
+#include "content/public/browser/session_storage_usage_info.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_errors.h"
 #include "net/cookies/cookie_monster.h"
@@ -20,7 +23,6 @@
 #include "net/url_request/url_request_context_getter.h"
 #include "webkit/browser/database/database_tracker.h"
 #include "webkit/browser/quota/quota_manager.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 namespace content {
 
@@ -143,11 +145,11 @@
 }
 
 void OnLocalStorageUsageInfo(
-    const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+    const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const base::Time delete_begin,
     const base::Time delete_end,
     const base::Closure& callback,
-    const std::vector<dom_storage::LocalStorageUsageInfo>& infos) {
+    const std::vector<LocalStorageUsageInfo>& infos) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   for (size_t i = 0; i < infos.size(); ++i) {
@@ -160,9 +162,9 @@
 }
 
 void OnSessionStorageUsageInfo(
-    const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+    const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const base::Closure& callback,
-    const std::vector<dom_storage::SessionStorageUsageInfo>& infos) {
+    const std::vector<SessionStorageUsageInfo>& infos) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
   for (size_t i = 0; i < infos.size(); ++i)
@@ -172,7 +174,7 @@
 }
 
 void ClearLocalStorageOnUIThread(
-    const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+    const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const GURL& remove_origin,
     const base::Time begin,
     const base::Time end,
@@ -191,7 +193,7 @@
 }
 
 void ClearSessionStorageOnUIThread(
-    const scoped_refptr<DOMStorageContextImpl>& dom_storage_context,
+    const scoped_refptr<DOMStorageContextWrapper>& dom_storage_context,
     const base::Closure& callback) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
 
@@ -248,7 +250,7 @@
                            const GURL& remove_origin,
                            const base::FilePath& path,
                            net::URLRequestContextGetter* rq_context,
-                           DOMStorageContextImpl* dom_storage_context,
+                           DOMStorageContextWrapper* dom_storage_context,
                            quota::QuotaManager* quota_manager,
                            const base::Time begin,
                            const base::Time end);
@@ -280,7 +282,7 @@
     ChromeAppCacheService* appcache_service,
     fileapi::FileSystemContext* filesystem_context,
     webkit_database::DatabaseTracker* database_tracker,
-    DOMStorageContextImpl* dom_storage_context,
+    DOMStorageContextWrapper* dom_storage_context,
     IndexedDBContextImpl* indexed_db_context,
     scoped_ptr<WebRTCIdentityStore> webrtc_identity_store)
     : partition_path_(partition_path),
@@ -345,8 +347,8 @@
               .get());
 
   base::FilePath path = in_memory ? base::FilePath() : partition_path;
-  scoped_refptr<DOMStorageContextImpl> dom_storage_context =
-      new DOMStorageContextImpl(path, context->GetSpecialStoragePolicy());
+  scoped_refptr<DOMStorageContextWrapper> dom_storage_context =
+      new DOMStorageContextWrapper(path, context->GetSpecialStoragePolicy());
 
   // BrowserMainLoop may not be initialized in unit tests. Tests will
   // need to inject their own task runner into the IndexedDBContext.
@@ -407,7 +409,7 @@
   return database_tracker_.get();
 }
 
-DOMStorageContextImpl* StoragePartitionImpl::GetDOMStorageContext() {
+DOMStorageContextWrapper* StoragePartitionImpl::GetDOMStorageContext() {
   return dom_storage_context_.get();
 }
 
@@ -542,7 +544,7 @@
     const GURL& remove_origin,
     const base::FilePath& path,
     net::URLRequestContextGetter* rq_context,
-    DOMStorageContextImpl* dom_storage_context,
+    DOMStorageContextWrapper* dom_storage_context,
     quota::QuotaManager* quota_manager,
     const base::Time begin,
     const base::Time end) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 0410f4d..8665a74 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "content/browser/appcache/chrome_appcache_service.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/media/webrtc_identity_store.h"
 #include "content/common/content_export.h"
@@ -29,7 +29,7 @@
   virtual ChromeAppCacheService* GetAppCacheService() OVERRIDE;
   virtual fileapi::FileSystemContext* GetFileSystemContext() OVERRIDE;
   virtual webkit_database::DatabaseTracker* GetDatabaseTracker() OVERRIDE;
-  virtual DOMStorageContextImpl* GetDOMStorageContext() OVERRIDE;
+  virtual DOMStorageContextWrapper* GetDOMStorageContext() OVERRIDE;
   virtual IndexedDBContextImpl* GetIndexedDBContext() OVERRIDE;
 
   virtual void ClearDataForOrigin(
@@ -75,7 +75,7 @@
       ChromeAppCacheService* appcache_service,
       fileapi::FileSystemContext* filesystem_context,
       webkit_database::DatabaseTracker* database_tracker,
-      DOMStorageContextImpl* dom_storage_context,
+      DOMStorageContextWrapper* dom_storage_context,
       IndexedDBContextImpl* indexed_db_context,
       scoped_ptr<WebRTCIdentityStore> webrtc_identity_store);
 
@@ -110,7 +110,7 @@
   scoped_refptr<ChromeAppCacheService> appcache_service_;
   scoped_refptr<fileapi::FileSystemContext> filesystem_context_;
   scoped_refptr<webkit_database::DatabaseTracker> database_tracker_;
-  scoped_refptr<DOMStorageContextImpl> dom_storage_context_;
+  scoped_refptr<DOMStorageContextWrapper> dom_storage_context_;
   scoped_refptr<IndexedDBContextImpl> indexed_db_context_;
   scoped_ptr<WebRTCIdentityStore> webrtc_identity_store_;
 
diff --git a/content/browser/web_contents/interstitial_page_impl.cc b/content/browser/web_contents/interstitial_page_impl.cc
index f08b0c9..232217d 100644
--- a/content/browser/web_contents/interstitial_page_impl.cc
+++ b/content/browser/web_contents/interstitial_page_impl.cc
@@ -12,7 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
@@ -490,9 +490,10 @@
   BrowserContext* browser_context = web_contents()->GetBrowserContext();
   scoped_refptr<SiteInstance> site_instance =
       SiteInstance::Create(browser_context);
-  DOMStorageContextImpl* dom_storage_context =
-      static_cast<DOMStorageContextImpl*>(BrowserContext::GetStoragePartition(
-          browser_context, site_instance.get())->GetDOMStorageContext());
+  DOMStorageContextWrapper* dom_storage_context =
+      static_cast<DOMStorageContextWrapper*>(
+          BrowserContext::GetStoragePartition(
+              browser_context, site_instance.get())->GetDOMStorageContext());
   session_storage_namespace_ =
       new SessionStorageNamespaceImpl(dom_storage_context);
 
diff --git a/content/browser/web_contents/navigation_controller_impl.cc b/content/browser/web_contents/navigation_controller_impl.cc
index 6176606..c3e9140 100644
--- a/content/browser/web_contents/navigation_controller_impl.cc
+++ b/content/browser/web_contents/navigation_controller_impl.cc
@@ -12,7 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "content/browser/browser_url_handler_impl.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"  // Temporary
 #include "content/browser/site_instance_impl.h"
@@ -105,18 +105,15 @@
 // See NavigationController::IsURLInPageNavigation for how this works and why.
 bool AreURLsInPageNavigation(const GURL& existing_url,
                              const GURL& new_url,
-                             bool renderer_says_in_page) {
+                             bool renderer_says_in_page,
+                             NavigationType navigation_type) {
   if (existing_url == new_url)
     return renderer_says_in_page;
 
   if (!new_url.has_ref()) {
-    // TODO(jcampan): what about when navigating back from a ref URL to the top
-    // non ref URL? Nothing is loaded in that case but we return false here.
-    // The user could also navigate from the ref URL to the non ref URL by
-    // entering the non ref URL in the location bar or through a bookmark, in
-    // which case there would be a load.  I am not sure if the non-load/load
-    // scenarios can be differentiated with the TransitionType.
-    return false;
+    // When going back from the ref URL to the non ref one the navigation type
+    // is IN_PAGE.
+    return navigation_type == NAVIGATION_TYPE_IN_PAGE;
   }
 
   url_canon::Replacements<char> replacements;
@@ -740,13 +737,13 @@
   details->did_replace_entry =
       pending_entry_ && pending_entry_->should_replace_entry();
 
-  // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = IsURLInPageNavigation(
-      params.url, params.was_within_same_page);
-
   // Do navigation-type specific actions. These will make and commit an entry.
   details->type = ClassifyNavigation(params);
 
+  // is_in_page must be computed before the entry gets committed.
+  details->is_in_page = IsURLInPageNavigation(
+      params.url, params.was_within_same_page, details->type);
+
   switch (details->type) {
     case NAVIGATION_TYPE_NEW_PAGE:
       RendererDidNavigateToNewPage(params, details->did_replace_entry);
@@ -956,7 +953,8 @@
   // navigations that don't actually navigate, but it can happen when there is
   // an encoding override (it always sends a navigation request).
   if (AreURLsInPageNavigation(existing_entry->GetURL(), params.url,
-                              params.was_within_same_page)) {
+                              params.was_within_same_page,
+                              NAVIGATION_TYPE_UNKNOWN)) {
     return NAVIGATION_TYPE_IN_PAGE;
   }
 
@@ -1197,10 +1195,12 @@
 }
 
 bool NavigationControllerImpl::IsURLInPageNavigation(
-    const GURL& url, bool renderer_says_in_page) const {
+    const GURL& url,
+    bool renderer_says_in_page,
+    NavigationType navigation_type) const {
   NavigationEntry* last_committed = GetLastCommittedEntry();
   return last_committed && AreURLsInPageNavigation(
-      last_committed->GetURL(), url, renderer_says_in_page);
+      last_committed->GetURL(), url, renderer_says_in_page, navigation_type);
 }
 
 void NavigationControllerImpl::CopyStateFrom(
@@ -1393,7 +1393,7 @@
               BrowserContext::GetStoragePartition(browser_context_, instance);
   SessionStorageNamespaceImpl* session_storage_namespace =
       new SessionStorageNamespaceImpl(
-          static_cast<DOMStorageContextImpl*>(
+          static_cast<DOMStorageContextWrapper*>(
               partition->GetDOMStorageContext()));
   session_storage_namespace_map_[partition_id] = session_storage_namespace;
 
diff --git a/content/browser/web_contents/navigation_controller_impl.h b/content/browser/web_contents/navigation_controller_impl.h
index c95ef45..bef3be2 100644
--- a/content/browser/web_contents/navigation_controller_impl.h
+++ b/content/browser/web_contents/navigation_controller_impl.h
@@ -155,7 +155,7 @@
   // be a reload, while only a different ref would be in-page (pages can't clear
   // refs without reload, only change to "#" which we don't count as empty).
   bool IsURLInPageNavigation(const GURL& url) const {
-    return IsURLInPageNavigation(url, false);
+    return IsURLInPageNavigation(url, false, NAVIGATION_TYPE_UNKNOWN);
   }
 
   // The situation is made murkier by history.replaceState(), which could
@@ -163,7 +163,10 @@
   // we need this form which lets the (untrustworthy) renderer resolve the
   // ambiguity, but only when the URLs are equal. This should be safe since the
   // origin isn't changing.
-  bool IsURLInPageNavigation(const GURL& url, bool renderer_says_in_page) const;
+  bool IsURLInPageNavigation(
+      const GURL& url,
+      bool renderer_says_in_page,
+      NavigationType navigation_type) const;
 
   // Sets the SessionStorageNamespace for the given |partition_id|. This is
   // used during initialization of a new NavigationController to allow
diff --git a/content/browser/web_contents/navigation_controller_impl_unittest.cc b/content/browser/web_contents/navigation_controller_impl_unittest.cc
index 6af4a55..c86e3a5 100644
--- a/content/browser/web_contents/navigation_controller_impl_unittest.cc
+++ b/content/browser/web_contents/navigation_controller_impl_unittest.cc
@@ -1922,6 +1922,7 @@
   params.gesture = NavigationGestureUser;
   params.is_post = false;
   params.page_state = PageState::CreateFromURL(url2);
+  params.was_within_same_page = true;
 
   // This should generate a new entry.
   EXPECT_TRUE(controller.RendererDidNavigate(params, &details));
@@ -1939,9 +1940,7 @@
   EXPECT_TRUE(controller.RendererDidNavigate(back_params, &details));
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
-  // is_in_page is false in that case but should be true.
-  // See comment in AreURLsInPageNavigation() in navigation_controller.cc
-  // EXPECT_TRUE(details.is_in_page);
+  EXPECT_TRUE(details.is_in_page);
   EXPECT_EQ(2, controller.GetEntryCount());
   EXPECT_EQ(0, controller.GetCurrentEntryIndex());
   EXPECT_EQ(back_params.url, controller.GetActiveEntry()->GetURL());
@@ -2756,8 +2755,17 @@
   EXPECT_FALSE(controller.IsURLInPageNavigation(url));
   EXPECT_FALSE(controller.IsURLInPageNavigation(other_url));
   const GURL other_url_with_ref("http://www.google.com/home.html#my_other_ref");
-  EXPECT_TRUE(controller.IsURLInPageNavigation(
-      other_url_with_ref));
+  EXPECT_TRUE(controller.IsURLInPageNavigation(other_url_with_ref));
+
+  // Going to the same url again will be considered in-page
+  // if the renderer says it is even if the navigation type isn't IN_PAGE.
+  EXPECT_TRUE(controller.IsURLInPageNavigation(url_with_ref, true,
+      NAVIGATION_TYPE_UNKNOWN));
+
+  // Going back to the non ref url will be considered in-page if the navigation
+  // type is IN_PAGE.
+  EXPECT_TRUE(controller.IsURLInPageNavigation(url, true,
+      NAVIGATION_TYPE_IN_PAGE));
 }
 
 // Some pages can have subframes with the same base URL (minus the reference) as
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index cafaea5..66e110e 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -24,7 +24,7 @@
 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/devtools_manager_impl.h"
-#include "content/browser/dom_storage/dom_storage_context_impl.h"
+#include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/download/mhtml_generation_manager.h"
@@ -1465,8 +1465,8 @@
                                        site_instance->GetSiteURL());
   StoragePartition* partition = BrowserContext::GetStoragePartition(
       GetBrowserContext(), site_instance.get());
-  DOMStorageContextImpl* dom_storage_context =
-      static_cast<DOMStorageContextImpl*>(partition->GetDOMStorageContext());
+  DOMStorageContextWrapper* dom_storage_context =
+      static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
   SessionStorageNamespaceImpl* session_storage_namespace_impl =
       static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace);
   CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
diff --git a/content/child/npapi/npobject_proxy.cc b/content/child/npapi/npobject_proxy.cc
index dcab2b4..fa28bbd 100644
--- a/content/child/npapi/npobject_proxy.cc
+++ b/content/child/npapi/npobject_proxy.cc
@@ -6,11 +6,13 @@
 
 #include "content/child/npapi/np_channel_base.h"
 #include "content/child/npapi/npobject_util.h"
-#include "content/child/npapi/plugin_host.h"
-#include "content/child/npapi/plugin_instance.h"
 #include "content/child/plugin_messages.h"
 #include "third_party/WebKit/public/web/WebBindings.h"
 
+#if defined(ENABLE_PLUGINS)
+#include "content/child/npapi/plugin_instance.h"
+#endif
+
 using WebKit::WebBindings;
 
 namespace content {
@@ -388,9 +390,7 @@
     return false;
 
   *count = static_cast<unsigned int>(value_param.size());
-  *value = static_cast<NPIdentifier *>(
-      PluginHost::Singleton()->host_functions()->memalloc(
-          sizeof(NPIdentifier) * *count));
+  *value = static_cast<NPIdentifier *>(malloc(sizeof(NPIdentifier) * *count));
   for (unsigned int i = 0; i < *count; ++i)
     (*value)[i] = CreateNPIdentifier(value_param[i]);
 
@@ -468,12 +468,14 @@
   int render_view_id = proxy->render_view_id_;
   bool popups_allowed = false;
 
+#if defined(ENABLE_PLUGINS)
   if (npp) {
     PluginInstance* plugin_instance =
         reinterpret_cast<PluginInstance*>(npp->ndata);
     if (plugin_instance)
       popups_allowed = plugin_instance->popups_allowed();
   }
+#endif
 
   NPVariant_Param result_param;
   std::string script_str = std::string(
diff --git a/content/child/npapi/npobject_stub.cc b/content/child/npapi/npobject_stub.cc
index 739c0b5..b58ecca 100644
--- a/content/child/npapi/npobject_stub.cc
+++ b/content/child/npapi/npobject_stub.cc
@@ -6,7 +6,6 @@
 
 #include "content/child/npapi/np_channel_base.h"
 #include "content/child/npapi/npobject_util.h"
-#include "content/child/npapi/plugin_host.h"
 #include "content/child/plugin_messages.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -339,7 +338,7 @@
     value->push_back(param);
   }
 
-  PluginHost::Singleton()->host_functions()->memfree(value_np);
+  free(value_np);
 }
 
 void NPObjectStub::OnConstruct(const std::vector<NPVariant_Param>& args,
diff --git a/content/child/plugin_param_traits.cc b/content/child/plugin_param_traits.cc
index 255369a..b444c17 100644
--- a/content/child/plugin_param_traits.cc
+++ b/content/child/plugin_param_traits.cc
@@ -5,7 +5,6 @@
 #include "content/child/plugin_param_traits.h"
 
 #include "base/strings/string_number_conversions.h"
-#include "content/child/npapi/plugin_host.h"
 #include "ipc/ipc_message_utils.h"
 #include "third_party/WebKit/public/web/WebBindings.h"
 
@@ -127,7 +126,7 @@
   if (WebKit::WebBindings::identifierIsString(p.identifier)) {
     NPUTF8* str = WebKit::WebBindings::utf8FromIdentifier(p.identifier);
     l->append(str);
-    content::PluginHost::Singleton()->host_functions()->memfree(str);
+    free(str);
   } else {
     l->append(base::IntToString(
         WebKit::WebBindings::intFromIdentifier(p.identifier)));
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index 1c3b85b..5f2e12a 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -16,7 +16,7 @@
 #include "content/common/device_orientation/device_motion_messages.h"
 #include "content/common/device_orientation/device_orientation_messages.h"
 #include "content/common/devtools_messages.h"
-#include "content/common/dom_storage_messages.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
 #include "content/common/drag_messages.h"
 #include "content/common/drag_traits.h"
 #include "content/common/file_utilities_messages.h"
@@ -30,7 +30,6 @@
 #include "content/common/input_messages.h"
 #include "content/common/java_bridge_messages.h"
 #include "content/common/media/audio_messages.h"
-#include "content/common/media/encoded_video_capture_messages.h"
 #include "content/common/media/midi_messages.h"
 #if defined(OS_ANDROID)
 #include "content/common/media/media_player_messages_android.h"
diff --git a/content/common/dom_storage/OWNERS b/content/common/dom_storage/OWNERS
new file mode 100644
index 0000000..66ceac5
--- /dev/null
+++ b/content/common/dom_storage/OWNERS
@@ -0,0 +1,2 @@
+marja@chromium.org
+michaeln@chromium.org
diff --git a/webkit/common/dom_storage/dom_storage_map.cc b/content/common/dom_storage/dom_storage_map.cc
similarity index 70%
rename from webkit/common/dom_storage/dom_storage_map.cc
rename to content/common/dom_storage/dom_storage_map.cc
index 5cc3c5e..4fe2c3c 100644
--- a/webkit/common/dom_storage/dom_storage_map.cc
+++ b/content/common/dom_storage/dom_storage_map.cc
@@ -1,23 +1,25 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "webkit/common/dom_storage/dom_storage_map.h"
+#include "content/common/dom_storage/dom_storage_map.h"
 
 #include "base/logging.h"
 
+namespace content {
+
 namespace {
 
 size_t size_of_item(const base::string16& key, const base::string16& value) {
   return (key.length() + value.length()) * sizeof(char16);
 }
 
-size_t CountBytes(const dom_storage::ValuesMap& values) {
+size_t CountBytes(const DOMStorageValuesMap& values) {
   if (values.size() == 0)
     return 0;
 
   size_t count = 0;
-  dom_storage::ValuesMap::const_iterator it = values.begin();
+  DOMStorageValuesMap::const_iterator it = values.begin();
   for (; it != values.end(); ++it)
     count += size_of_item(it->first, it->second.string());
   return count;
@@ -25,21 +27,19 @@
 
 }  // namespace
 
-namespace dom_storage {
-
-DomStorageMap::DomStorageMap(size_t quota)
+DOMStorageMap::DOMStorageMap(size_t quota)
     : bytes_used_(0),
       quota_(quota) {
   ResetKeyIterator();
 }
 
-DomStorageMap::~DomStorageMap() {}
+DOMStorageMap::~DOMStorageMap() {}
 
-unsigned DomStorageMap::Length() const {
+unsigned DOMStorageMap::Length() const {
   return values_.size();
 }
 
-base::NullableString16 DomStorageMap::Key(unsigned index) {
+base::NullableString16 DOMStorageMap::Key(unsigned index) {
   if (index >= values_.size())
     return base::NullableString16();
   while (last_key_index_ != index) {
@@ -54,17 +54,17 @@
   return base::NullableString16(key_iterator_->first, false);
 }
 
-base::NullableString16 DomStorageMap::GetItem(const base::string16& key) const {
-  ValuesMap::const_iterator found = values_.find(key);
+base::NullableString16 DOMStorageMap::GetItem(const base::string16& key) const {
+  DOMStorageValuesMap::const_iterator found = values_.find(key);
   if (found == values_.end())
     return base::NullableString16();
   return found->second;
 }
 
-bool DomStorageMap::SetItem(
+bool DOMStorageMap::SetItem(
     const base::string16& key, const base::string16& value,
     base::NullableString16* old_value) {
-  ValuesMap::const_iterator found = values_.find(key);
+  DOMStorageValuesMap::const_iterator found = values_.find(key);
   if (found == values_.end())
     *old_value = base::NullableString16();
   else
@@ -86,10 +86,10 @@
   return true;
 }
 
-bool DomStorageMap::RemoveItem(
+bool DOMStorageMap::RemoveItem(
     const base::string16& key,
     base::string16* old_value) {
-  ValuesMap::iterator found = values_.find(key);
+  DOMStorageValuesMap::iterator found = values_.find(key);
   if (found == values_.end())
     return false;
   *old_value = found->second.string();
@@ -99,24 +99,24 @@
   return true;
 }
 
-void DomStorageMap::SwapValues(ValuesMap* values) {
+void DOMStorageMap::SwapValues(DOMStorageValuesMap* values) {
   // Note: A pre-existing file may be over the quota budget.
   values_.swap(*values);
   bytes_used_ = CountBytes(values_);
   ResetKeyIterator();
 }
 
-DomStorageMap* DomStorageMap::DeepCopy() const {
-  DomStorageMap* copy = new DomStorageMap(quota_);
+DOMStorageMap* DOMStorageMap::DeepCopy() const {
+  DOMStorageMap* copy = new DOMStorageMap(quota_);
   copy->values_ = values_;
   copy->bytes_used_ = bytes_used_;
   copy->ResetKeyIterator();
   return copy;
 }
 
-void DomStorageMap::ResetKeyIterator() {
+void DOMStorageMap::ResetKeyIterator() {
   key_iterator_ = values_.begin();
   last_key_index_ = 0;
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/common/dom_storage/dom_storage_map.h b/content/common/dom_storage/dom_storage_map.h
new file mode 100644
index 0000000..140de07
--- /dev/null
+++ b/content/common/dom_storage/dom_storage_map.h
@@ -0,0 +1,64 @@
+// 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 CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
+#define CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/strings/nullable_string16.h"
+#include "base/strings/string16.h"
+#include "content/common/content_export.h"
+#include "content/common/dom_storage/dom_storage_types.h"
+
+namespace content {
+
+// A wrapper around a std::map that adds refcounting and
+// tracks the size in bytes of the keys/values, enforcing a quota.
+// See class comments for DOMStorageContextImpl for a larger overview.
+class CONTENT_EXPORT DOMStorageMap
+    : public base::RefCountedThreadSafe<DOMStorageMap> {
+ public:
+  explicit DOMStorageMap(size_t quota);
+
+  unsigned Length() const;
+  base::NullableString16 Key(unsigned index);
+  base::NullableString16 GetItem(const base::string16& key) const;
+  bool SetItem(const base::string16& key, const base::string16& value,
+               base::NullableString16* old_value);
+  bool RemoveItem(const base::string16& key, base::string16* old_value);
+
+  // Swaps this instances values_ with |map|.
+  // Note: to grandfather in pre-existing files that are overbudget,
+  // this method does not do quota checking.
+  void SwapValues(DOMStorageValuesMap* map);
+
+  // Writes a copy of the current set of values_ to the |map|.
+  void ExtractValues(DOMStorageValuesMap* map) const { *map = values_; }
+
+  // Creates a new instance of DOMStorageMap containing
+  // a deep copy of values_.
+  DOMStorageMap* DeepCopy() const;
+
+  size_t bytes_used() const { return bytes_used_; }
+  size_t quota() const { return quota_; }
+  void set_quota(size_t quota) { quota_ = quota; }
+
+ private:
+  friend class base::RefCountedThreadSafe<DOMStorageMap>;
+  ~DOMStorageMap();
+
+  void ResetKeyIterator();
+
+  DOMStorageValuesMap values_;
+  DOMStorageValuesMap::const_iterator key_iterator_;
+  unsigned last_key_index_;
+  size_t bytes_used_;
+  size_t quota_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
diff --git a/webkit/common/dom_storage/dom_storage_map_unittest.cc b/content/common/dom_storage/dom_storage_map_unittest.cc
similarity index 89%
rename from webkit/common/dom_storage/dom_storage_map_unittest.cc
rename to content/common/dom_storage/dom_storage_map_unittest.cc
index d634bce..0937c21 100644
--- a/webkit/common/dom_storage/dom_storage_map_unittest.cc
+++ b/content/common/dom_storage/dom_storage_map_unittest.cc
@@ -1,14 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 "base/strings/utf_string_conversions.h"
+#include "content/common/dom_storage/dom_storage_map.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "webkit/common/dom_storage/dom_storage_map.h"
 
-namespace dom_storage {
+namespace content {
 
-TEST(DomStorageMapTest, DomStorageMapBasics) {
+TEST(DOMStorageMapTest, DOMStorageMapBasics) {
   const base::string16 kKey(ASCIIToUTF16("key"));
   const base::string16 kValue(ASCIIToUTF16("value"));
   const size_t kValueBytes = kValue.size() * sizeof(char16);
@@ -21,11 +21,11 @@
       (kKey2.size() + kValue2.size()) * sizeof(char16);
   const size_t kQuota = 1024;  // 1K quota for this test.
 
-  scoped_refptr<DomStorageMap> map(new DomStorageMap(kQuota));
+  scoped_refptr<DOMStorageMap> map(new DOMStorageMap(kQuota));
   base::string16 old_value;
   base::NullableString16 old_nullable_value;
-  ValuesMap swap;
-  scoped_refptr<DomStorageMap> copy;
+  DOMStorageValuesMap swap;
+  scoped_refptr<DOMStorageMap> copy;
 
   // Check the behavior of an empty map.
   EXPECT_EQ(0u, map->Length());
@@ -82,19 +82,19 @@
   EXPECT_EQ(0u, map->bytes_used());
 }
 
-TEST(DomStorageMapTest, EnforcesQuota) {
+TEST(DOMStorageMapTest, EnforcesQuota) {
   const base::string16 kKey = ASCIIToUTF16("test_key");
   const base::string16 kValue = ASCIIToUTF16("test_value");
   const base::string16 kKey2 = ASCIIToUTF16("test_key_2");
 
   // A 50 byte quota is too small to hold both keys, so we
-  // should see the DomStorageMap enforcing it.
+  // should see the DOMStorageMap enforcing it.
   const size_t kQuota = 50;
 
   base::string16 old_value;
   base::NullableString16 old_nullable_value;
 
-  scoped_refptr<DomStorageMap> map(new DomStorageMap(kQuota));
+  scoped_refptr<DOMStorageMap> map(new DOMStorageMap(kQuota));
   EXPECT_TRUE(map->SetItem(kKey, kValue, &old_nullable_value));
   EXPECT_FALSE(map->SetItem(kKey2, kValue, &old_nullable_value));
   EXPECT_EQ(1u, map->Length());
@@ -106,7 +106,7 @@
   EXPECT_EQ(1u, map->Length());
 
   // Verify that the SwapValues method does not do quota checking.
-  ValuesMap swap;
+  DOMStorageValuesMap swap;
   swap[kKey] = base::NullableString16(kValue, false);
   swap[kKey2] = base::NullableString16(kValue, false);
   map->SwapValues(&swap);
@@ -121,4 +121,4 @@
   EXPECT_EQ(kValue, old_nullable_value.string());
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/common/dom_storage_messages.h b/content/common/dom_storage/dom_storage_messages.h
similarity index 95%
rename from content/common/dom_storage_messages.h
rename to content/common/dom_storage/dom_storage_messages.h
index da847ec..11c05e8 100644
--- a/content/common/dom_storage_messages.h
+++ b/content/common/dom_storage/dom_storage_messages.h
@@ -1,14 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
 
 // Multiply-included message file, no traditional include guard.
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/public/common/common_param_traits.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_param_traits.h"
 #include "third_party/WebKit/public/platform/WebStorageArea.h"
 #include "url/gurl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 #define IPC_MESSAGE_START DOMStorageMsgStart
 
@@ -69,7 +69,7 @@
 // the renderer-side cache. A completion notification is sent in response.
 IPC_SYNC_MESSAGE_CONTROL1_1(DOMStorageHostMsg_LoadStorageArea,
                             int /* connection_id */,
-                            dom_storage::ValuesMap)
+                            content::DOMStorageValuesMap)
 
 // Set a value that's associated with a key in a storage area.
 // A completion notification is sent in response.
diff --git a/content/common/dom_storage/dom_storage_types.h b/content/common/dom_storage/dom_storage_types.h
new file mode 100644
index 0000000..1b25b41
--- /dev/null
+++ b/content/common/dom_storage/dom_storage_types.h
@@ -0,0 +1,41 @@
+// 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 CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
+#define CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/strings/nullable_string16.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+namespace content {
+
+typedef std::map<base::string16, base::NullableString16> DOMStorageValuesMap;
+
+// The quota for each storage area.
+// This value is enforced in renderer processes and the browser process.
+const size_t kPerStorageAreaQuota = 10 * 1024 * 1024;
+
+// In the browser process we allow some overage to
+// accomodate concurrent writes from different renderers
+// that were allowed because the limit imposed in the renderer
+// wasn't exceeded.
+const size_t kPerStorageAreaOverQuotaAllowance = 100 * 1024;
+
+// Value to indicate the localstorage namespace vs non-zero
+// values for sessionstorage namespaces.
+const int64 kLocalStorageNamespaceId = 0;
+
+const int64 kInvalidSessionStorageNamespaceId = kLocalStorageNamespaceId;
+
+// Start purging memory if the number of in-memory areas exceeds this.
+const int64 kMaxInMemoryStorageAreas = 100;
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
diff --git a/content/common/gpu/media/video_decode_accelerator_unittest.cc b/content/common/gpu/media/video_decode_accelerator_unittest.cc
index c81cef2..a180ff6 100644
--- a/content/common/gpu/media/video_decode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_decode_accelerator_unittest.cc
@@ -1254,11 +1254,16 @@
     ::testing::Values(
         MakeTuple(1, 1, 1, 4, END_OF_STREAM_RESET, CS_RESET, false, false)));
 
+// This hangs on Exynos, preventing further testing and wasting test machine
+// time.
+// TODO(ihf): Enable again once http://crbug.com/269754 is fixed.
+#if defined(ARCH_CPU_X86_FAMILY)
 // Test that Reset() before the first Decode() works fine.
 INSTANTIATE_TEST_CASE_P(
     ResetBeforeDecode, VideoDecodeAcceleratorTest,
     ::testing::Values(
         MakeTuple(1, 1, 1, 1, START_OF_STREAM_RESET, CS_RESET, false, false)));
+#endif  // ARCH_CPU_X86_FAMILY
 
 // Test that Reset() mid-stream works fine and doesn't affect decoding even when
 // Decode() calls are made during the reset.
diff --git a/content/common/media/encoded_video_capture_messages.h b/content/common/media/encoded_video_capture_messages.h
deleted file mode 100644
index 6313f72..0000000
--- a/content/common/media/encoded_video_capture_messages.h
+++ /dev/null
@@ -1,135 +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 "base/memory/shared_memory.h"
-#include "ipc/ipc_message_macros.h"
-#include "media/video/capture/video_capture_types.h"
-#include "media/video/video_encode_types.h"
-
-#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT CONTENT_EXPORT
-#define IPC_MESSAGE_START EncodedVideoCaptureMsgStart
-
-#if !defined(OS_ANDROID)
-IPC_ENUM_TRAITS(media::VideoCodec)
-#endif  // !defined(OS_ANDROID)
-
-IPC_STRUCT_TRAITS_BEGIN(media::VideoEncodingConfig)
-  IPC_STRUCT_TRAITS_MEMBER(codec_type)
-  IPC_STRUCT_TRAITS_MEMBER(codec_name)
-  IPC_STRUCT_TRAITS_MEMBER(max_resolution)
-  IPC_STRUCT_TRAITS_MEMBER(max_frames_per_second)
-  IPC_STRUCT_TRAITS_MEMBER(max_bitrate)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(media::RuntimeVideoEncodingParameters)
-  IPC_STRUCT_TRAITS_MEMBER(target_bitrate)
-  IPC_STRUCT_TRAITS_MEMBER(max_bitrate)
-  IPC_STRUCT_TRAITS_MEMBER(frames_per_second)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(media::VideoEncodingParameters)
-  IPC_STRUCT_TRAITS_MEMBER(codec_name)
-  IPC_STRUCT_TRAITS_MEMBER(resolution)
-  IPC_STRUCT_TRAITS_MEMBER(runtime_params)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(media::BufferEncodingMetadata)
-  IPC_STRUCT_TRAITS_MEMBER(timestamp)
-  IPC_STRUCT_TRAITS_MEMBER(key_frame)
-IPC_STRUCT_TRAITS_END()
-
-//------------------------------------------------------------------------------
-// Renderer Source Messages
-// These are messages from the renderer to the browser process.
-
-// Queries the encoding capabilities for the device. A successful request
-// results in EncoderVideoSourceMessage_CapabilitiesAvailable message.
-IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_GetCapabilities,
-                     int /* device_id */,
-                     media::VideoCaptureSessionId /* session_id */)
-
-// Message from renderer to browser process to create a bitstream with specific
-// parameters. A successful request results in beginning of streaming and
-// EncoderVideoCaptureMsg_BitstreamCreated message to renderer. A failed request
-// triggers EncodedVideoCaptureMsg_BitstreamDestroyed message. |session_id| is
-// the capture session id returned by the MediaStreamManager. The renderer is
-// responsible for generating unique |device_id| within its context that will be
-// used to identify bitstreams in IPC.
-IPC_MESSAGE_CONTROL3(EncodedVideoCaptureHostMsg_OpenBitstream,
-                     int /* device_id */,
-                     media::VideoCaptureSessionId /* session_id */,
-                     media::VideoEncodingParameters /* params */)
-
-// Stops streaming a bitstream. When browser has finalized the bitstream it will
-// trigger EncodedVideoCaptureMsg_BitstreamClosed message back to renderer.
-// Renderer must be prepared to receive EncodedVideoCaptureMsg_BitstreamReady
-// messages until it receives EncodedVideoCaptureMsg_BitstreamClosed message.
-IPC_MESSAGE_CONTROL1(EncodedVideoCaptureHostMsg_CloseBitstream,
-                    int /* device_id */)
-
-// Sets a stream's bitstream configuration. Will always result in
-// EncodedVideoCaptureMsg_BitstreamConfigChanged message containing
-// currently active parameters, regardless of whether this call succeeded or
-// not.
-IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_TryConfigureBitstream,
-                     int /* device_id */,
-                     media::RuntimeVideoEncodingParameters /* params */)
-
-// Requests a key frame in the encoded bitstream. Upon receiving this request,
-// browser will try to encode an upcoming captured frame as a key frame. This
-// allows the receiver to quickly recover from data loss. The request is served
-// on a best-effort basis and there is no explicit acknowledgement.
-IPC_MESSAGE_CONTROL1(EncodedVideoCaptureHostMsg_RequestKeyFrame,
-                     int /* device_id */)
-
-// Notifies that the data within a buffer has been processed and it can be
-// reused to encode upcoming bitstream.
-IPC_MESSAGE_CONTROL2(EncodedVideoCaptureHostMsg_BitstreamBufferConsumed,
-                     int /* device_id */,
-                     int /* buffer_id */)
-
-//------------------------------------------------------------------------------
-// Renderer Messages
-// These are messages from the browser to the renderer process.
-
-// Reports the encoding capabilities of the device.
-IPC_MESSAGE_CONTROL2(EncodedVideoCaptureMsg_CapabilitiesAvailable,
-                     int /* device_id */,
-                     media::VideoEncodingCapabilities /* capabilities */)
-
-// Acknowledges a request to open an encoded video bitstream. When this message
-// occurs, bitstream can be considered to be streaming, and renderer should be
-// ready to start accepting EncodedVideoCaptureMsg_BitstreamReady messages and
-// buffers contained within them. Shared memory buffers used to deliver the
-// bitstream are assigned with buffer IDs as specified by the buffers parameter.
-// All buffers have the same size as indicated by |buffer_size|.
-IPC_MESSAGE_CONTROL4(EncodedVideoCaptureMsg_BitstreamOpened,
-                     int /* device_id */,
-                     media::VideoEncodingParameters /* params */,
-                     std::vector<base::SharedMemoryHandle> /* buffers */,
-                     uint32 /* buffer_size */)
-
-// Acknowledges a request to close an encoded video bitstream.
-IPC_MESSAGE_CONTROL1(EncodedVideoCaptureMsg_BitstreamClosed,
-                     int /* device_id */)
-
-// Informs the clients of the current encoding parameters, regardless of whether
-// the previous request to change them has been successful or not. It is usually
-// called in response to EncodedVideoCaptureHostMsg_TryConfigureBitstream
-// at runtime, but can occur also as a result of config change initiated by
-// encoder or other clients in the system, e.g. if there are multiple clients
-// and bitstream config change is requested from one client, all clients should
-// be prepared to handle the configuration change.
-IPC_MESSAGE_CONTROL2(EncodedVideoCaptureMsg_BitstreamConfigChanged,
-                     int /* device_id */,
-                     media::RuntimeVideoEncodingParameters /* current_params */)
-
-// Indicates that a bitstream buffer is available for the stream. The value of
-// |size| indicates the amount of valid bitstream data (in bytes).
-IPC_MESSAGE_CONTROL4(EncodedVideoCaptureMsg_BitstreamReady,
-                     int /* device_id */,
-                     int /* buffer_id */,
-                     uint32 /* size */,
-                     media::BufferEncodingMetadata /* metadata */)
diff --git a/content/common/sandbox_linux.cc b/content/common/sandbox_linux.cc
index de7f7e4..1746390 100644
--- a/content/common/sandbox_linux.cc
+++ b/content/common/sandbox_linux.cc
@@ -138,7 +138,7 @@
     // The GPU process is allowed to call InitializeSandbox() with threads for
     // now, because it loads third party libraries.
     if (process_type != switches::kGpuProcess)
-      DCHECK(false) << error_message;
+      CHECK(false) << error_message;
     LOG(ERROR) << error_message;
     return false;
   }
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index 7bd409f..9ab0e99 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -2016,10 +2016,6 @@
                     int32, /* line number */
                     string16 /* source id */)
 
-// Sent to the renderer process to indicate completion of the previous
-// ViewHostMsg_AddMessageToConsole operation.
-IPC_MESSAGE_ROUTED0(ViewMsg_AddMessageToConsole_ACK)
-
 // Sent by the renderer process to indicate that a plugin instance has crashed.
 // Note: |plugin_pid| should not be trusted. The corresponding process has
 // probably died. Moreover, the ID may have been reused by a new process. Any
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 1124248..b3751ac 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -3,9 +3,6 @@
 # found in the LICENSE file.
 
 {
-  'variables': {
-    'use_cras%': 0,
-  },
   'dependencies': [
     'browser/speech/proto/speech_proto.gyp:speech_proto',
     '../base/base.gyp:base_static',
@@ -116,6 +113,8 @@
     'public/browser/load_from_memory_cache_details.cc',
     'public/browser/load_from_memory_cache_details.h',
     'public/browser/load_notification_details.h',
+    'public/browser/local_storage_usage_info.cc',
+    'public/browser/local_storage_usage_info.h',
     'public/browser/media_devices_monitor.h',
     'public/browser/native_web_keyboard_event.h',
     'public/browser/navigation_controller.cc',
@@ -136,8 +135,8 @@
     'public/browser/page_navigator.h',
     'public/browser/pepper_flash_settings_helper.h',
     'public/browser/plugin_data_remover.h',
-    'public/browser/plugin_service_filter.h',
     'public/browser/plugin_service.h',
+    'public/browser/plugin_service_filter.h',
     'public/browser/power_save_blocker.h',
     'public/browser/profiler_controller.h',
     'public/browser/profiler_subscriber.h',
@@ -163,6 +162,7 @@
     'public/browser/resource_throttle.h',
     'public/browser/save_page_type.h',
     'public/browser/session_storage_namespace.h',
+    'public/browser/session_storage_usage_info.h',
     'public/browser/site_instance.h',
     'public/browser/speech_recognition_event_listener.h',
     'public/browser/speech_recognition_manager.h',
@@ -305,6 +305,8 @@
     'browser/aura/no_transport_image_transport_factory.h',
     'browser/aura/reflector_impl.cc',
     'browser/aura/reflector_impl.h',
+    'browser/aura/software_browser_compositor_output_surface.cc',
+    'browser/aura/software_browser_compositor_output_surface.h',
     'browser/aura/software_output_device_win.cc',
     'browser/aura/software_output_device_win.h',
     'browser/aura/software_output_device_x11.cc',
@@ -420,10 +422,31 @@
     'browser/device_orientation/provider.h',
     'browser/device_orientation/provider_impl.cc',
     'browser/device_orientation/provider_impl.h',
+    'browser/dom_storage/dom_storage_area.cc',
+    'browser/dom_storage/dom_storage_area.h',
     'browser/dom_storage/dom_storage_context_impl.cc',
     'browser/dom_storage/dom_storage_context_impl.h',
+    'browser/dom_storage/dom_storage_context_wrapper.cc',
+    'browser/dom_storage/dom_storage_context_wrapper.h',
+    'browser/dom_storage/dom_storage_database.cc',
+    'browser/dom_storage/dom_storage_database.h',
+    'browser/dom_storage/dom_storage_database_adapter.h',
+    'browser/dom_storage/dom_storage_host.cc',
+    'browser/dom_storage/dom_storage_host.h',
     'browser/dom_storage/dom_storage_message_filter.cc',
     'browser/dom_storage/dom_storage_message_filter.h',
+    'browser/dom_storage/dom_storage_namespace.cc',
+    'browser/dom_storage/dom_storage_namespace.h',
+    'browser/dom_storage/dom_storage_session.cc',
+    'browser/dom_storage/dom_storage_session.h',
+    'browser/dom_storage/dom_storage_task_runner.cc',
+    'browser/dom_storage/dom_storage_task_runner.h',
+    'browser/dom_storage/local_storage_database_adapter.cc',
+    'browser/dom_storage/local_storage_database_adapter.h',
+    'browser/dom_storage/session_storage_database.cc',
+    'browser/dom_storage/session_storage_database.h',
+    'browser/dom_storage/session_storage_database_adapter.cc',
+    'browser/dom_storage/session_storage_database_adapter.h',
     'browser/dom_storage/session_storage_namespace_impl.cc',
     'browser/dom_storage/session_storage_namespace_impl.h',
     'browser/download/base_file.cc',
@@ -1347,11 +1370,6 @@
         '../build/linux/system.gyp:x11',
       ],
     }],
-    ['use_cras==1', {
-      'defines': [
-        'USE_CRAS',
-      ],
-    }],
     ['use_pango==1', {
       'dependencies': [
         '../build/linux/system.gyp:pangocairo',
diff --git a/content/content_browser.target.darwin-arm.mk b/content/content_browser.target.darwin-arm.mk
index 5cf9dfc..1b6db5c 100644
--- a/content/content_browser.target.darwin-arm.mk
+++ b/content/content_browser.target.darwin-arm.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_browser.target.darwin-mips.mk b/content/content_browser.target.darwin-mips.mk
index 44d0f5b..ee0dac8 100644
--- a/content/content_browser.target.darwin-mips.mk
+++ b/content/content_browser.target.darwin-mips.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_browser.target.darwin-x86.mk b/content/content_browser.target.darwin-x86.mk
index f0508e2..bac157c 100644
--- a/content/content_browser.target.darwin-x86.mk
+++ b/content/content_browser.target.darwin-x86.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_browser.target.linux-arm.mk b/content/content_browser.target.linux-arm.mk
index 5cf9dfc..1b6db5c 100644
--- a/content/content_browser.target.linux-arm.mk
+++ b/content/content_browser.target.linux-arm.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_browser.target.linux-mips.mk b/content/content_browser.target.linux-mips.mk
index 44d0f5b..ee0dac8 100644
--- a/content/content_browser.target.linux-mips.mk
+++ b/content/content_browser.target.linux-mips.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_browser.target.linux-x86.mk b/content/content_browser.target.linux-x86.mk
index f0508e2..bac157c 100644
--- a/content/content_browser.target.linux-x86.mk
+++ b/content/content_browser.target.linux-x86.mk
@@ -57,6 +57,7 @@
 	content/public/browser/indexed_db_info.cc \
 	content/public/browser/javascript_dialog_manager.cc \
 	content/public/browser/load_from_memory_cache_details.cc \
+	content/public/browser/local_storage_usage_info.cc \
 	content/public/browser/navigation_controller.cc \
 	content/public/browser/navigation_details.cc \
 	content/public/browser/notification_registrar.cc \
@@ -159,8 +160,18 @@
 	content/browser/device_orientation/orientation_message_filter.cc \
 	content/browser/device_orientation/provider.cc \
 	content/browser/device_orientation/provider_impl.cc \
+	content/browser/dom_storage/dom_storage_area.cc \
 	content/browser/dom_storage/dom_storage_context_impl.cc \
+	content/browser/dom_storage/dom_storage_context_wrapper.cc \
+	content/browser/dom_storage/dom_storage_database.cc \
+	content/browser/dom_storage/dom_storage_host.cc \
 	content/browser/dom_storage/dom_storage_message_filter.cc \
+	content/browser/dom_storage/dom_storage_namespace.cc \
+	content/browser/dom_storage/dom_storage_session.cc \
+	content/browser/dom_storage/dom_storage_task_runner.cc \
+	content/browser/dom_storage/local_storage_database_adapter.cc \
+	content/browser/dom_storage/session_storage_database.cc \
+	content/browser/dom_storage/session_storage_database_adapter.cc \
 	content/browser/dom_storage/session_storage_namespace_impl.cc \
 	content/browser/download/base_file.cc \
 	content/browser/download/base_file_posix.cc \
diff --git a/content/content_child.gypi b/content/content_child.gypi
index 109ae20..b0c18ed 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -23,6 +23,8 @@
     'child/appcache_backend_proxy.h',
     'child/appcache_dispatcher.cc',
     'child/appcache_dispatcher.h',
+    'child/browser_font_resource_trusted.cc',
+    'child/browser_font_resource_trusted.h',
     'child/child_histogram_message_filter.cc',
     'child/child_histogram_message_filter.h',
     'child/child_process.cc',
@@ -135,10 +137,13 @@
         '../build/android/cpufeatures.gypi',
       ],
     }],
-    ['enable_plugins==1', {
-      'sources': [
+    ['enable_plugins==0', {
+      'sources!': [
         'child/browser_font_resource_trusted.cc',
-        'child/browser_font_resource_trusted.h',
+      ],
+      'sources/': [
+        ['exclude', '^child/npapi/plugin_'],
+        ['exclude', '^child/npapi/webplugin_'],
       ],
     }],
     ['OS=="ios"', {
diff --git a/content/content_child.target.darwin-arm.mk b/content/content_child.target.darwin-arm.mk
index 540ce0c..264be10 100644
--- a/content/content_child.target.darwin-arm.mk
+++ b/content/content_child.target.darwin-arm.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_child.target.darwin-mips.mk b/content/content_child.target.darwin-mips.mk
index 88dbb58..aea02dd 100644
--- a/content/content_child.target.darwin-mips.mk
+++ b/content/content_child.target.darwin-mips.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_child.target.darwin-x86.mk b/content/content_child.target.darwin-x86.mk
index eea5017..affffa7 100644
--- a/content/content_child.target.darwin-x86.mk
+++ b/content/content_child.target.darwin-x86.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_child.target.linux-arm.mk b/content/content_child.target.linux-arm.mk
index 540ce0c..264be10 100644
--- a/content/content_child.target.linux-arm.mk
+++ b/content/content_child.target.linux-arm.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_child.target.linux-mips.mk b/content/content_child.target.linux-mips.mk
index 88dbb58..aea02dd 100644
--- a/content/content_child.target.linux-mips.mk
+++ b/content/content_child.target.linux-mips.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_child.target.linux-x86.mk b/content/content_child.target.linux-x86.mk
index eea5017..affffa7 100644
--- a/content/content_child.target.linux-x86.mk
+++ b/content/content_child.target.linux-x86.mk
@@ -55,15 +55,6 @@
 	content/child/npapi/npobject_stub.cc \
 	content/child/npapi/npobject_util.cc \
 	content/child/npapi/npruntime_util.cc \
-	content/child/npapi/plugin_host.cc \
-	content/child/npapi/plugin_instance.cc \
-	content/child/npapi/plugin_lib.cc \
-	content/child/npapi/plugin_stream.cc \
-	content/child/npapi/plugin_stream_posix.cc \
-	content/child/npapi/plugin_stream_url.cc \
-	content/child/npapi/plugin_string_stream.cc \
-	content/child/npapi/webplugin_delegate_impl.cc \
-	content/child/npapi/webplugin_delegate_impl_android.cc \
 	content/child/plugin_message_generator.cc \
 	content/child/plugin_param_traits.cc \
 	content/child/power_monitor_broadcast_source.cc \
diff --git a/content/content_common.gypi b/content/content_common.gypi
index b89fb5e..42a345b 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -157,7 +157,9 @@
     'common/device_orientation/device_orientation_hardware_buffer.h',
     'common/device_orientation/device_orientation_messages.h',
     'common/devtools_messages.h',
-    'common/dom_storage_messages.h',
+    'common/dom_storage/dom_storage_map.cc',
+    'common/dom_storage/dom_storage_map.h',
+    'common/dom_storage/dom_storage_messages.h',
     'common/drag_event_source_info.h',
     'common/drag_messages.h',
     'common/drag_traits.h',
@@ -259,7 +261,6 @@
     'common/mac/font_loader.h',
     'common/mac/font_loader.mm',
     'common/media/audio_messages.h',
-    'common/media/encoded_video_capture_messages.h',
     'common/media/media_param_traits.cc',
     'common/media/media_param_traits.h',
     'common/media/media_player_messages_android.h',
diff --git a/content/content_common.target.darwin-arm.mk b/content/content_common.target.darwin-arm.mk
index a957abb..d1a213b 100644
--- a/content/content_common.target.darwin-arm.mk
+++ b/content/content_common.target.darwin-arm.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_common.target.darwin-mips.mk b/content/content_common.target.darwin-mips.mk
index 18c3033..ba84ef0 100644
--- a/content/content_common.target.darwin-mips.mk
+++ b/content/content_common.target.darwin-mips.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_common.target.darwin-x86.mk b/content/content_common.target.darwin-x86.mk
index 60ed34b..9d0a842 100644
--- a/content/content_common.target.darwin-x86.mk
+++ b/content/content_common.target.darwin-x86.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_common.target.linux-arm.mk b/content/content_common.target.linux-arm.mk
index a957abb..d1a213b 100644
--- a/content/content_common.target.linux-arm.mk
+++ b/content/content_common.target.linux-arm.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_common.target.linux-mips.mk b/content/content_common.target.linux-mips.mk
index 18c3033..ba84ef0 100644
--- a/content/content_common.target.linux-mips.mk
+++ b/content/content_common.target.linux-mips.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_common.target.linux-x86.mk b/content/content_common.target.linux-x86.mk
index 60ed34b..9d0a842 100644
--- a/content/content_common.target.linux-x86.mk
+++ b/content/content_common.target.linux-x86.mk
@@ -76,6 +76,7 @@
 	content/common/content_param_traits.cc \
 	content/common/content_paths.cc \
 	content/common/cookie_data.cc \
+	content/common/dom_storage/dom_storage_map.cc \
 	content/common/find_match_rect_android.cc \
 	content/common/font_list.cc \
 	content/common/font_list_android.cc \
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 53ddc8a..25ad0ea 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -402,8 +402,6 @@
     'renderer/pepper/usb_key_code_conversion_win.cc',
     'renderer/pepper/v8_var_converter.cc',
     'renderer/pepper/v8_var_converter.h',
-    'renderer/plugin_channel_host.cc',
-    'renderer/plugin_channel_host.h',
     'renderer/browser_plugin/browser_plugin.cc',
     'renderer/browser_plugin/browser_plugin.h',
     'renderer/browser_plugin/browser_plugin_backing_store.h',
@@ -431,6 +429,12 @@
     'renderer/fetchers/resource_fetcher.h',
     'renderer/ime_event_guard.cc',
     'renderer/ime_event_guard.h',
+    'renderer/npapi/plugin_channel_host.cc',
+    'renderer/npapi/plugin_channel_host.h',
+    'renderer/npapi/webplugin_delegate_proxy.cc',
+    'renderer/npapi/webplugin_delegate_proxy.h',
+    'renderer/npapi/webplugin_impl.cc',
+    'renderer/npapi/webplugin_impl.h',
     'renderer/render_frame_impl.cc',
     'renderer/render_frame_impl.h',
     'renderer/render_process.h',
@@ -500,10 +504,6 @@
     'renderer/web_ui_extension.h',
     'renderer/web_ui_extension_data.cc',
     'renderer/web_ui_extension_data.h',
-    'renderer/webplugin_delegate_proxy.cc',
-    'renderer/webplugin_delegate_proxy.h',
-    'renderer/webplugin_impl.cc',
-    'renderer/webplugin_impl.h',
     'renderer/websharedworker_proxy.cc',
     'renderer/websharedworker_proxy.h',
     'renderer/websharedworkerrepository_impl.cc',
@@ -599,10 +599,6 @@
         'renderer/media/rtc_data_channel_handler.h',
         'renderer/media/rtc_dtmf_sender_handler.cc',
         'renderer/media/rtc_dtmf_sender_handler.h',
-        'renderer/media/rtc_encoding_video_capturer.cc',
-        'renderer/media/rtc_encoding_video_capturer.h',
-        'renderer/media/rtc_encoding_video_capturer_factory.cc',
-        'renderer/media/rtc_encoding_video_capturer_factory.h',
         'renderer/media/rtc_media_constraints.cc',
         'renderer/media/rtc_media_constraints.h',
         'renderer/media/rtc_peer_connection_handler.cc',
@@ -674,6 +670,7 @@
       ],
     }, {  # enable_plugins==0
       'sources/': [
+        ['exclude', '^renderer/npapi/'],
         ['exclude', '^renderer/pepper/'],
       ],
       'sources!': [
diff --git a/content/content_renderer.target.darwin-arm.mk b/content/content_renderer.target.darwin-arm.mk
index 0eca00f..4fb613c 100644
--- a/content/content_renderer.target.darwin-arm.mk
+++ b/content/content_renderer.target.darwin-arm.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.darwin-mips.mk b/content/content_renderer.target.darwin-mips.mk
index be11b4b..5ccec42 100644
--- a/content/content_renderer.target.darwin-mips.mk
+++ b/content/content_renderer.target.darwin-mips.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.darwin-x86.mk b/content/content_renderer.target.darwin-x86.mk
index ab3a363..1db78f3 100644
--- a/content/content_renderer.target.darwin-x86.mk
+++ b/content/content_renderer.target.darwin-x86.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-arm.mk b/content/content_renderer.target.linux-arm.mk
index 0eca00f..4fb613c 100644
--- a/content/content_renderer.target.linux-arm.mk
+++ b/content/content_renderer.target.linux-arm.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-mips.mk b/content/content_renderer.target.linux-mips.mk
index be11b4b..5ccec42 100644
--- a/content/content_renderer.target.linux-mips.mk
+++ b/content/content_renderer.target.linux-mips.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_renderer.target.linux-x86.mk b/content/content_renderer.target.linux-x86.mk
index ab3a363..1db78f3 100644
--- a/content/content_renderer.target.linux-x86.mk
+++ b/content/content_renderer.target.linux-x86.mk
@@ -138,7 +138,6 @@
 	content/renderer/mouse_lock_dispatcher.cc \
 	content/renderer/paint_aggregator.cc \
 	content/renderer/password_form_conversion_utils.cc \
-	content/renderer/plugin_channel_host.cc \
 	content/renderer/browser_plugin/browser_plugin.cc \
 	content/renderer/browser_plugin/browser_plugin_backing_store.cc \
 	content/renderer/browser_plugin/browser_plugin_bindings.cc \
@@ -185,8 +184,6 @@
 	content/renderer/webcrypto_impl.cc \
 	content/renderer/web_ui_extension.cc \
 	content/renderer/web_ui_extension_data.cc \
-	content/renderer/webplugin_delegate_proxy.cc \
-	content/renderer/webplugin_impl.cc \
 	content/renderer/websharedworker_proxy.cc \
 	content/renderer/websharedworkerrepository_impl.cc
 
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index df479b0..bbd785c 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -284,6 +284,10 @@
         'browser/device_orientation/provider_unittest.cc',
         'browser/devtools/devtools_http_handler_unittest.cc',
         'browser/devtools/devtools_manager_unittest.cc',
+        'browser/dom_storage/dom_storage_area_unittest.cc',
+        'browser/dom_storage/dom_storage_context_impl_unittest.cc',
+        'browser/dom_storage/dom_storage_database_unittest.cc',
+        'browser/dom_storage/session_storage_database_unittest.cc',
         'browser/download/base_file_unittest.cc',
         'browser/download/download_file_unittest.cc',
         'browser/download/download_item_impl_unittest.cc',
@@ -396,6 +400,7 @@
         'common/android/address_parser_unittest.cc',
         'common/cc_messages_unittest.cc',
         'common/common_param_traits_unittest.cc',
+        'common/dom_storage/dom_storage_map_unittest.cc',
         'common/gpu/gpu_memory_manager_unittest.cc',
         'common/indexed_db/indexed_db_key_unittest.cc',
         'common/inter_process_time_ticks_converter_unittest.cc',
@@ -435,6 +440,7 @@
         'renderer/media/video_capture_message_filter_unittest.cc',
         'renderer/media/video_destination_handler_unittest.cc',
         'renderer/media/webaudiosourceprovider_impl_unittest.cc',
+        'renderer/npapi/webplugin_impl_unittest.cc',
         'renderer/paint_aggregator_unittest.cc',
         'renderer/pepper/host_var_tracker_unittest.cc',
         'renderer/pepper/mock_resource.h',
@@ -447,9 +453,9 @@
         'renderer/render_view_impl_unittest.cc',
         'renderer/skia_benchmarking_extension_unittest.cc',
         'renderer/v8_value_converter_impl_unittest.cc',
-        'renderer/webplugin_impl_unittest.cc',
         'test/image_decoder_test.cc',
         'test/image_decoder_test.h',
+        'test/run_all_unittests.cc',
         '../webkit/browser/appcache/appcache_database_unittest.cc',
         '../webkit/browser/appcache/appcache_group_unittest.cc',
         '../webkit/browser/appcache/appcache_host_unittest.cc',
@@ -480,10 +486,6 @@
         '../webkit/browser/database/database_tracker_unittest.cc',
         '../webkit/browser/database/database_util_unittest.cc',
         '../webkit/browser/database/databases_table_unittest.cc',
-        '../webkit/browser/dom_storage/dom_storage_area_unittest.cc',
-        '../webkit/browser/dom_storage/dom_storage_context_unittest.cc',
-        '../webkit/browser/dom_storage/dom_storage_database_unittest.cc',
-        '../webkit/browser/dom_storage/session_storage_database_unittest.cc',
         '../webkit/browser/fileapi/async_file_test_helper.cc',
         '../webkit/browser/fileapi/async_file_test_helper.h',
         '../webkit/browser/fileapi/copy_or_move_file_validator_unittest.cc',
@@ -525,7 +527,6 @@
         '../webkit/browser/fileapi/timed_task_helper_unittest.cc',
         '../webkit/browser/fileapi/transient_file_util_unittest.cc',
         '../webkit/browser/fileapi/upload_file_system_file_element_reader_unittest.cc',
-        'test/run_all_unittests.cc',
         '../webkit/child/multipart_response_delegate_unittest.cc',
         '../webkit/child/touch_fling_gesture_curve_unittest.cc',
         '../webkit/child/worker_task_runner_unittest.cc',
@@ -533,7 +534,6 @@
         '../webkit/common/cursors/webcursor_unittest.cc',
         '../webkit/common/database/database_connections_unittest.cc',
         '../webkit/common/database/database_identifier_unittest.cc',
-        '../webkit/common/dom_storage/dom_storage_map_unittest.cc',
         '../webkit/common/fileapi/file_system_util_unittest.cc',
         '../webkit/glue/webkit_glue_unittest.cc',
         '../webkit/mocks/mock_weburlloader.cc',
@@ -599,8 +599,10 @@
         }],
         ['enable_plugins==0', {
           'sources/': [
-            ['exclude', '^renderer/pepper/'],
             ['exclude', '^browser/renderer_host/pepper/'],
+            ['exclude', '^child/npapi/'],
+            ['exclude', '^renderer/npapi/'],
+            ['exclude', '^renderer/pepper/'],
           ],
           'sources!': [
             'browser/plugin_loader_posix_unittest.cc',
@@ -841,12 +843,12 @@
             'browser/webkit_browsertest.cc',
             'browser/worker_host/test/worker_browsertest.cc',
             'renderer/accessibility/renderer_accessibility_browsertest.cc',
-            'renderer/browser_plugin/mock_browser_plugin.h',
-            'renderer/browser_plugin/mock_browser_plugin.cc',
-            'renderer/browser_plugin/mock_browser_plugin_manager.h',
-            'renderer/browser_plugin/mock_browser_plugin_manager.cc',
-            'renderer/browser_plugin/browser_plugin_browsertest.h',
             'renderer/browser_plugin/browser_plugin_browsertest.cc',
+            'renderer/browser_plugin/browser_plugin_browsertest.h',
+            'renderer/browser_plugin/mock_browser_plugin.cc',
+            'renderer/browser_plugin/mock_browser_plugin.h',
+            'renderer/browser_plugin/mock_browser_plugin_manager.cc',
+            'renderer/browser_plugin/mock_browser_plugin_manager.h',
             'renderer/cpp_bound_class_unittest.cc',
             'renderer/dom_serializer_browsertest.cc',
             'renderer/mouse_lock_dispatcher_browsertest.cc',
@@ -871,8 +873,8 @@
             'test/content_browser_test_utils_mac.mm',
             'test/content_browser_test_test.cc',
             'test/content_test_launcher.cc',
-            '../webkit/renderer/cpp_binding_example.cc',
-            '../webkit/renderer/cpp_binding_example.h',
+            'test/cpp_binding_example.cc',
+            'test/cpp_binding_example.h',
           ],
           'conditions': [
             ['chromeos==0', {
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentView.java b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
index dce2cbf..135cb26 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentView.java
@@ -314,10 +314,6 @@
         mContentViewCore.getContentViewGestureHandler().fling(timeMs, x, y, velocityX, velocityY);
     }
 
-    void endFling(long timeMs) {
-        mContentViewCore.getContentViewGestureHandler().endFling(timeMs);
-    }
-
     /**
      * Start pinch zoom. You must call {@link #pinchEnd} to stop.
      */
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
index eb5ef13..053aa9a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
@@ -86,12 +86,12 @@
     // will be mistakenly fired.
     private boolean mIgnoreSingleTap;
 
-    // Does native think we are scrolling?  True from right before we
-    // send the first scroll event until the last finger is raised.
-    // Call nativeScrollBegin() when setting this to true, and use
-    // tellNativeScrollingHasEnded() to set it to false.
-    private boolean mNativeScrolling;
+    // True from right before we send the first scroll event until the last finger is raised.
+    private boolean mTouchScrolling;
 
+    // TODO(wangxianzhu): For now it is true after a fling is started until the next
+    // touch. Should reset it to false on end of fling if the UI is able to know when the
+    // fling ends.
     private boolean mFlingMayBeActive;
 
     private boolean mSeenFirstScrollEvent;
@@ -352,7 +352,7 @@
                     public boolean onDown(MotionEvent e) {
                         mShowPressIsCalled = false;
                         mIgnoreSingleTap = false;
-                        mNativeScrolling = false;
+                        mTouchScrolling = false;
                         mSeenFirstScrollEvent = false;
                         mSnapScrollController.resetSnapScrollMode();
                         mLastRawX = e.getRawX();
@@ -394,11 +394,11 @@
                         mLastRawX = e2.getRawX();
                         mLastRawY = e2.getRawY();
                         if (didUIStealScroll) return true;
-                        if (!mNativeScrolling) {
+                        if (!mTouchScrolling) {
                             sendShowPressCancelIfNecessary(e1);
-                            endFling(e2.getEventTime());
+                            endFlingIfNecessary(e2.getEventTime());
                             if (sendMotionEventAsGesture(GESTURE_SCROLL_START, e1, null)) {
-                                mNativeScrolling = true;
+                                mTouchScrolling = true;
                             }
                         }
                         // distanceX and distanceY is the scrolling offset since last onScroll.
@@ -632,13 +632,13 @@
      * @param velocityY Initial velocity of the fling (Y) measured in pixels per second.
      */
     void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
-        boolean nativeScrolling = mNativeScrolling;
-        endFling(timeMs);
-        if (!nativeScrolling) {
+        endFlingIfNecessary(timeMs);
+        if (!mTouchScrolling) {
             // The native side needs a GESTURE_SCROLL_BEGIN before GESTURE_FLING_START
             // to send the fling to the correct target. Send if it has not sent.
             sendGesture(GESTURE_SCROLL_START, timeMs, x, y, null);
         }
+        endTouchScrollIfNecessary(timeMs, false);
 
         mFlingMayBeActive = true;
 
@@ -649,15 +649,13 @@
     }
 
     /**
-     * Send a FlingCancel gesture event and also cancel scrolling if it is active.
+     * Send a GESTURE_FLING_CANCEL event if necessary.
      * @param timeMs The time in ms for the event initiating this gesture.
      */
-    void endFling(long timeMs) {
-        if (mFlingMayBeActive) {
-            sendGesture(GESTURE_FLING_CANCEL, timeMs, 0, 0, null);
-            tellNativeScrollingHasEnded(timeMs, false);
-            mFlingMayBeActive = false;
-        }
+    void endFlingIfNecessary(long timeMs) {
+        if (!mFlingMayBeActive) return;
+        mFlingMayBeActive = false;
+        sendGesture(GESTURE_FLING_CANCEL, timeMs, 0, 0, null);
     }
 
     /**
@@ -675,23 +673,26 @@
         mDoubleTapDragMode = DOUBLE_TAP_DRAG_MODE_NONE;
     }
 
-    // If native thinks scrolling (or fling-scrolling) is going on, tell native
-    // it has ended.
-    private void tellNativeScrollingHasEnded(long timeMs, boolean sendScrollEndEvent) {
-        if (mNativeScrolling) {
-            mNativeScrolling = false;
-            if (sendScrollEndEvent) {
-                sendGesture(GESTURE_SCROLL_END, timeMs, 0, 0, null);
-            }
+    /**
+     * Reset touch scroll flag and optionally send a GESTURE_SCROLL_END event if necessary.
+     * @param timeMs The time in ms for the event initiating this gesture.
+     * @param sendScrollEndEvent Whether to send GESTURE_SCROLL_END event.
+     */
+    private void endTouchScrollIfNecessary(long timeMs, boolean sendScrollEndEvent) {
+        if (!mTouchScrolling) return;
+        mTouchScrolling = false;
+        if (sendScrollEndEvent) {
+            sendGesture(GESTURE_SCROLL_END, timeMs, 0, 0, null);
         }
     }
 
     /**
-     * @return Whether native is tracking a scroll (i.e. between sending GESTURE_SCROLL_START and
-     *         GESTURE_SCROLL_END, or during a fling before sending GESTURE_FLING_CANCEL).
+     * @return Whether native is tracking a scroll.
      */
     boolean isNativeScrolling() {
-        return mNativeScrolling;
+        // TODO(wangxianzhu): Also return true when fling is active once the UI knows exactly when
+        // the fling ends.
+        return mTouchScrolling;
     }
 
     /**
@@ -777,7 +778,7 @@
             if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
                 mNoTouchHandlerForGesture = false;
                 mJavaScriptIsConsumingGesture = false;
-                endFling(event.getEventTime());
+                endFlingIfNecessary(event.getEventTime());
             } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
                 endDoubleTapDragMode(null);
             }
@@ -899,14 +900,15 @@
 
         if (type == TouchPoint.CONVERSION_ERROR) return EVENT_NOT_FORWARDED;
 
-        if (!mNativeScrolling && !mPinchInProgress) {
+        if (!mTouchScrolling && !mPinchInProgress) {
             mTouchCancelEventSent = false;
 
             if (mMotionEventDelegate.sendTouchEvent(event.getEventTime(), type, pts)) {
                 // If confirmTouchEvent() is called synchronously with respect to sendTouchEvent(),
                 // then |event| will have been recycled. Only start the timer if the sent event has
                 // not yet been confirmed.
-                if (event == mPendingMotionEvents.peekFirst()
+                if (!mJavaScriptIsConsumingGesture
+                        && event == mPendingMotionEvents.peekFirst()
                         && event.getAction() != MotionEvent.ACTION_UP
                         && event.getAction() != MotionEvent.ACTION_CANCEL) {
                     mTouchEventTimeoutHandler.start(event.getEventTime(), pts);
@@ -940,7 +942,7 @@
         // give the mSimpleTouchDetector a chance to continue
         // scrolling with a fling.
         if (event.getAction() == MotionEvent.ACTION_UP) {
-            if (mNativeScrolling) {
+            if (mTouchScrolling) {
                 possiblyEndMovement = true;
             }
         }
@@ -960,7 +962,7 @@
         handled |= mZoomManager.processTouchEvent(event);
 
         if (possiblyEndMovement && !handled) {
-            tellNativeScrollingHasEnded(event.getEventTime(), true);
+            endTouchScrollIfNecessary(event.getEventTime(), true);
         }
 
         return handled;
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
index 8cc0709..2647b3a 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
@@ -605,7 +605,7 @@
                 downTime, eventTime + 10, MotionEvent.ACTION_MOVE,
                 FAKE_COORD_X * 5, FAKE_COORD_Y * 5, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
-
+        assertTrue(mGestureHandler.isNativeScrolling());
         assertTrue("A scrollStart event should have been sent",
                 mockDelegate.mGestureTypeList.contains(
                         ContentViewGestureHandler.GESTURE_SCROLL_START));
@@ -619,6 +619,7 @@
                 downTime, eventTime + 15, MotionEvent.ACTION_UP,
                 FAKE_COORD_X * 10, FAKE_COORD_Y * 10, 0);
         assertTrue(mGestureHandler.onTouchEvent(event));
+        assertFalse(mGestureHandler.isNativeScrolling());
         assertEquals("We should have started flinging",
                 ContentViewGestureHandler.GESTURE_FLING_START,
                         mockDelegate.mMostRecentGestureEvent.mType);
diff --git a/content/public/browser/android/synchronous_compositor.h b/content/public/browser/android/synchronous_compositor.h
index 5223480..f559b97 100644
--- a/content/public/browser/android/synchronous_compositor.h
+++ b/content/public/browser/android/synchronous_compositor.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_H_
 #define CONTENT_PUBLIC_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_H_
 
+#include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
@@ -12,6 +13,7 @@
 class SkCanvas;
 
 namespace gfx {
+class GLSurface;
 class Transform;
 };
 
@@ -40,8 +42,9 @@
   // Synchronously initialize compositor for hardware draw. Can only be called
   // while compositor is in software only mode, either after compositor is
   // first created or after ReleaseHwDraw is called. It is invalid to
-  // DemandDrawHw before this returns true.
-  virtual bool InitializeHwDraw() = 0;
+  // DemandDrawHw before this returns true. |surface| is the GLSurface that
+  // should be used to create the underlying hardware context.
+  virtual bool InitializeHwDraw(scoped_refptr<gfx::GLSurface> surface) = 0;
 
   // Reverse of InitializeHwDraw above. Can only be called while hardware draw
   // is already initialized. Brings compositor back to software only mode and
diff --git a/content/public/browser/dom_storage_context.h b/content/public/browser/dom_storage_context.h
index d0c502f..a4aba1e 100644
--- a/content/public/browser/dom_storage_context.h
+++ b/content/public/browser/dom_storage_context.h
@@ -9,29 +9,25 @@
 #include <vector>
 
 #include "base/callback.h"
-#include "content/common/content_export.h"
 
 class GURL;
 
-namespace dom_storage {
-struct LocalStorageUsageInfo;
-struct SessionStorageUsageInfo;
-}
-
 namespace content {
 
 class BrowserContext;
+struct LocalStorageUsageInfo;
 class SessionStorageNamespace;
+struct SessionStorageUsageInfo;
 
 // Represents the per-BrowserContext Local Storage data.
 class DOMStorageContext {
  public:
   typedef base::Callback<
-      void(const std::vector<dom_storage::LocalStorageUsageInfo>&)>
+      void(const std::vector<LocalStorageUsageInfo>&)>
           GetLocalStorageUsageCallback;
 
   typedef base::Callback<
-      void(const std::vector<dom_storage::SessionStorageUsageInfo>&)>
+      void(const std::vector<SessionStorageUsageInfo>&)>
           GetSessionStorageUsageCallback;
 
   // Returns a collection of origins using local storage to the given callback.
@@ -48,12 +44,12 @@
 
   // Deletes the session storage data identified by |usage_info|.
   virtual void DeleteSessionStorage(
-      const dom_storage::SessionStorageUsageInfo& usage_info) = 0;
+      const SessionStorageUsageInfo& usage_info) = 0;
 
   // If this is called, sessionStorage data will be stored on disk, and can be
   // restored after a browser restart (with RecreateSessionStorage). This
-  // function must be called right after DOMStorageContextImpl is created, and
-  // before it's used.
+  // function must be called right after DOMStorageContextWrapper is created,
+  // and before it's used.
   virtual void SetSaveSessionStorageOnDisk() = 0;
 
   // Creates a SessionStorageNamespace with the given |persistent_id|. Used
diff --git a/content/public/browser/local_storage_usage_info.cc b/content/public/browser/local_storage_usage_info.cc
new file mode 100644
index 0000000..7bbfed3
--- /dev/null
+++ b/content/public/browser/local_storage_usage_info.cc
@@ -0,0 +1,14 @@
+// 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 "content/public/browser/local_storage_usage_info.h"
+
+namespace content {
+
+LocalStorageUsageInfo::LocalStorageUsageInfo()
+    : data_size(0) {}
+
+LocalStorageUsageInfo::~LocalStorageUsageInfo() {}
+
+}  // namespace content
diff --git a/content/public/browser/local_storage_usage_info.h b/content/public/browser/local_storage_usage_info.h
new file mode 100644
index 0000000..8048c6c
--- /dev/null
+++ b/content/public/browser/local_storage_usage_info.h
@@ -0,0 +1,26 @@
+// 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 CONTENT_PUBLIC_BROWSER_LOCAL_STORAGE_USAGE_INFO_H_
+#define CONTENT_PUBLIC_BROWSER_LOCAL_STORAGE_USAGE_INFO_H_
+
+#include "base/time/time.h"
+#include "content/common/content_export.h"
+#include "url/gurl.h"
+
+namespace content {
+
+// Used to report Local Storage usage info by DOMStorageContext.
+struct CONTENT_EXPORT LocalStorageUsageInfo {
+  GURL origin;
+  size_t data_size;
+  base::Time last_modified;
+
+  LocalStorageUsageInfo();
+  ~LocalStorageUsageInfo();
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_LOCAL_STORAGE_USAGE_INFO_H_
diff --git a/content/public/browser/session_storage_usage_info.h b/content/public/browser/session_storage_usage_info.h
new file mode 100644
index 0000000..2faf952
--- /dev/null
+++ b/content/public/browser/session_storage_usage_info.h
@@ -0,0 +1,18 @@
+// 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 CONTENT_PUBLIC_BROWSER_SESSION_STORAGE_USAGE_INFO_H_
+#define CONTENT_PUBLIC_BROWSER_SESSION_STORAGE_USAGE_INFO_H_
+
+namespace content {
+
+// Used to report Session Storage usage info by DOMStorageContext.
+struct CONTENT_EXPORT SessionStorageUsageInfo {
+  GURL origin;
+  std::string persistent_namespace_id;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_SESSION_STORAGE_USAGE_INFO_H_
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index fe4150e..40e932b 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -335,11 +335,6 @@
 // Enables restarting interrupted downloads.
 const char kEnableDownloadResumption[]      = "enable-download-resumption";
 
-#if defined(OS_CHROMEOS)
-// Enables hardware-encoded screen capture.
-const char kEnableEncodedScreenCapture[]    = "enable-encoded-screen-capture";
-#endif
-
 // Enables Web Platform features that are in development.
 const char kEnableExperimentalWebPlatformFeatures[] =
     "enable-experimental-web-platform-features";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 7b548ac..9124de1 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -35,9 +35,6 @@
 CONTENT_EXPORT extern const char kDisableDatabases[];
 extern const char kDisableDesktopNotifications[];
 CONTENT_EXPORT extern const char kDisableDeviceOrientation[];
-#if defined(OS_CHROMEOS)
-CONTENT_EXPORT extern const char kEnableEncodedScreenCapture[];
-#endif
 CONTENT_EXPORT extern const char kDisableExperimentalWebGL[];
 CONTENT_EXPORT extern const char kBlacklistAcceleratedCompositing[];
 CONTENT_EXPORT extern const char kBlacklistWebGL[];
diff --git a/content/public/test/render_view_fake_resources_test.cc b/content/public/test/render_view_fake_resources_test.cc
index 3b9d35b..89c6900 100644
--- a/content/public/test/render_view_fake_resources_test.cc
+++ b/content/public/test/render_view_fake_resources_test.cc
@@ -11,6 +11,7 @@
 #include "base/process/process.h"
 #include "base/run_loop.h"
 #include "base/time/time.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/common/resource_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/common/resource_response.h"
@@ -30,7 +31,6 @@
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/ui_base_switches.h"
 #include "url/gurl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/glue/webkit_glue.h"
 
 namespace content {
@@ -87,8 +87,7 @@
   ViewMsg_New_Params params;
   params.view_id = kViewId;
   params.opener_route_id = MSG_ROUTING_NONE;
-  params.session_storage_namespace_id =
-      dom_storage::kInvalidSessionStorageNamespaceId;
+  params.session_storage_namespace_id = kInvalidSessionStorageNamespaceId;
   ASSERT_TRUE(channel_->Send(new ViewMsg_New(params)));
   message_loop_.Run();
 }
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 99bdc18..df772f6 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -5,6 +5,7 @@
 #include "content/public/test/render_view_test.h"
 
 #include "base/run_loop.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/native_web_keyboard_event.h"
@@ -25,7 +26,6 @@
 #include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebView.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/glue/webkit_glue.h"
 
 using WebKit::WebFrame;
@@ -173,7 +173,7 @@
       kRouteId,
       kMainFrameRouteId,
       kSurfaceId,
-      dom_storage::kInvalidSessionStorageNamespaceId,
+      kInvalidSessionStorageNamespaceId,
       string16(),
       false,
       false,
diff --git a/content/renderer/cpp_bound_class_unittest.cc b/content/renderer/cpp_bound_class_unittest.cc
index 29c2fd4..2c0f75f 100644
--- a/content/renderer/cpp_bound_class_unittest.cc
+++ b/content/renderer/cpp_bound_class_unittest.cc
@@ -10,13 +10,12 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/renderer/render_view_observer.h"
 #include "content/public/test/render_view_test.h"
+#include "content/test/cpp_binding_example.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebElement.h"
-#include "webkit/renderer/cpp_binding_example.h"
 
 using webkit_glue::CppArgumentList;
-using webkit_glue::CppBindingExample;
 using webkit_glue::CppVariant;
 
 namespace content {
diff --git a/content/renderer/devtools/devtools_agent_filter.cc b/content/renderer/devtools/devtools_agent_filter.cc
index 8d448dd..1613ad8 100644
--- a/content/renderer/devtools/devtools_agent_filter.cc
+++ b/content/renderer/devtools/devtools_agent_filter.cc
@@ -8,7 +8,6 @@
 #include "base/message_loop/message_loop.h"
 #include "content/common/devtools_messages.h"
 #include "content/renderer/devtools/devtools_agent.h"
-#include "content/renderer/plugin_channel_host.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/web/WebDevToolsAgent.h"
 
diff --git a/content/renderer/dom_storage/OWNERS b/content/renderer/dom_storage/OWNERS
index 66ceac5..e1e6b1b 100644
--- a/content/renderer/dom_storage/OWNERS
+++ b/content/renderer/dom_storage/OWNERS
@@ -1,2 +1,7 @@
-marja@chromium.org
 michaeln@chromium.org
+kinuko@chromium.org
+jsbell@chromium.org
+ericu@chromium.org
+marja@chromium.org
+
+# Please include michaeln@ or marja@ if you make any functional/runtime changes.
diff --git a/content/renderer/dom_storage/dom_storage_cached_area.cc b/content/renderer/dom_storage/dom_storage_cached_area.cc
index a0203bb..a01d3c6 100644
--- a/content/renderer/dom_storage/dom_storage_cached_area.cc
+++ b/content/renderer/dom_storage/dom_storage_cached_area.cc
@@ -7,47 +7,47 @@
 #include "base/basictypes.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
+#include "content/common/dom_storage/dom_storage_map.h"
 #include "content/renderer/dom_storage/dom_storage_proxy.h"
-#include "webkit/common/dom_storage/dom_storage_map.h"
 
 namespace content {
 
-DomStorageCachedArea::DomStorageCachedArea(int64 namespace_id,
+DOMStorageCachedArea::DOMStorageCachedArea(int64 namespace_id,
                                            const GURL& origin,
-                                           DomStorageProxy* proxy)
+                                           DOMStorageProxy* proxy)
     : ignore_all_mutations_(false),
       namespace_id_(namespace_id),
       origin_(origin),
       proxy_(proxy),
       weak_factory_(this) {}
 
-DomStorageCachedArea::~DomStorageCachedArea() {}
+DOMStorageCachedArea::~DOMStorageCachedArea() {}
 
-unsigned DomStorageCachedArea::GetLength(int connection_id) {
+unsigned DOMStorageCachedArea::GetLength(int connection_id) {
   PrimeIfNeeded(connection_id);
   return map_->Length();
 }
 
-base::NullableString16 DomStorageCachedArea::GetKey(int connection_id,
+base::NullableString16 DOMStorageCachedArea::GetKey(int connection_id,
                                                     unsigned index) {
   PrimeIfNeeded(connection_id);
   return map_->Key(index);
 }
 
-base::NullableString16 DomStorageCachedArea::GetItem(
+base::NullableString16 DOMStorageCachedArea::GetItem(
     int connection_id,
     const base::string16& key) {
   PrimeIfNeeded(connection_id);
   return map_->GetItem(key);
 }
 
-bool DomStorageCachedArea::SetItem(int connection_id,
+bool DOMStorageCachedArea::SetItem(int connection_id,
                                    const base::string16& key,
                                    const base::string16& value,
                                    const GURL& page_url) {
   // A quick check to reject obviously overbudget items to avoid
   // the priming the cache.
-  if (key.length() + value.length() > dom_storage::kPerAreaQuota)
+  if (key.length() + value.length() > kPerStorageAreaQuota)
     return false;
 
   PrimeIfNeeded(connection_id);
@@ -59,12 +59,12 @@
   ignore_key_mutations_[key]++;
   proxy_->SetItem(
       connection_id, key, value, page_url,
-      base::Bind(&DomStorageCachedArea::OnSetItemComplete,
+      base::Bind(&DOMStorageCachedArea::OnSetItemComplete,
                  weak_factory_.GetWeakPtr(), key));
   return true;
 }
 
-void DomStorageCachedArea::RemoveItem(int connection_id,
+void DOMStorageCachedArea::RemoveItem(int connection_id,
                                       const base::string16& key,
                                       const GURL& page_url) {
   PrimeIfNeeded(connection_id);
@@ -76,24 +76,24 @@
   ignore_key_mutations_[key]++;
   proxy_->RemoveItem(
       connection_id, key, page_url,
-      base::Bind(&DomStorageCachedArea::OnRemoveItemComplete,
+      base::Bind(&DOMStorageCachedArea::OnRemoveItemComplete,
                  weak_factory_.GetWeakPtr(), key));
 }
 
-void DomStorageCachedArea::Clear(int connection_id, const GURL& page_url) {
+void DOMStorageCachedArea::Clear(int connection_id, const GURL& page_url) {
   // No need to prime the cache in this case.
   Reset();
-  map_ = new dom_storage::DomStorageMap(dom_storage::kPerAreaQuota);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota);
 
   // Ignore all mutations until OnClearComplete time.
   ignore_all_mutations_ = true;
   proxy_->ClearArea(connection_id,
                     page_url,
-                    base::Bind(&DomStorageCachedArea::OnClearComplete,
+                    base::Bind(&DOMStorageCachedArea::OnClearComplete,
                                weak_factory_.GetWeakPtr()));
 }
 
-void DomStorageCachedArea::ApplyMutation(
+void DOMStorageCachedArea::ApplyMutation(
     const base::NullableString16& key,
     const base::NullableString16& new_value) {
   if (!map_.get() || ignore_all_mutations_)
@@ -101,8 +101,8 @@
 
   if (key.is_null()) {
     // It's a clear event.
-    scoped_refptr<dom_storage::DomStorageMap> old = map_;
-    map_ = new dom_storage::DomStorageMap(dom_storage::kPerAreaQuota);
+    scoped_refptr<DOMStorageMap> old = map_;
+    map_ = new DOMStorageMap(kPerStorageAreaQuota);
 
     // We have to retain local additions which happened after this
     // clear operation from another process.
@@ -136,14 +136,14 @@
   base::NullableString16 unused;
   map_->set_quota(kint32max);
   map_->SetItem(key.string(), new_value.string(), &unused);
-  map_->set_quota(dom_storage::kPerAreaQuota);
+  map_->set_quota(kPerStorageAreaQuota);
 }
 
-size_t DomStorageCachedArea::MemoryBytesUsedByCache() const {
+size_t DOMStorageCachedArea::MemoryBytesUsedByCache() const {
   return map_.get() ? map_->bytes_used() : 0;
 }
 
-void DomStorageCachedArea::Prime(int connection_id) {
+void DOMStorageCachedArea::Prime(int connection_id) {
   DCHECK(!map_.get());
 
   // The LoadArea method is actually synchronous, but we have to
@@ -154,18 +154,18 @@
 
   // Ignore all mutations until OnLoadComplete time.
   ignore_all_mutations_ = true;
-  dom_storage::ValuesMap values;
+  DOMStorageValuesMap values;
   base::TimeTicks before = base::TimeTicks::Now();
   proxy_->LoadArea(connection_id,
                    &values,
-                   base::Bind(&DomStorageCachedArea::OnLoadComplete,
+                   base::Bind(&DOMStorageCachedArea::OnLoadComplete,
                               weak_factory_.GetWeakPtr()));
   base::TimeDelta time_to_prime = base::TimeTicks::Now() - before;
   // Keeping this histogram named the same (without the ForRenderer suffix)
   // to maintain histogram continuity.
   UMA_HISTOGRAM_TIMES("LocalStorage.TimeToPrimeLocalStorage",
                       time_to_prime);
-  map_ = new dom_storage::DomStorageMap(dom_storage::kPerAreaQuota);
+  map_ = new DOMStorageMap(kPerStorageAreaQuota);
   map_->SwapValues(&values);
 
   size_t local_storage_size_kb = map_->bytes_used() / 1024;
@@ -190,20 +190,20 @@
   }
 }
 
-void DomStorageCachedArea::Reset() {
+void DOMStorageCachedArea::Reset() {
   map_ = NULL;
   weak_factory_.InvalidateWeakPtrs();
   ignore_key_mutations_.clear();
   ignore_all_mutations_ = false;
 }
 
-void DomStorageCachedArea::OnLoadComplete(bool success) {
+void DOMStorageCachedArea::OnLoadComplete(bool success) {
   DCHECK(success);
   DCHECK(ignore_all_mutations_);
   ignore_all_mutations_ = false;
 }
 
-void DomStorageCachedArea::OnSetItemComplete(const base::string16& key,
+void DOMStorageCachedArea::OnSetItemComplete(const base::string16& key,
                                              bool success) {
   if (!success) {
     Reset();
@@ -216,7 +216,7 @@
     ignore_key_mutations_.erase(found);
 }
 
-void DomStorageCachedArea::OnRemoveItemComplete(const base::string16& key,
+void DOMStorageCachedArea::OnRemoveItemComplete(const base::string16& key,
                                                 bool success) {
   DCHECK(success);
   std::map<base::string16, int>::iterator found =
@@ -226,7 +226,7 @@
     ignore_key_mutations_.erase(found);
 }
 
-void DomStorageCachedArea::OnClearComplete(bool success) {
+void DOMStorageCachedArea::OnClearComplete(bool success) {
   DCHECK(success);
   DCHECK(ignore_all_mutations_);
   ignore_all_mutations_ = false;
diff --git a/content/renderer/dom_storage/dom_storage_cached_area.h b/content/renderer/dom_storage/dom_storage_cached_area.h
index 2aa4cd9..b991038 100644
--- a/content/renderer/dom_storage/dom_storage_cached_area.h
+++ b/content/renderer/dom_storage/dom_storage_cached_area.h
@@ -13,13 +13,10 @@
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
-namespace dom_storage {
-class DomStorageMap;
-}
-
 namespace content {
 
-class DomStorageProxy;
+class DOMStorageMap;
+class DOMStorageProxy;
 
 // Unlike the other classes in the dom_storage library, this one is intended
 // for use in renderer processes. It maintains a complete cache of the
@@ -27,12 +24,12 @@
 // first access and changes are written to the backend thru the |proxy|.
 // Mutations originating in other processes are applied to the cache via
 // the ApplyMutation method.
-class CONTENT_EXPORT DomStorageCachedArea
-    : public base::RefCounted<DomStorageCachedArea> {
+class CONTENT_EXPORT DOMStorageCachedArea
+    : public base::RefCounted<DOMStorageCachedArea> {
  public:
-  DomStorageCachedArea(int64 namespace_id,
+  DOMStorageCachedArea(int64 namespace_id,
                        const GURL& origin,
-                       DomStorageProxy* proxy);
+                       DOMStorageProxy* proxy);
 
   int64 namespace_id() const { return namespace_id_; }
   const GURL& origin() const { return origin_; }
@@ -55,9 +52,9 @@
   size_t MemoryBytesUsedByCache() const;
 
  private:
-  friend class DomStorageCachedAreaTest;
-  friend class base::RefCounted<DomStorageCachedArea>;
-  ~DomStorageCachedArea();
+  friend class DOMStorageCachedAreaTest;
+  friend class base::RefCounted<DOMStorageCachedArea>;
+  ~DOMStorageCachedArea();
 
   // Primes the cache, loading all values for the area.
   void Prime(int connection_id);
@@ -87,9 +84,9 @@
 
   int64 namespace_id_;
   GURL origin_;
-  scoped_refptr<dom_storage::DomStorageMap> map_;
-  scoped_refptr<DomStorageProxy> proxy_;
-  base::WeakPtrFactory<DomStorageCachedArea> weak_factory_;
+  scoped_refptr<DOMStorageMap> map_;
+  scoped_refptr<DOMStorageProxy> proxy_;
+  base::WeakPtrFactory<DOMStorageCachedArea> weak_factory_;
 };
 
 }  // namespace content
diff --git a/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc b/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
index 9dcef95..ada36d7 100644
--- a/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
+++ b/content/renderer/dom_storage/dom_storage_cached_area_unittest.cc
@@ -14,17 +14,17 @@
 namespace content {
 
 namespace {
-// A mock implementation of the DomStorageProxy interface.
-class MockProxy : public DomStorageProxy {
+// A mock implementation of the DOMStorageProxy interface.
+class MockProxy : public DOMStorageProxy {
  public:
   MockProxy() {
     ResetObservations();
   }
 
-  // DomStorageProxy interface for use by DomStorageCachedArea.
+  // DOMStorageProxy interface for use by DOMStorageCachedArea.
 
   virtual void LoadArea(int connection_id,
-                        dom_storage::ValuesMap* values,
+                        DOMStorageValuesMap* values,
                         const CompletionCallback& callback) OVERRIDE {
     pending_callbacks_.push_back(callback);
     observed_load_area_ = true;
@@ -91,7 +91,7 @@
 
   typedef std::list<CompletionCallback> CallbackList;
 
-  dom_storage::ValuesMap load_area_return_values_;
+  DOMStorageValuesMap load_area_return_values_;
   CallbackList pending_callbacks_;
   bool observed_load_area_;
   bool observed_set_item_;
@@ -108,9 +108,9 @@
 
 }  // namespace
 
-class DomStorageCachedAreaTest : public testing::Test {
+class DOMStorageCachedAreaTest : public testing::Test {
  public:
-  DomStorageCachedAreaTest()
+  DOMStorageCachedAreaTest()
     : kNamespaceId(10),
       kOrigin("http://dom_storage/"),
       kKey(ASCIIToUTF16("key")),
@@ -128,26 +128,26 @@
     mock_proxy_ = new MockProxy();
   }
 
-  bool IsPrimed(DomStorageCachedArea* cached_area) {
+  bool IsPrimed(DOMStorageCachedArea* cached_area) {
     return cached_area->map_.get();
   }
 
-  bool IsIgnoringAllMutations(DomStorageCachedArea* cached_area) {
+  bool IsIgnoringAllMutations(DOMStorageCachedArea* cached_area) {
     return cached_area->ignore_all_mutations_;
   }
 
-  bool IsIgnoringKeyMutations(DomStorageCachedArea* cached_area,
+  bool IsIgnoringKeyMutations(DOMStorageCachedArea* cached_area,
                               const base::string16& key) {
     return cached_area->should_ignore_key_mutation(key);
   }
 
-  void ResetAll(DomStorageCachedArea* cached_area) {
+  void ResetAll(DOMStorageCachedArea* cached_area) {
     cached_area->Reset();
     mock_proxy_->ResetObservations();
     mock_proxy_->pending_callbacks_.clear();
   }
 
-  void ResetCacheOnly(DomStorageCachedArea* cached_area) {
+  void ResetCacheOnly(DOMStorageCachedArea* cached_area) {
     cached_area->Reset();
   }
 
@@ -155,10 +155,10 @@
   scoped_refptr<MockProxy> mock_proxy_;
 };
 
-TEST_F(DomStorageCachedAreaTest, Basics) {
+TEST_F(DOMStorageCachedAreaTest, Basics) {
   EXPECT_TRUE(mock_proxy_->HasOneRef());
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
   EXPECT_EQ(kNamespaceId, cached_area->namespace_id());
   EXPECT_EQ(kOrigin, cached_area->origin());
   EXPECT_FALSE(mock_proxy_->HasOneRef());
@@ -180,10 +180,10 @@
   EXPECT_EQ(0u, cached_area->GetLength(kConnectionId));
 }
 
-TEST_F(DomStorageCachedAreaTest, Getters) {
+TEST_F(DOMStorageCachedAreaTest, Getters) {
   const int kConnectionId = 7;
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
 
   // GetLength, we expect to see one call to load in the proxy.
   EXPECT_FALSE(IsPrimed(cached_area.get()));
@@ -215,10 +215,10 @@
   EXPECT_EQ(1u, mock_proxy_->pending_callbacks_.size());
 }
 
-TEST_F(DomStorageCachedAreaTest, Setters) {
+TEST_F(DOMStorageCachedAreaTest, Setters) {
   const int kConnectionId = 7;
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
 
   // SetItem, we expect a call to load followed by a call to set item
   // in the proxy.
@@ -270,10 +270,10 @@
   EXPECT_EQ(2u, mock_proxy_->pending_callbacks_.size());
 }
 
-TEST_F(DomStorageCachedAreaTest, MutationsAreIgnoredUntilLoadCompletion) {
+TEST_F(DOMStorageCachedAreaTest, MutationsAreIgnoredUntilLoadCompletion) {
   const int kConnectionId = 7;
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
   EXPECT_TRUE(cached_area->GetItem(kConnectionId, kKey).is_null());
   EXPECT_TRUE(IsPrimed(cached_area.get()));
   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
@@ -293,10 +293,10 @@
   EXPECT_EQ(kValue, cached_area->GetItem(kConnectionId, kKey).string());
 }
 
-TEST_F(DomStorageCachedAreaTest, MutationsAreIgnoredUntilClearCompletion) {
+TEST_F(DOMStorageCachedAreaTest, MutationsAreIgnoredUntilClearCompletion) {
   const int kConnectionId = 4;
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
   cached_area->Clear(kConnectionId, kPageUrl);
   EXPECT_TRUE(IsIgnoringAllMutations(cached_area.get()));
   mock_proxy_->CompleteOnePendingCallback(true);
@@ -315,10 +315,10 @@
   EXPECT_FALSE(IsIgnoringAllMutations(cached_area.get()));
 }
 
-TEST_F(DomStorageCachedAreaTest, KeyMutationsAreIgnoredUntilCompletion) {
+TEST_F(DOMStorageCachedAreaTest, KeyMutationsAreIgnoredUntilCompletion) {
   const int kConnectionId = 8;
-  scoped_refptr<DomStorageCachedArea> cached_area =
-      new DomStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
+  scoped_refptr<DOMStorageCachedArea> cached_area =
+      new DOMStorageCachedArea(kNamespaceId, kOrigin, mock_proxy_.get());
 
   // SetItem
   EXPECT_TRUE(cached_area->SetItem(kConnectionId, kKey, kValue, kPageUrl));
@@ -353,4 +353,4 @@
   EXPECT_FALSE(IsPrimed(cached_area.get()));
 }
 
-}  // namespace dom_storage
+}  // namespace content
diff --git a/content/renderer/dom_storage/dom_storage_dispatcher.cc b/content/renderer/dom_storage/dom_storage_dispatcher.cc
index 3cab4fe..a8a37c9 100644
--- a/content/renderer/dom_storage/dom_storage_dispatcher.cc
+++ b/content/renderer/dom_storage/dom_storage_dispatcher.cc
@@ -9,7 +9,8 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
-#include "content/common/dom_storage_messages.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/renderer/dom_storage/dom_storage_cached_area.h"
 #include "content/renderer/dom_storage/dom_storage_proxy.h"
 #include "content/renderer/dom_storage/webstoragearea_impl.h"
@@ -18,9 +19,6 @@
 #include "third_party/WebKit/public/platform/Platform.h"
 #include "third_party/WebKit/public/web/WebKit.h"
 #include "third_party/WebKit/public/web/WebStorageEventDispatcher.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
-
-using dom_storage::ValuesMap;
 
 namespace content {
 
@@ -92,24 +90,24 @@
 }  // namespace
 
 // ProxyImpl -----------------------------------------------------
-// An implementation of the DomStorageProxy interface in terms of IPC.
+// An implementation of the DOMStorageProxy interface in terms of IPC.
 // This class also manages the collection of cached areas and pending
 // operations awaiting completion callbacks.
-class DomStorageDispatcher::ProxyImpl : public DomStorageProxy {
+class DomStorageDispatcher::ProxyImpl : public DOMStorageProxy {
  public:
   explicit ProxyImpl(RenderThreadImpl* sender);
 
   // Methods for use by DomStorageDispatcher directly.
-  DomStorageCachedArea* OpenCachedArea(
+  DOMStorageCachedArea* OpenCachedArea(
       int64 namespace_id, const GURL& origin);
-  void CloseCachedArea(DomStorageCachedArea* area);
-  DomStorageCachedArea* LookupCachedArea(
+  void CloseCachedArea(DOMStorageCachedArea* area);
+  DOMStorageCachedArea* LookupCachedArea(
       int64 namespace_id, const GURL& origin);
   void CompleteOnePendingCallback(bool success);
   void Shutdown();
 
-  // DomStorageProxy interface for use by DomStorageCachedArea.
-  virtual void LoadArea(int connection_id, ValuesMap* values,
+  // DOMStorageProxy interface for use by DOMStorageCachedArea.
+  virtual void LoadArea(int connection_id, DOMStorageValuesMap* values,
                         const CompletionCallback& callback) OVERRIDE;
   virtual void SetItem(int connection_id, const string16& key,
                        const string16& value, const GURL& page_url,
@@ -125,10 +123,10 @@
   // Struct to hold references to our contained areas and
   // to keep track of how many tabs have a given area open.
   struct CachedAreaHolder {
-    scoped_refptr<DomStorageCachedArea> area_;
+    scoped_refptr<DOMStorageCachedArea> area_;
     int open_count_;
     CachedAreaHolder() : open_count_(0) {}
-    CachedAreaHolder(DomStorageCachedArea* area, int count)
+    CachedAreaHolder(DOMStorageCachedArea* area, int count)
         : area_(area), open_count_(count) {}
   };
   typedef std::map<std::string, CachedAreaHolder> CachedAreaMap;
@@ -176,21 +174,21 @@
   sender_->AddFilter(throttling_filter_.get());
 }
 
-DomStorageCachedArea* DomStorageDispatcher::ProxyImpl::OpenCachedArea(
+DOMStorageCachedArea* DomStorageDispatcher::ProxyImpl::OpenCachedArea(
     int64 namespace_id, const GURL& origin) {
   std::string key = GetCachedAreaKey(namespace_id, origin);
   if (CachedAreaHolder* holder = GetAreaHolder(key)) {
     ++(holder->open_count_);
     return holder->area_.get();
   }
-  scoped_refptr<DomStorageCachedArea> area =
-      new DomStorageCachedArea(namespace_id, origin, this);
+  scoped_refptr<DOMStorageCachedArea> area =
+      new DOMStorageCachedArea(namespace_id, origin, this);
   cached_areas_[key] = CachedAreaHolder(area.get(), 1);
   return area.get();
 }
 
 void DomStorageDispatcher::ProxyImpl::CloseCachedArea(
-    DomStorageCachedArea* area) {
+    DOMStorageCachedArea* area) {
   std::string key = GetCachedAreaKey(area->namespace_id(), area->origin());
   CachedAreaHolder* holder = GetAreaHolder(key);
   DCHECK(holder);
@@ -201,7 +199,7 @@
   }
 }
 
-DomStorageCachedArea* DomStorageDispatcher::ProxyImpl::LookupCachedArea(
+DOMStorageCachedArea* DomStorageDispatcher::ProxyImpl::LookupCachedArea(
     int64 namespace_id, const GURL& origin) {
   std::string key = GetCachedAreaKey(namespace_id, origin);
   CachedAreaHolder* holder = GetAreaHolder(key);
@@ -223,7 +221,7 @@
 }
 
 void DomStorageDispatcher::ProxyImpl::LoadArea(
-    int connection_id, ValuesMap* values,
+    int connection_id, DOMStorageValuesMap* values,
     const CompletionCallback& callback) {
   PushPendingCallback(callback);
   throttling_filter_->SendThrottled(new DOMStorageHostMsg_LoadStorageArea(
@@ -265,7 +263,7 @@
   proxy_->Shutdown();
 }
 
-scoped_refptr<DomStorageCachedArea> DomStorageDispatcher::OpenCachedArea(
+scoped_refptr<DOMStorageCachedArea> DomStorageDispatcher::OpenCachedArea(
     int connection_id, int64 namespace_id, const GURL& origin) {
   RenderThreadImpl::current()->Send(
       new DOMStorageHostMsg_OpenStorageArea(
@@ -274,7 +272,7 @@
 }
 
 void DomStorageDispatcher::CloseCachedArea(
-    int connection_id, DomStorageCachedArea* area) {
+    int connection_id, DOMStorageCachedArea* area) {
   RenderThreadImpl::current()->Send(
       new DOMStorageHostMsg_CloseStorageArea(connection_id));
   proxy_->CloseCachedArea(area);
@@ -301,13 +299,13 @@
     originating_area = WebStorageAreaImpl::FromConnectionId(
         params.connection_id);
   } else {
-    DomStorageCachedArea* cached_area = proxy_->LookupCachedArea(
+    DOMStorageCachedArea* cached_area = proxy_->LookupCachedArea(
         params.namespace_id, params.origin);
     if (cached_area)
       cached_area->ApplyMutation(params.key, params.new_value);
   }
 
-  if (params.namespace_id == dom_storage::kLocalStorageNamespaceId) {
+  if (params.namespace_id == kLocalStorageNamespaceId) {
     WebKit::WebStorageEventDispatcher::dispatchLocalStorageEvent(
         params.key,
         params.old_value,
diff --git a/content/renderer/dom_storage/dom_storage_dispatcher.h b/content/renderer/dom_storage/dom_storage_dispatcher.h
index f5d4004..f395d57 100644
--- a/content/renderer/dom_storage/dom_storage_dispatcher.h
+++ b/content/renderer/dom_storage/dom_storage_dispatcher.h
@@ -16,23 +16,23 @@
 
 namespace content {
 
-class DomStorageCachedArea;
+class DOMStorageCachedArea;
 
 // Dispatches DomStorage related messages sent to a renderer process from the
 // main browser process. There is one instance per child process. Messages
 // are dispatched on the main renderer thread. The RenderThreadImpl
 // creates an instance and delegates calls to it. This classes also manages
-// the collection of DomStorageCachedAreas that are active in the process.
+// the collection of DOMStorageCachedAreas that are active in the process.
 class DomStorageDispatcher {
  public:
   DomStorageDispatcher();
   ~DomStorageDispatcher();
 
   // Each call to open should be balanced with a call to close.
-  scoped_refptr<DomStorageCachedArea> OpenCachedArea(int connection_id,
+  scoped_refptr<DOMStorageCachedArea> OpenCachedArea(int connection_id,
                                                      int64 namespace_id,
                                                      const GURL& origin);
-  void CloseCachedArea(int connection_id, DomStorageCachedArea* area);
+  void CloseCachedArea(int connection_id, DOMStorageCachedArea* area);
 
   bool OnMessageReceived(const IPC::Message& msg);
 
diff --git a/content/renderer/dom_storage/dom_storage_proxy.h b/content/renderer/dom_storage/dom_storage_proxy.h
index 57fcfaf..80cd87c 100644
--- a/content/renderer/dom_storage/dom_storage_proxy.h
+++ b/content/renderer/dom_storage/dom_storage_proxy.h
@@ -9,18 +9,18 @@
 #include "base/memory/ref_counted.h"
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string16.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "url/gurl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 namespace content {
 
 // Abstract interface for cached area, renderer to browser communications.
-class DomStorageProxy : public base::RefCounted<DomStorageProxy> {
+class DOMStorageProxy : public base::RefCounted<DOMStorageProxy> {
  public:
   typedef base::Callback<void(bool)> CompletionCallback;
 
   virtual void LoadArea(int connection_id,
-                        dom_storage::ValuesMap* values,
+                        DOMStorageValuesMap* values,
                         const CompletionCallback& callback) = 0;
 
   virtual void SetItem(int connection_id,
@@ -39,8 +39,8 @@
                          const CompletionCallback& callback) = 0;
 
  protected:
-  friend class base::RefCounted<DomStorageProxy>;
-  virtual ~DomStorageProxy() {}
+  friend class base::RefCounted<DOMStorageProxy>;
+  virtual ~DOMStorageProxy() {}
 };
 
 }  // namespace content
diff --git a/content/renderer/dom_storage/webstoragearea_impl.cc b/content/renderer/dom_storage/webstoragearea_impl.cc
index 72e9415..d5bf07d 100644
--- a/content/renderer/dom_storage/webstoragearea_impl.cc
+++ b/content/renderer/dom_storage/webstoragearea_impl.cc
@@ -8,7 +8,7 @@
 #include "base/metrics/histogram.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "content/common/dom_storage_messages.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
 #include "content/renderer/dom_storage/dom_storage_cached_area.h"
 #include "content/renderer/dom_storage/dom_storage_dispatcher.h"
 #include "content/renderer/render_thread_impl.h"
diff --git a/content/renderer/dom_storage/webstoragearea_impl.h b/content/renderer/dom_storage/webstoragearea_impl.h
index 47d0581..7854562 100644
--- a/content/renderer/dom_storage/webstoragearea_impl.h
+++ b/content/renderer/dom_storage/webstoragearea_impl.h
@@ -14,7 +14,7 @@
 
 namespace content {
 
-class DomStorageCachedArea;
+class DOMStorageCachedArea;
 
 class WebStorageAreaImpl : public WebKit::WebStorageArea {
  public:
@@ -37,7 +37,7 @@
 
  private:
   int connection_id_;
-  scoped_refptr<DomStorageCachedArea> cached_area_;
+  scoped_refptr<DOMStorageCachedArea> cached_area_;
 };
 
 }  // namespace content
diff --git a/content/renderer/dom_storage/webstoragenamespace_impl.cc b/content/renderer/dom_storage/webstoragenamespace_impl.cc
index de2b6c5..d5f1dc5 100644
--- a/content/renderer/dom_storage/webstoragenamespace_impl.cc
+++ b/content/renderer/dom_storage/webstoragenamespace_impl.cc
@@ -5,10 +5,10 @@
 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
 
 #include "base/logging.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/renderer/dom_storage/webstoragearea_impl.h"
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "url/gurl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 
 using WebKit::WebStorageArea;
 using WebKit::WebStorageNamespace;
@@ -17,13 +17,13 @@
 namespace content {
 
 WebStorageNamespaceImpl::WebStorageNamespaceImpl()
-    : namespace_id_(dom_storage::kLocalStorageNamespaceId) {
+    : namespace_id_(kLocalStorageNamespaceId) {
 }
 
 WebStorageNamespaceImpl::WebStorageNamespaceImpl(
     int64 namespace_id)
     : namespace_id_(namespace_id) {
-  DCHECK_NE(dom_storage::kInvalidSessionStorageNamespaceId, namespace_id);
+  DCHECK_NE(kInvalidSessionStorageNamespaceId, namespace_id);
 }
 
 WebStorageNamespaceImpl::~WebStorageNamespaceImpl() {
diff --git a/content/renderer/media/media_stream_dependency_factory.cc b/content/renderer/media/media_stream_dependency_factory.cc
index a0f25a6..7f5e64a 100644
--- a/content/renderer/media/media_stream_dependency_factory.cc
+++ b/content/renderer/media/media_stream_dependency_factory.cc
@@ -37,10 +37,6 @@
 #include "third_party/WebKit/public/web/WebFrame.h"
 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h"
 
-#if defined(ENABLE_WEBRTC)
-#include "content/renderer/media/rtc_encoding_video_capturer_factory.h"
-#endif
-
 #if defined(USE_OPENSSL)
 #include "third_party/libjingle/source/talk/base/ssladapter.h"
 #else
@@ -303,6 +299,11 @@
   RTCMediaConstraints native_audio_constraints(audio_constraints);
   WebKit::WebVector<WebKit::WebMediaStreamTrack> audio_tracks;
   web_stream->audioTracks(audio_tracks);
+  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+  if (command_line.HasSwitch(switches::kEnableWebRtcAecRecordings)) {
+    native_audio_constraints.AddOptional(
+        RTCMediaConstraints::kInternalAecDump, "true");
+  }
   for (size_t i = 0; i < audio_tracks.size(); ++i) {
     const WebKit::WebMediaStreamSource& source = audio_tracks[i].source();
     MediaStreamSourceExtraData* source_data =
@@ -313,22 +314,20 @@
       continue;
     }
 
+    // TODO(xians): Create a new capturer for difference microphones when we
+    // support multiple microphones. See issue crbug/262117 .
     const StreamDeviceInfo device_info = source_data->device_info();
-    if (IsAudioMediaType(device_info.device.type)) {
-      if (!InitializeAudioSource(render_view_id, device_info)) {
-        DLOG(WARNING) << "Unsupported audio source";
-        sources_created.Run(web_stream, false);
-        return;
-      }
-    }
-
-    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-    if (command_line.HasSwitch(switches::kEnableWebRtcAecRecordings)) {
-      native_audio_constraints.AddOptional(
-          RTCMediaConstraints::kInternalAecDump, "true");
+    scoped_refptr<WebRtcAudioCapturer> capturer(
+        MaybeCreateAudioCapturer(render_view_id, device_info));
+    if (!capturer.get()) {
+      DLOG(WARNING) << "Failed to create the capturer for device "
+                    << device_info.device.id;
+      sources_created.Run(web_stream, false);
+      return;
     }
 
     // Creates a LocalAudioSource object which holds audio options.
+    // TODO(xians): The option should apply to the track instead of the source.
     source_data->SetLocalAudioSource(
         CreateLocalAudioSource(&native_audio_constraints).get());
     source_observer->AddSource(source_data->local_audio_source());
@@ -389,21 +388,14 @@
   MediaStreamSourceExtraData* source_data =
       static_cast<MediaStreamSourceExtraData*>(source.extraData());
 
+  scoped_refptr<WebRtcAudioCapturer> capturer;
   if (!source_data) {
     if (source.requiresAudioConsumer()) {
       // We're adding a WebAudio MediaStream.
-      // TODO(crogers, xians): In reality we should be able to send a unique
-      // audio stream to each PeerConnection separately.
-      // Currently WebRTC is only able to handle a global audio stream sent to
-      // ALL peers. Create a special source where default WebAudio constraints
-      // are used.
-      if (CreateWebAudioSource(&source)) {
-        source_data =
-            static_cast<MediaStreamSourceExtraData*>(source.extraData());
-      } else {
-        LOG(ERROR) << "Failed to create WebAudio source";
-        return false;
-      }
+      // Create a specific capturer for each WebAudio consumer.
+      capturer = CreateWebAudioSource(&source);
+      source_data =
+          static_cast<MediaStreamSourceExtraData*>(source.extraData());
     } else {
       // TODO(perkj): Implement support for sources from
       // remote MediaStreams.
@@ -418,16 +410,17 @@
 
   std::string track_id = UTF16ToUTF8(track.id());
   if (source.type() == WebKit::WebMediaStreamSource::TypeAudio) {
-    scoped_refptr<webrtc::AudioTrackInterface> audio_track(
-        CreateLocalAudioTrack(track_id, source_data->local_audio_source()));
-    audio_track->set_enabled(track.isEnabled());
-    // Start the audio track. This will hook the |audio_track| to the capturer
-    // as the sink of the audio, and only start the source of the capturer if
-    // it is the first audio track connecting to the capturer.
-    static_cast<WebRtcLocalAudioTrack*>(audio_track.get())->Start();
+    if (!capturer.get() && GetWebRtcAudioDevice())
+      capturer = GetWebRtcAudioDevice()->GetDefaultCapturer();
 
+    scoped_refptr<webrtc::AudioTrackInterface> audio_track(
+        CreateLocalAudioTrack(track_id,
+                              capturer,
+                              source_data->local_audio_source()));
+    audio_track->set_enabled(track.isEnabled());
     return native_stream->AddTrack(audio_track.get());
   } else {
+    DCHECK(source.type() == WebKit::WebMediaStreamSource::TypeVideo);
     scoped_refptr<webrtc::VideoTrackInterface> video_track(
         CreateLocalVideoTrack(track_id, source_data->video_source()));
     video_track->set_enabled(track.isEnabled());
@@ -494,7 +487,6 @@
     audio_device_ = new WebRtcAudioDeviceImpl();
 
     scoped_ptr<cricket::WebRtcVideoDecoderFactory> decoder_factory;
-    scoped_ptr<cricket::WebRtcVideoEncoderFactory> encoder_factory;
 
     const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
     if (cmd_line->HasSwitch(switches::kEnableWebRtcHWDecoding)) {
@@ -511,24 +503,11 @@
     decoder_factory.reset(decoder_factory_tv_ = new RTCVideoDecoderFactoryTv);
 #endif
 
-#if defined(ENABLE_WEBRTC) && defined(OS_CHROMEOS)
-    const CommandLine& command_line = *CommandLine::ForCurrentProcess();
-    if (command_line.HasSwitch(switches::kEnableEncodedScreenCapture)) {
-      // PeerConnectionFactory owns the encoder factory. Pass a weak pointer of
-      // encoder factory to |vc_manager_| because the manager outlives it.
-      RtcEncodingVideoCapturerFactory* rtc_encoding_capturer_factory =
-          new RtcEncodingVideoCapturerFactory();
-      encoder_factory.reset(rtc_encoding_capturer_factory);
-      vc_manager_->set_encoding_capturer_factory(
-          rtc_encoding_capturer_factory->AsWeakPtr());
-    }
-#endif
-
     scoped_refptr<webrtc::PeerConnectionFactoryInterface> factory(
         webrtc::CreatePeerConnectionFactory(worker_thread_,
                                             signaling_thread_,
                                             audio_device_.get(),
-                                            encoder_factory.release(),
+                                            NULL,
                                             decoder_factory.release()));
     if (factory.get())
       pc_factory_ = factory;
@@ -610,47 +589,23 @@
   return source;
 }
 
-bool MediaStreamDependencyFactory::InitializeAudioSource(
-    int render_view_id,
-    const StreamDeviceInfo& device_info) {
-  DVLOG(1) << "MediaStreamDependencyFactory::InitializeAudioSource()";
-
-  // TODO(henrika): the current design does not support a unique source
-  // for each audio track.
-  if (device_info.session_id <= 0)
-    return false;
-
-  // Initialize the source using audio parameters for the selected
-  // capture device.
-  WebRtcAudioCapturer* capturer = GetWebRtcAudioDevice()->capturer().get();
-  // TODO(henrika): refactor \content\public\common\media_stream_request.h
-  // to allow dependency of media::ChannelLayout and avoid static_cast.
-  if (!capturer->Initialize(
-          render_view_id,
-          static_cast<media::ChannelLayout>(device_info.device.channel_layout),
-          device_info.device.sample_rate, device_info.session_id))
-    return false;
-
-  return true;
-}
-
-bool MediaStreamDependencyFactory::CreateWebAudioSource(
+scoped_refptr<WebRtcAudioCapturer>
+MediaStreamDependencyFactory::CreateWebAudioSource(
     WebKit::WebMediaStreamSource* source) {
   DVLOG(1) << "MediaStreamDependencyFactory::CreateWebAudioSource()";
   DCHECK(GetWebRtcAudioDevice());
 
-  // WebAudio needs the WebRtcAudioCapturer to be able to send its data
-  // over a PeerConnection. The microphone source is not utilized in this
-  // case; instead the WebRtcAudioCapturer is driving.
-  WebRtcAudioCapturer* capturer = GetWebRtcAudioDevice()->capturer().get();
-  if (!capturer)
-    return false;
-
   // Set up the source and ensure that WebAudio is driving things instead of
-  // a microphone.
+  // a microphone. For WebAudio, we always create a new capturer without
+  // calling initialize(), WebAudio will re-configure the capturer later on.
+  // Pass -1 as the |render_view_id| and an empty device struct to tell the
+  // capturer not to start the default source.
+  scoped_refptr<WebRtcAudioCapturer> capturer(
+      MaybeCreateAudioCapturer(-1, StreamDeviceInfo()));
+  DCHECK(capturer.get());
 
   scoped_refptr<WebAudioCapturerSource>
-      webaudio_capturer_source(new WebAudioCapturerSource(capturer));
+      webaudio_capturer_source(new WebAudioCapturerSource(capturer.get()));
   MediaStreamSourceExtraData* source_data =
       new content::MediaStreamSourceExtraData(webaudio_capturer_source.get());
 
@@ -667,7 +622,7 @@
   // Replace the default source with WebAudio as source instead.
   source->addAudioConsumer(webaudio_capturer_source.get());
 
-  return true;
+  return capturer;
 }
 
 scoped_refptr<webrtc::VideoTrackInterface>
@@ -696,12 +651,20 @@
 scoped_refptr<webrtc::AudioTrackInterface>
 MediaStreamDependencyFactory::CreateLocalAudioTrack(
     const std::string& id,
+    const scoped_refptr<WebRtcAudioCapturer>& capturer,
     webrtc::AudioSourceInterface* source) {
   // TODO(xians): Merge |source| to the capturer(). We can't do this today
   // because only one capturer() is supported while one |source| is created
   // for each audio track.
-  return WebRtcLocalAudioTrack::Create(id, GetWebRtcAudioDevice()->capturer(),
-                                       source);
+  scoped_refptr<WebRtcLocalAudioTrack> audio_track(
+      WebRtcLocalAudioTrack::Create(id, capturer, source));
+  // Add the WebRtcAudioDevice as the sink to the local audio track.
+  audio_track->AddSink(GetWebRtcAudioDevice());
+  // Start the audio track. This will hook the |audio_track| to the capturer
+  // as the sink of the audio, and only start the source of the capturer if
+  // it is the first audio track connecting to the capturer.
+  audio_track->Start();
+  return audio_track;
 }
 
 webrtc::SessionDescriptionInterface*
@@ -724,20 +687,6 @@
   return audio_device_.get();
 }
 
-void MediaStreamDependencyFactory::StopLocalAudioSource(
-    const WebKit::WebMediaStream& web_stream) {
-  MediaStreamExtraData* extra_data = static_cast<MediaStreamExtraData*>(
-      web_stream.extraData());
-  if (extra_data && extra_data->is_local() && extra_data->stream().get() &&
-      !extra_data->stream()->GetAudioTracks().empty()) {
-    // Stop the audio track. This will unhook the audio track from the capturer
-    // and will shutdown the source of the capturer if it is the last audio
-    // track connecting to the capturer.
-    static_cast<WebRtcLocalAudioTrack*>(
-        extra_data->stream()->GetAudioTracks()[0].get())->Stop();
-  }
-}
-
 void MediaStreamDependencyFactory::InitializeWorkerThread(
     talk_base::Thread** thread,
     base::WaitableEvent* event) {
@@ -841,4 +790,36 @@
   }
 }
 
+scoped_refptr<WebRtcAudioCapturer>
+MediaStreamDependencyFactory::MaybeCreateAudioCapturer(
+    int render_view_id,
+    const StreamDeviceInfo& device_info) {
+  scoped_refptr<WebRtcAudioCapturer> capturer;
+  if (render_view_id != -1) {
+    // From a normal getUserMedia, re-use the existing default capturer.
+    capturer = GetWebRtcAudioDevice()->GetDefaultCapturer();
+  }
+  // If the default capturer does not exist or |render_view_id| == -1, create
+  // a new capturer.
+  bool is_new_capturer = false;
+  if (!capturer.get()) {
+    capturer = WebRtcAudioCapturer::CreateCapturer();
+    is_new_capturer = true;
+  }
+
+  if (!capturer->Initialize(
+          render_view_id,
+          static_cast<media::ChannelLayout>(device_info.device.channel_layout),
+          device_info.device.sample_rate, device_info.session_id,
+          device_info.device.id)) {
+    return NULL;
+  }
+
+  // Add the capturer to the WebRtcAudioDeviceImpl if it is a new capturer.
+  if (is_new_capturer)
+    GetWebRtcAudioDevice()->AddAudioCapturer(capturer);
+
+  return capturer;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/media_stream_dependency_factory.h b/content/renderer/media/media_stream_dependency_factory.h
index 74dceb5..720ecb0 100644
--- a/content/renderer/media/media_stream_dependency_factory.h
+++ b/content/renderer/media/media_stream_dependency_factory.h
@@ -43,6 +43,7 @@
 class IpcNetworkManager;
 class IpcPacketSocketFactory;
 class VideoCaptureImplManager;
+class WebRtcAudioCapturer;
 class WebRtcAudioDeviceImpl;
 class WebRtcLoggingHandlerImpl;
 class WebRtcLoggingMessageFilter;
@@ -135,11 +136,6 @@
 
   WebRtcAudioDeviceImpl* GetWebRtcAudioDevice();
 
-  // Stop the audio source for local audio tracks.
-  // TODO(xians): Remove this function if each audio track takes care of their
-  // own source.
-  void StopLocalAudioSource(const WebKit::WebMediaStream& web_stream);
-
 #if defined(GOOGLE_TV)
   RTCVideoDecoderFactoryTv* decoder_factory_tv() { return decoder_factory_tv_; }
 #endif
@@ -161,21 +157,17 @@
           bool is_screen_cast,
           const webrtc::MediaConstraintsInterface* constraints);
 
-  // Initializes the source using audio parameters for the selected
-  // capture device and specifies which capture device to use as capture
-  // source.
-  virtual bool InitializeAudioSource(int render_view_id,
-                                     const StreamDeviceInfo& device_info);
-
   // Creates a media::AudioCapturerSource with an implementation that is
   // specific for a WebAudio source. The created WebAudioCapturerSource
   // instance will function as audio source instead of the default
   // WebRtcAudioCapturer.
-  virtual bool CreateWebAudioSource(WebKit::WebMediaStreamSource* source);
+  virtual scoped_refptr<WebRtcAudioCapturer> CreateWebAudioSource(
+      WebKit::WebMediaStreamSource* source);
 
   // Asks the PeerConnection factory to create a Local AudioTrack object.
   virtual scoped_refptr<webrtc::AudioTrackInterface>
       CreateLocalAudioTrack(const std::string& id,
+                            const scoped_refptr<WebRtcAudioCapturer>& capturer,
                             webrtc::AudioSourceInterface* source);
 
   // Asks the PeerConnection factory to create a Local VideoTrack object.
@@ -192,6 +184,12 @@
   virtual bool EnsurePeerConnectionFactory();
   virtual bool PeerConnectionFactoryCreated();
 
+  // Returns a new capturer or existing capturer based on the |render_view_id|
+  // and |device_info|. When the |render_view_id| and |device_info| are valid,
+  // it reuses existing capture if any; otherwise it creates a new capturer.
+  virtual scoped_refptr<WebRtcAudioCapturer> MaybeCreateAudioCapturer(
+      int render_view_id, const StreamDeviceInfo& device_info);
+
  private:
   // Creates and deletes |pc_factory_|, which in turn is used for
   // creating PeerConnection objects.
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
index 3033301..abe68a2 100644
--- a/content/renderer/media/media_stream_impl.cc
+++ b/content/renderer/media/media_stream_impl.cc
@@ -132,8 +132,7 @@
 
   UserMediaRequestInfo* user_media_request = FindUserMediaRequestInfo(label);
   if (user_media_request) {
-    dependency_factory_->StopLocalAudioSource(user_media_request->web_stream);
-
+    StopLocalAudioTrack(user_media_request->web_stream);
     media_stream_dispatcher_->StopStream(label);
     DeleteUserMediaRequestInfo(user_media_request);
   } else {
@@ -514,7 +513,7 @@
       // If not, we cancel the request and delete the request object.
       if ((*request_it)->generated) {
         // Stop the local audio track before closing the device in the browser.
-        dependency_factory_->StopLocalAudioSource((*request_it)->web_stream);
+        StopLocalAudioTrack((*request_it)->web_stream);
 
         media_stream_dispatcher_->StopStream(
             UTF16ToUTF8((*request_it)->web_stream.id()));
@@ -566,12 +565,6 @@
   DVLOG(1) << "MediaStreamImpl::CreateLocalAudioRenderer label:"
            << stream->label();
 
-  scoped_refptr<WebRtcAudioCapturer> source =
-      dependency_factory_->GetWebRtcAudioDevice()->capturer();
-  if (!source.get()) {
-    return NULL;
-  }
-
   webrtc::AudioTrackVector audio_tracks = stream->GetAudioTracks();
   DCHECK_EQ(audio_tracks.size(), 1u);
   webrtc::AudioTrackInterface* audio_track = audio_tracks[0];
@@ -586,6 +579,27 @@
       RenderViewObserver::routing_id());
 }
 
+void MediaStreamImpl::StopLocalAudioTrack(
+    const WebKit::WebMediaStream& web_stream) {
+  MediaStreamExtraData* extra_data = static_cast<MediaStreamExtraData*>(
+      web_stream.extraData());
+  if (extra_data && extra_data->is_local() && extra_data->stream().get() &&
+      !extra_data->stream()->GetAudioTracks().empty()) {
+    webrtc::AudioTrackVector audio_tracks =
+        extra_data->stream()->GetAudioTracks();
+    for (size_t i = 0; i < audio_tracks.size(); ++i) {
+      WebRtcLocalAudioTrack* audio_track = static_cast<WebRtcLocalAudioTrack*>(
+          audio_tracks[i].get());
+      // Remove the WebRtcAudioDevice as the sink to the local audio track.
+      audio_track->RemoveSink(dependency_factory_->GetWebRtcAudioDevice());
+      // Stop the audio track. This will unhook the audio track from the
+      // capturer and will shutdown the source of the capturer if it is the
+      // last audio track connecting to the capturer.
+      audio_track->Stop();
+    }
+  }
+}
+
 MediaStreamSourceExtraData::MediaStreamSourceExtraData(
     const StreamDeviceInfo& device_info,
     const WebKit::WebMediaStreamSource& webkit_source)
diff --git a/content/renderer/media/media_stream_impl.h b/content/renderer/media/media_stream_impl.h
index fb3db97..ee506cc 100644
--- a/content/renderer/media/media_stream_impl.h
+++ b/content/renderer/media/media_stream_impl.h
@@ -152,6 +152,8 @@
   scoped_refptr<WebRtcLocalAudioRenderer> CreateLocalAudioRenderer(
       webrtc::MediaStreamInterface* stream);
 
+  void StopLocalAudioTrack(const WebKit::WebMediaStream& web_stream);
+
   // Weak ref to a MediaStreamDependencyFactory, owned by the RenderThread.
   // It's valid for the lifetime of RenderThread.
   MediaStreamDependencyFactory* dependency_factory_;
diff --git a/content/renderer/media/mock_media_stream_dependency_factory.cc b/content/renderer/media/mock_media_stream_dependency_factory.cc
index d2ca141..cac1eaf4 100644
--- a/content/renderer/media/mock_media_stream_dependency_factory.cc
+++ b/content/renderer/media/mock_media_stream_dependency_factory.cc
@@ -406,15 +406,10 @@
   return last_video_source_;
 }
 
-bool MockMediaStreamDependencyFactory::InitializeAudioSource(
-    int render_view_id,
-    const StreamDeviceInfo& device_info) {
-  return true;
-}
-
-bool MockMediaStreamDependencyFactory::CreateWebAudioSource(
+scoped_refptr<WebRtcAudioCapturer>
+MockMediaStreamDependencyFactory::CreateWebAudioSource(
     WebKit::WebMediaStreamSource* source) {
-  return true;
+  return NULL;
 }
 
 scoped_refptr<webrtc::MediaStreamInterface>
@@ -451,11 +446,12 @@
 scoped_refptr<webrtc::AudioTrackInterface>
 MockMediaStreamDependencyFactory::CreateLocalAudioTrack(
     const std::string& id,
+    const scoped_refptr<WebRtcAudioCapturer>& capturer,
     webrtc::AudioSourceInterface* source) {
   DCHECK(mock_pc_factory_created_);
-  scoped_refptr<WebRtcAudioCapturer> capturer(
-      WebRtcAudioCapturer::CreateCapturer());
-  return WebRtcLocalAudioTrack::Create(id, capturer, source);
+  DCHECK(!capturer.get());
+  return WebRtcLocalAudioTrack::Create(
+      id, WebRtcAudioCapturer::CreateCapturer(), source);
 }
 
 SessionDescriptionInterface*
@@ -474,4 +470,10 @@
   return new MockIceCandidate(sdp_mid, sdp_mline_index, sdp);
 }
 
+scoped_refptr<WebRtcAudioCapturer>
+MockMediaStreamDependencyFactory::MaybeCreateAudioCapturer(
+    int render_view_id, const StreamDeviceInfo& device_info) {
+  return WebRtcAudioCapturer::CreateCapturer();
+}
+
 }  // namespace content
diff --git a/content/renderer/media/mock_media_stream_dependency_factory.h b/content/renderer/media/mock_media_stream_dependency_factory.h
index 65faa66..1d37a2f 100644
--- a/content/renderer/media/mock_media_stream_dependency_factory.h
+++ b/content/renderer/media/mock_media_stream_dependency_factory.h
@@ -126,9 +126,7 @@
           int video_session_id,
           bool is_screencast,
           const webrtc::MediaConstraintsInterface* constraints) OVERRIDE;
-  virtual bool InitializeAudioSource(
-      int render_view_id, const StreamDeviceInfo& device_info) OVERRIDE;
-  virtual bool CreateWebAudioSource(
+  virtual scoped_refptr<WebRtcAudioCapturer> CreateWebAudioSource(
       WebKit::WebMediaStreamSource* source) OVERRIDE;
   virtual scoped_refptr<webrtc::MediaStreamInterface>
       CreateLocalMediaStream(const std::string& label) OVERRIDE;
@@ -140,6 +138,7 @@
                             cricket::VideoCapturer* capturer) OVERRIDE;
   virtual scoped_refptr<webrtc::AudioTrackInterface>
       CreateLocalAudioTrack(const std::string& id,
+                            const scoped_refptr<WebRtcAudioCapturer>& capturer,
                             webrtc::AudioSourceInterface* source) OVERRIDE;
   virtual webrtc::SessionDescriptionInterface* CreateSessionDescription(
       const std::string& type,
@@ -153,6 +152,9 @@
   virtual bool EnsurePeerConnectionFactory() OVERRIDE;
   virtual bool PeerConnectionFactoryCreated() OVERRIDE;
 
+  virtual scoped_refptr<WebRtcAudioCapturer> MaybeCreateAudioCapturer(
+      int render_view_id, const StreamDeviceInfo& device_info) OVERRIDE;
+
   MockAudioSource* last_audio_source() { return last_audio_source_.get(); }
   MockVideoSource* last_video_source() { return last_video_source_.get(); }
 
diff --git a/content/renderer/media/rtc_encoding_video_capturer.cc b/content/renderer/media/rtc_encoding_video_capturer.cc
deleted file mode 100644
index 9561c83..0000000
--- a/content/renderer/media/rtc_encoding_video_capturer.cc
+++ /dev/null
@@ -1,260 +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 "content/renderer/media/rtc_encoding_video_capturer.h"
-
-#include "base/logging.h"
-#include "media/base/encoded_bitstream_buffer.h"
-
-namespace content {
-
-namespace {
-
-static const unsigned int kMaxBitrateKbps = 50 * 1000;
-
-}  // namespace
-
-// Client of EncodedVideoSource. This object is created and owned by the
-// RtcEncodingVideoCapturer.
-class RtcEncodingVideoCapturer::EncodedVideoSourceClient :
-    public media::EncodedVideoSource::Client {
- public:
-  EncodedVideoSourceClient(
-      media::EncodedVideoSource* encoded_video_source,
-      media::VideoEncodingParameters params,
-      webrtc::VideoCodecType rtc_codec_type);
-  virtual ~EncodedVideoSourceClient();
-
-  // media::EncodedVideoSource::Client implementation.
-  virtual void OnOpened(
-      const media::VideoEncodingParameters& params) OVERRIDE;
-  virtual void OnClosed() OVERRIDE;
-  virtual void OnBufferReady(
-      scoped_refptr<const media::EncodedBitstreamBuffer> buffer) OVERRIDE;
-  virtual void OnConfigChanged(
-      const media::RuntimeVideoEncodingParameters& params) OVERRIDE;
-
-  // Getters and setters for bitstream properties.
-  media::RuntimeVideoEncodingParameters runtime_params() const;
-  void set_round_trip_time(base::TimeDelta round_trip_time);
-  void set_callback(webrtc::EncodedImageCallback* callback);
-
-  // Sets target bitrate and framerate.
-  void SetRates(uint32_t target_bitrate, uint32_t frame_rate);
-
-  // Requests key frame.
-  void RequestKeyFrame();
-
- private:
-  // Convert buffer to webrtc types and invoke encode complete callback.
-  void ReportEncodedFrame(
-      scoped_refptr<const media::EncodedBitstreamBuffer> buffer);
-
-  media::VideoEncodingParameters params_;
-  webrtc::VideoCodecType rtc_codec_type_;
-  bool finished_;
-
-  base::Time time_base_;
-  base::TimeDelta round_trip_time_;
-  media::EncodedVideoSource* encoded_video_source_;
-  webrtc::EncodedImageCallback* callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(EncodedVideoSourceClient);
-};
-
-RtcEncodingVideoCapturer::EncodedVideoSourceClient::EncodedVideoSourceClient(
-    media::EncodedVideoSource* encoded_video_source,
-    media::VideoEncodingParameters params,
-    webrtc::VideoCodecType rtc_codec_type)
-    : params_(params),
-      rtc_codec_type_(rtc_codec_type),
-      finished_(false),
-      encoded_video_source_(encoded_video_source),
-      callback_(NULL) {
-  DCHECK(encoded_video_source_);
-  encoded_video_source_->OpenBitstream(this, params);
-}
-
-RtcEncodingVideoCapturer::EncodedVideoSourceClient::
-    ~EncodedVideoSourceClient() {
-  if (!finished_)
-    encoded_video_source_->CloseBitstream();
-}
-
-media::RuntimeVideoEncodingParameters
-    RtcEncodingVideoCapturer::EncodedVideoSourceClient::runtime_params() const {
-  return params_.runtime_params;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_round_trip_time(
-    base::TimeDelta round_trip_time) {
-  round_trip_time_ = round_trip_time;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::set_callback(
-    webrtc::EncodedImageCallback* callback) {
-  DCHECK(!callback_);
-  callback_ = callback;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnOpened(
-    const media::VideoEncodingParameters& params) {
-  params_ = params;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnClosed() {
-  finished_ = true;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnBufferReady(
-    scoped_refptr<const media::EncodedBitstreamBuffer> buffer) {
-  DCHECK(!finished_ && buffer.get());
-
-  // First buffer constitutes the origin of the time for this bitstream context.
-  if (time_base_.is_null())
-    time_base_ = buffer->metadata().timestamp;
-
-  ReportEncodedFrame(buffer);
-  encoded_video_source_->ReturnBitstreamBuffer(buffer);
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::OnConfigChanged(
-    const media::RuntimeVideoEncodingParameters& params) {
-  params_.runtime_params = params;
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::SetRates(
-    uint32_t target_bitrate, uint32_t frame_rate) {
-  params_.runtime_params.target_bitrate = target_bitrate;
-  params_.runtime_params.frames_per_second = frame_rate;
-  encoded_video_source_->TrySetBitstreamConfig(params_.runtime_params);
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::RequestKeyFrame() {
-  encoded_video_source_->RequestKeyFrame();
-}
-
-void RtcEncodingVideoCapturer::EncodedVideoSourceClient::ReportEncodedFrame(
-    scoped_refptr<const media::EncodedBitstreamBuffer> buffer) {
-  if (!callback_)
-    return;
-
-  webrtc::EncodedImage image;
-  webrtc::CodecSpecificInfo codecInfo;
-  webrtc::RTPFragmentationHeader fragHeader;
-
-  // TODO(hshi): remove this const_cast. Unfortunately webrtc::EncodedImage
-  // defines member |_buffer| of type uint8_t* even though webrtc never modifies
-  // the buffer contents.
-  image._buffer = const_cast<uint8_t*>(buffer->buffer());
-  image._length = buffer->size();
-  image._size = image._length;
-
-  const media::BufferEncodingMetadata& metadata = buffer->metadata();
-  base::TimeDelta capture_time = metadata.timestamp - time_base_;
-  image.capture_time_ms_ = capture_time.InMilliseconds();
-  // Convert capture time to 90 kHz RTP timestamp.
-  image._timeStamp = (capture_time * 90000).InSeconds();
-  if (metadata.key_frame) {
-    image._frameType = webrtc::kKeyFrame;
-  } else {
-    image._frameType = webrtc::kDeltaFrame;
-  }
-  image._completeFrame = true;
-  image._encodedWidth = params_.resolution.width();
-  image._encodedHeight = params_.resolution.height();
-
-  // TODO(hshi): generate codec specific info for VP8.
-  codecInfo.codecType = rtc_codec_type_;
-
-  // Generate header containing a single fragmentation.
-  fragHeader.VerifyAndAllocateFragmentationHeader(1);
-  fragHeader.fragmentationOffset[0] = 0;
-  fragHeader.fragmentationLength[0] = buffer->size();
-  fragHeader.fragmentationPlType[0] = 0;
-  fragHeader.fragmentationTimeDiff[0] = 0;
-
-  callback_->Encoded(image, &codecInfo, &fragHeader);
-}
-
-// RtcEncodingVideoCapturer
-RtcEncodingVideoCapturer::RtcEncodingVideoCapturer(
-    media::EncodedVideoSource* encoded_video_source,
-    webrtc::VideoCodecType codec_type)
-    : encoded_video_source_(encoded_video_source),
-      rtc_codec_type_(codec_type) {
-}
-
-RtcEncodingVideoCapturer::~RtcEncodingVideoCapturer() {
-}
-
-int32_t RtcEncodingVideoCapturer::InitEncode(
-    const webrtc::VideoCodec* codecSettings,
-    int32_t numberOfCores,
-    uint32_t maxPayloadSize) {
-  DCHECK(!encoded_video_source_client_);
-  if (codecSettings->codecType != rtc_codec_type_)
-    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
-  if (codecSettings->startBitrate > kMaxBitrateKbps ||
-      codecSettings->maxBitrate > kMaxBitrateKbps)
-    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
-
-  // Convert |codecSettings| to |params|.
-  media::VideoEncodingParameters params;
-  params.codec_name = codecSettings->plName;
-  params.resolution = gfx::Size(codecSettings->width, codecSettings->height);
-  params.runtime_params.target_bitrate = codecSettings->startBitrate * 1000;
-  params.runtime_params.max_bitrate = codecSettings->maxBitrate * 1000;
-  params.runtime_params.frames_per_second = codecSettings->maxFramerate;
-  encoded_video_source_client_.reset(new EncodedVideoSourceClient(
-      encoded_video_source_, params, rtc_codec_type_));
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t RtcEncodingVideoCapturer::Encode(
-    const webrtc::I420VideoFrame& /* inputImage */,
-    const webrtc::CodecSpecificInfo* codecSpecificInfo,
-    const std::vector<webrtc::VideoFrameType>* frame_types) {
-  if (frame_types && !frame_types->empty()) {
-    webrtc::VideoFrameType type = frame_types->front();
-    if (type == webrtc::kKeyFrame)
-      encoded_video_source_client_->RequestKeyFrame();
-  }
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t RtcEncodingVideoCapturer::RegisterEncodeCompleteCallback(
-      webrtc::EncodedImageCallback* callback) {
-  DCHECK(encoded_video_source_client_);
-  encoded_video_source_client_->set_callback(callback);
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t RtcEncodingVideoCapturer::Release() {
-  DCHECK(encoded_video_source_client_);
-  encoded_video_source_client_.reset(NULL);
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t RtcEncodingVideoCapturer::SetChannelParameters(
-    uint32_t /* packetLoss */,
-    int rtt_in_ms) {
-  if (!encoded_video_source_client_)
-    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
-  encoded_video_source_client_->set_round_trip_time(
-      base::TimeDelta::FromMilliseconds(rtt_in_ms));
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-int32_t RtcEncodingVideoCapturer::SetRates(uint32_t newBitRate,
-                                           uint32_t frameRate) {
-  if (!encoded_video_source_client_)
-    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
-  if (newBitRate > kMaxBitrateKbps)
-    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
-  encoded_video_source_client_->SetRates(newBitRate * 1000, frameRate);
-  return WEBRTC_VIDEO_CODEC_OK;
-}
-
-}  // namespace content
diff --git a/content/renderer/media/rtc_encoding_video_capturer.h b/content/renderer/media/rtc_encoding_video_capturer.h
deleted file mode 100644
index 77f9626..0000000
--- a/content/renderer/media/rtc_encoding_video_capturer.h
+++ /dev/null
@@ -1,56 +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 CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_
-#define CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_
-
-#include "base/memory/ref_counted.h"
-#include "media/video/encoded_video_source.h"
-#include "media/video/video_encode_types.h"
-#include "third_party/libjingle/source/talk/media/webrtc/webrtcvie.h"
-
-namespace content {
-
-// Class to represent an encoding capable video capture interface for the
-// WebRTC component. This class expects to be registered as an encoder with
-// an internal source to the WebRTC stack and will not be able to function as
-// an encoder for uncompressed video frames.
-class RtcEncodingVideoCapturer : public webrtc::VideoEncoder {
- public:
-  RtcEncodingVideoCapturer(media::EncodedVideoSource* encoded_video_source,
-                           webrtc::VideoCodecType codec_type);
-  virtual ~RtcEncodingVideoCapturer();
-
-  // webrtc::VideoEncoder implementation.
-  virtual int32_t InitEncode(const webrtc::VideoCodec* codecSettings,
-                             int32_t numberOfCores,
-                             uint32_t maxPayloadSize) OVERRIDE;
-  virtual int32_t Encode(
-      const webrtc::I420VideoFrame& /* inputImage */,
-      const webrtc::CodecSpecificInfo* codecSpecificInfo,
-      const std::vector<webrtc::VideoFrameType>* frame_types) OVERRIDE;
-  virtual int32_t RegisterEncodeCompleteCallback(
-      webrtc::EncodedImageCallback* callback) OVERRIDE;
-  virtual int32_t Release() OVERRIDE;
-  virtual int32_t SetChannelParameters(uint32_t /* packetLoss */,
-                                       int rtt_in_ms) OVERRIDE;
-  virtual int32_t SetRates(uint32_t newBitRate,
-                           uint32_t frameRate) OVERRIDE;
- private:
-  // Forward declaration for private implementation to represent the
-  // encoded video source client;
-  class EncodedVideoSourceClient;
-  scoped_ptr<EncodedVideoSourceClient> encoded_video_source_client_;
-
-  // Pointer to the underlying EncodedVideoSource object. It is guaranteed to
-  // outlive the RtcEncodingVideoCapturer.
-  media::EncodedVideoSource* encoded_video_source_;
-  webrtc::VideoCodecType rtc_codec_type_;
-
-  DISALLOW_COPY_AND_ASSIGN(RtcEncodingVideoCapturer);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_H_
diff --git a/content/renderer/media/rtc_encoding_video_capturer_factory.cc b/content/renderer/media/rtc_encoding_video_capturer_factory.cc
deleted file mode 100644
index a699aed..0000000
--- a/content/renderer/media/rtc_encoding_video_capturer_factory.cc
+++ /dev/null
@@ -1,100 +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 "content/renderer/media/rtc_encoding_video_capturer_factory.h"
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "content/renderer/media/rtc_encoding_video_capturer.h"
-#include "media/base/encoded_bitstream_buffer.h"
-
-namespace content {
-
-RtcEncodingVideoCapturerFactory::RtcEncodingVideoCapturerFactory()
-    : encoded_video_source_(NULL) {
-}
-
-RtcEncodingVideoCapturerFactory::~RtcEncodingVideoCapturerFactory() {
-  DCHECK(encoder_set_.empty());
-}
-
-void RtcEncodingVideoCapturerFactory::OnEncodedVideoSourceAdded(
-    media::EncodedVideoSource* source) {
-  // TODO(hshi): support multiple encoded video sources.
-  // For now we only support one instance of encoded video source at a time.
-  DCHECK(!encoded_video_source_);
-  encoded_video_source_ = source;
-  source->RequestCapabilities(base::Bind(
-      &RtcEncodingVideoCapturerFactory::OnCapabilitiesAvailable,
-      AsWeakPtr()));
-}
-
-void RtcEncodingVideoCapturerFactory::OnEncodedVideoSourceRemoved(
-    media::EncodedVideoSource* source) {
-  encoded_video_source_ = NULL;
-}
-
-webrtc::VideoEncoder* RtcEncodingVideoCapturerFactory::CreateVideoEncoder(
-    webrtc::VideoCodecType type) {
-  for (size_t i = 0; i < codecs_.size(); ++i) {
-    if (codecs_[i].type == type) {
-      RtcEncodingVideoCapturer* capturer =
-          new RtcEncodingVideoCapturer(encoded_video_source_, type);
-      encoder_set_.insert(capturer);
-      return capturer;
-    }
-  }
-  return NULL;
-}
-
-void RtcEncodingVideoCapturerFactory::DestroyVideoEncoder(
-    webrtc::VideoEncoder* encoder) {
-  EncoderSet::iterator it = encoder_set_.find(encoder);
-  if (it != encoder_set_.end()) {
-      delete encoder;
-      encoder_set_.erase(it);
-  }
-}
-
-void RtcEncodingVideoCapturerFactory::AddObserver(
-    WebRtcVideoEncoderFactory::Observer* observer) {
-  observers_.AddObserver(observer);
-}
-
-void RtcEncodingVideoCapturerFactory::RemoveObserver(
-    WebRtcVideoEncoderFactory::Observer* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-const std::vector<cricket::WebRtcVideoEncoderFactory::VideoCodec>&
-RtcEncodingVideoCapturerFactory::codecs() const {
-  return codecs_;
-}
-
-void RtcEncodingVideoCapturerFactory::OnCapabilitiesAvailable(
-    const media::VideoEncodingCapabilities& caps) {
-  codecs_.clear();
-
-  for (size_t i = 0; i < caps.size(); ++i) {
-    webrtc::VideoCodecType webrtc_codec_type = webrtc::kVideoCodecGeneric;
-    switch (caps[i].codec_type) {
-      case media::kCodecVP8:
-        webrtc_codec_type = webrtc::kVideoCodecVP8;
-        break;
-      default:
-        break;
-    }
-    codecs_.push_back(cricket::WebRtcVideoEncoderFactory::VideoCodec(
-        webrtc_codec_type,
-        caps[i].codec_name,
-        caps[i].max_resolution.width(),
-        caps[i].max_resolution.height(),
-        caps[i].max_frames_per_second));
-  }
-
-  FOR_EACH_OBSERVER(WebRtcVideoEncoderFactory::Observer, observers_,
-                    OnCodecsAvailable());
-}
-
-}  // namespace content
diff --git a/content/renderer/media/rtc_encoding_video_capturer_factory.h b/content/renderer/media/rtc_encoding_video_capturer_factory.h
deleted file mode 100644
index 1fdf4f5..0000000
--- a/content/renderer/media/rtc_encoding_video_capturer_factory.h
+++ /dev/null
@@ -1,61 +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 CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_
-#define CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_
-
-#include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
-#include "media/video/encoded_video_source.h"
-#include "media/video/video_encode_types.h"
-#include "third_party/libjingle/source/talk/media/webrtc/webrtcvideoencoderfactory.h"
-
-namespace content {
-
-class RtcEncodingVideoCapturer;
-
-class RtcEncodingVideoCapturerFactory :
-      public cricket::WebRtcVideoEncoderFactory,
-      public base::SupportsWeakPtr<RtcEncodingVideoCapturerFactory> {
- public:
-  RtcEncodingVideoCapturerFactory();
-
-  // WebRtcVideoEncoderFactory interface.
-  virtual webrtc::VideoEncoder* CreateVideoEncoder(
-      webrtc::VideoCodecType type) OVERRIDE;
-  virtual void DestroyVideoEncoder(webrtc::VideoEncoder* encoder) OVERRIDE;
-
-  virtual const std::vector<VideoCodec>& codecs() const OVERRIDE;
-
-  virtual void AddObserver(
-      WebRtcVideoEncoderFactory::Observer* observer) OVERRIDE;
-  virtual void RemoveObserver(
-      WebRtcVideoEncoderFactory::Observer* observer) OVERRIDE;
-
-  // Callback for RequestCapabilities().
-  void OnCapabilitiesAvailable(const media::VideoEncodingCapabilities& caps);
-
-  // Invoked when an EncodedVideoSource is added/removed.
-  void OnEncodedVideoSourceAdded(media::EncodedVideoSource* source);
-  void OnEncodedVideoSourceRemoved(media::EncodedVideoSource* source);
-
-private:
-  virtual ~RtcEncodingVideoCapturerFactory();
-
-  // Set of registered encoding capable video capturers.
-  typedef std::set<webrtc::VideoEncoder*> EncoderSet;
-
-  media::EncodedVideoSource* encoded_video_source_;
-  std::vector<VideoCodec> codecs_;
-
-  EncoderSet encoder_set_;
-
-  ObserverList<WebRtcVideoEncoderFactory::Observer, true> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(RtcEncodingVideoCapturerFactory);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_RTC_ENCODING_VIDEO_CAPTURER_FACTORY_H_
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 72e9cfd..4f048fa 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -15,6 +15,7 @@
 #include "content/renderer/media/peer_connection_tracker.h"
 #include "content/renderer/media/rtc_media_constraints.h"
 #include "content/renderer/media/rtc_peer_connection_handler.h"
+#include "content/renderer/media/webrtc_audio_capturer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
@@ -248,8 +249,10 @@
 
     local_stream.audioTracks(audio_tracks);
     const std::string audio_track_id = UTF16ToUTF8(audio_tracks[0].id());
+    scoped_refptr<WebRtcAudioCapturer> capturer;
     scoped_refptr<webrtc::AudioTrackInterface> audio_track(
         mock_dependency_factory_->CreateLocalAudioTrack(audio_track_id,
+                                                        capturer,
                                                         NULL));
     native_stream->AddTrack(audio_track.get());
 
@@ -282,8 +285,10 @@
       stream->AddTrack(video_track.get());
     }
     if (!audio_track_label.empty()) {
+      scoped_refptr<WebRtcAudioCapturer> capturer;
       scoped_refptr<webrtc::AudioTrackInterface> audio_track(
           mock_dependency_factory_->CreateLocalAudioTrack(audio_track_label,
+                                                          capturer,
                                                           NULL));
       stream->AddTrack(audio_track.get());
     }
diff --git a/content/renderer/media/video_capture_impl.cc b/content/renderer/media/video_capture_impl.cc
index 4fc186b..032cd7f 100644
--- a/content/renderer/media/video_capture_impl.cc
+++ b/content/renderer/media/video_capture_impl.cc
@@ -5,10 +5,8 @@
 #include "content/renderer/media/video_capture_impl.h"
 
 #include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/stl_util.h"
 #include "content/child/child_process.h"
-#include "content/common/media/encoded_video_capture_messages.h"
 #include "content/common/media/video_capture_messages.h"
 #include "media/base/limits.h"
 
@@ -60,9 +58,7 @@
       video_type_(media::VideoCaptureCapability::kI420),
       device_info_available_(false),
       suspended_(false),
-      state_(VIDEO_CAPTURE_STATE_STOPPED),
-      encoded_video_source_client_(NULL),
-      bitstream_open_(false) {
+      state_(VIDEO_CAPTURE_STATE_STOPPED) {
   DCHECK(filter);
   capture_format_.session_id = id;
 }
@@ -103,87 +99,6 @@
                  base::Unretained(this), handler));
 }
 
-void VideoCaptureImpl::RequestCapabilities(
-    const media::EncodedVideoSource::RequestCapabilitiesCallback& callback) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread,
-                 base::Unretained(this), callback));
-}
-
-void VideoCaptureImpl::StartFetchCapabilities() {
-  Send(new EncodedVideoCaptureHostMsg_GetCapabilities(
-      device_id_, capture_format_.session_id));
-}
-
-void VideoCaptureImpl::OpenBitstream(
-    media::EncodedVideoSource::Client* client,
-    const media::VideoEncodingParameters& params) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoOpenBitstreamOnCaptureThread,
-                 base::Unretained(this), client, params));
-}
-
-void VideoCaptureImpl::CloseBitstream() {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoCloseBitstreamOnCaptureThread,
-                 base::Unretained(this)));
-}
-
-void VideoCaptureImpl::ReturnBitstreamBuffer(
-    scoped_refptr<const media::EncodedBitstreamBuffer> buffer) {
-  Send(new EncodedVideoCaptureHostMsg_BitstreamBufferConsumed(
-      device_id_, buffer->buffer_id()));
-}
-
-void VideoCaptureImpl::TrySetBitstreamConfig(
-    const media::RuntimeVideoEncodingParameters& params) {
-  Send(new EncodedVideoCaptureHostMsg_TryConfigureBitstream(
-      device_id_, params));
-}
-
-void VideoCaptureImpl::RequestKeyFrame() {
-  Send(new EncodedVideoCaptureHostMsg_RequestKeyFrame(device_id_));
-}
-
-void VideoCaptureImpl::OnEncodingCapabilitiesAvailable(
-    const media::VideoEncodingCapabilities& capabilities) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE, base::Bind(
-      &VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread,
-      base::Unretained(this), capabilities));
-}
-
-void VideoCaptureImpl::OnEncodedBitstreamOpened(
-    const media::VideoEncodingParameters& params,
-    const std::vector<base::SharedMemoryHandle>& buffers,
-    uint32 buffer_size) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread,
-                 base::Unretained(this), params, buffers, buffer_size));
-}
-
-void VideoCaptureImpl::OnEncodedBitstreamClosed() {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread,
-                 base::Unretained(this)));
-}
-
-void VideoCaptureImpl::OnEncodingConfigChanged(
-      const media::RuntimeVideoEncodingParameters& params) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(
-          &VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread,
-          base::Unretained(this), params));
-}
-
-void VideoCaptureImpl::OnEncodedBufferReady(
-    int buffer_id,
-    uint32 size,
-    const media::BufferEncodingMetadata& metadata) {
-  capture_message_loop_proxy_->PostTask(FROM_HERE,
-      base::Bind(&VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread,
-                 base::Unretained(this), buffer_id, size, metadata));
-}
-
 void VideoCaptureImpl::FeedBuffer(scoped_refptr<VideoFrameBuffer> buffer) {
   capture_message_loop_proxy_->PostTask(FROM_HERE,
       base::Bind(&VideoCaptureImpl::DoFeedBufferOnCaptureThread,
@@ -397,9 +312,6 @@
 
   switch (state) {
     case VIDEO_CAPTURE_STATE_STARTED:
-      if (!encoding_caps_callback_.is_null()) {
-        StartFetchCapabilities();
-      }
       break;
     case VIDEO_CAPTURE_STATE_STOPPED:
       state_ = VIDEO_CAPTURE_STATE_STOPPED;
@@ -483,118 +395,6 @@
   suspended_ = suspend;
 }
 
-void VideoCaptureImpl::DoRequestCapabilitiesOnCaptureThread(
-    const RequestCapabilitiesCallback& callback) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  DCHECK(encoding_caps_callback_.is_null());
-  encoding_caps_callback_ = callback;
-
-  // Invoke callback immediately if capabilities are already available.
-  if (!encoding_caps_.empty())
-    base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_);
-}
-
-void VideoCaptureImpl::DoOpenBitstreamOnCaptureThread(
-    media::EncodedVideoSource::Client* client,
-    const media::VideoEncodingParameters& params) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  DCHECK(!encoded_video_source_client_);
-  encoded_video_source_client_ = client;
-  Send(new EncodedVideoCaptureHostMsg_OpenBitstream(
-      device_id_, capture_format_.session_id, params));
-}
-
-void VideoCaptureImpl::DoCloseBitstreamOnCaptureThread() {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  DCHECK(bitstream_open_);
-
-  // Immediately clear EVS client pointer and release bitstream buffers if the
-  // client requests to close bitstream. Any further encoded capture messages
-  // from the browser process will be ignored.
-  bitstream_open_ = false;
-  for (size_t i = 0; i < bitstream_buffers_.size(); ++i) {
-    bitstream_buffers_[i]->Close();
-    delete bitstream_buffers_[i];
-  }
-  bitstream_buffers_.clear();
-  encoded_video_source_client_ = NULL;
-
-  Send(new EncodedVideoCaptureHostMsg_CloseBitstream(device_id_));
-}
-
-void VideoCaptureImpl::DoNotifyBitstreamOpenedOnCaptureThread(
-    const media::VideoEncodingParameters& params,
-    const std::vector<base::SharedMemoryHandle>& buffers,
-    uint32 buffer_size) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  DCHECK(!bitstream_open_ && bitstream_buffers_.empty());
-  if (!encoded_video_source_client_)
-    return;
-  bitstream_open_ = true;
-  for (size_t i = 0; i < buffers.size(); ++i) {
-    base::SharedMemory* shm = new base::SharedMemory(buffers[i], true);
-    CHECK(shm->Map(buffer_size));
-    bitstream_buffers_.push_back(shm);
-  }
-  encoded_video_source_client_->OnOpened(params);
-}
-
-void VideoCaptureImpl::DoNotifyBitstreamClosedOnCaptureThread() {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-
-  // Ignore the BitstreamClosed message if bitstream has already been closed
-  // by the EVS client.
-  if (!bitstream_open_)
-    return;
-
-  // The bitstream may still be open when we receive BitstreamClosed message
-  // if the request to close bitstream comes from the browser process.
-  bitstream_open_ = false;
-  for (size_t i = 0; i < bitstream_buffers_.size(); ++i) {
-    bitstream_buffers_[i]->Close();
-    delete bitstream_buffers_[i];
-  }
-  bitstream_buffers_.clear();
-  if (encoded_video_source_client_) {
-    encoded_video_source_client_->OnClosed();
-    encoded_video_source_client_ = NULL;
-  }
-}
-
-void VideoCaptureImpl::DoNotifyBitstreamConfigChangedOnCaptureThread(
-    const media::RuntimeVideoEncodingParameters& params) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  if (!encoded_video_source_client_)
-    return;
-  encoded_video_source_client_->OnConfigChanged(params);
-}
-
-void VideoCaptureImpl::DoNotifyBitstreamBufferReadyOnCaptureThread(
-    int buffer_id,
-    uint32 size,
-    const media::BufferEncodingMetadata& metadata) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  if (!encoded_video_source_client_)
-    return;
-  if (buffer_id >= 0 &&
-      static_cast<size_t>(buffer_id) < bitstream_buffers_.size()) {
-    base::SharedMemory* shm = bitstream_buffers_.at(buffer_id);
-    scoped_refptr<media::EncodedBitstreamBuffer> buffer =
-        new media::EncodedBitstreamBuffer(
-            buffer_id, (uint8*)shm->memory(), size, shm->handle(),
-            metadata, base::Bind(&base::DoNothing));
-    encoded_video_source_client_->OnBufferReady(buffer);
-  }
-}
-
-void VideoCaptureImpl::DoNotifyCapabilitiesAvailableOnCaptureThread(
-    const media::VideoEncodingCapabilities& capabilities) {
-  DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
-  encoding_caps_ = capabilities;
-  if (!encoding_caps_callback_.is_null())
-    base::ResetAndReturn(&encoding_caps_callback_).Run(encoding_caps_);
-}
-
 void VideoCaptureImpl::StopDevice() {
   DCHECK(capture_message_loop_proxy_->BelongsToCurrentThread());
 
diff --git a/content/renderer/media/video_capture_impl.h b/content/renderer/media/video_capture_impl.h
index cd98d01..2ed7717 100644
--- a/content/renderer/media/video_capture_impl.h
+++ b/content/renderer/media/video_capture_impl.h
@@ -38,7 +38,6 @@
 #include "content/renderer/media/video_capture_message_filter.h"
 #include "media/video/capture/video_capture.h"
 #include "media/video/capture/video_capture_types.h"
-#include "media/video/encoded_video_source.h"
 
 namespace base {
 class MessageLoopProxy;
@@ -47,9 +46,7 @@
 namespace content {
 
 class CONTENT_EXPORT VideoCaptureImpl
-    : public media::VideoCapture,
-      public VideoCaptureMessageFilter::Delegate,
-      public media::EncodedVideoSource {
+    : public media::VideoCapture, public VideoCaptureMessageFilter::Delegate {
  public:
   // media::VideoCapture interface.
   virtual void StartCapture(
@@ -72,32 +69,6 @@
   virtual void OnDeviceInfoChanged(
       const media::VideoCaptureParams& device_info) OVERRIDE;
   virtual void OnDelegateAdded(int32 device_id) OVERRIDE;
-  virtual void OnEncodingCapabilitiesAvailable(
-          const media::VideoEncodingCapabilities& capabilities) OVERRIDE;
-  virtual void OnEncodedBitstreamOpened(
-      const media::VideoEncodingParameters& params,
-      const std::vector<base::SharedMemoryHandle>& buffers,
-      uint32 buffer_size) OVERRIDE;
-  virtual void OnEncodedBitstreamClosed() OVERRIDE;
-  virtual void OnEncodingConfigChanged(
-      const media::RuntimeVideoEncodingParameters& params) OVERRIDE;
-  virtual void OnEncodedBufferReady(
-      int buffer_id,
-      uint32 size,
-      const media::BufferEncodingMetadata& metadata) OVERRIDE;
-
-  // media::EncodedVideoSource interface.
-  virtual void RequestCapabilities(
-      const RequestCapabilitiesCallback& callback) OVERRIDE;
-  virtual void OpenBitstream(
-      media::EncodedVideoSource::Client* client,
-      const media::VideoEncodingParameters& params) OVERRIDE;
-  virtual void CloseBitstream() OVERRIDE;
-  virtual void ReturnBitstreamBuffer(
-      scoped_refptr<const media::EncodedBitstreamBuffer> buffer) OVERRIDE;
-  virtual void TrySetBitstreamConfig(
-      const media::RuntimeVideoEncodingParameters& params) OVERRIDE;
-  virtual void RequestKeyFrame() OVERRIDE;
 
   // Stop/resume delivering video frames to clients, based on flag |suspend|.
   virtual void SuspendCapture(bool suspend);
@@ -134,26 +105,6 @@
 
   void DoSuspendCaptureOnCaptureThread(bool suspend);
 
-  void StartFetchCapabilities();
-  void DoRequestCapabilitiesOnCaptureThread(
-      const RequestCapabilitiesCallback& callback);
-  void DoOpenBitstreamOnCaptureThread(
-      media::EncodedVideoSource::Client* client,
-      const media::VideoEncodingParameters& params);
-  void DoCloseBitstreamOnCaptureThread();
-  void DoNotifyBitstreamOpenedOnCaptureThread(
-      const media::VideoEncodingParameters& params,
-      const std::vector<base::SharedMemoryHandle>& buffers,
-      uint32 buffer_size);
-  void DoNotifyBitstreamClosedOnCaptureThread();
-  void DoNotifyBitstreamConfigChangedOnCaptureThread(
-      const media::RuntimeVideoEncodingParameters& params);
-  void DoNotifyBitstreamBufferReadyOnCaptureThread(
-      int buffer_id, uint32 size,
-      const media::BufferEncodingMetadata& metadata);
-  void DoNotifyCapabilitiesAvailableOnCaptureThread(
-      const media::VideoEncodingCapabilities& capabilities);
-
   void Init();
   void DeInit(base::Closure task);
   void DoDeInitOnCaptureThread(base::Closure task);
@@ -196,20 +147,6 @@
   bool suspended_;
   VideoCaptureState state_;
 
-  // Video encoding capabilities as reported by the device.
-  media::VideoEncodingCapabilities encoding_caps_;
-  // Callback for RequestCapabilities().
-  RequestCapabilitiesCallback encoding_caps_callback_;
-  // Pointer to the EVS client.
-  media::EncodedVideoSource::Client* encoded_video_source_client_;
-  // Bitstream buffers returned by the video capture device. Unowned.
-  std::vector<base::SharedMemory*> bitstream_buffers_;
-  // |bitstream_open_| is set to true when renderer receives BitstreamOpened
-  // message acknowledging an OpenBitstream request, and is set to false when
-  // the EVS client requests to close bitstream, or when renderer receives
-  // BitstreamClosed message from the browser procses.
-  bool bitstream_open_;
-
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureImpl);
 };
 
diff --git a/content/renderer/media/video_capture_impl_manager.cc b/content/renderer/media/video_capture_impl_manager.cc
index 3a25378..672fbd4 100644
--- a/content/renderer/media/video_capture_impl_manager.cc
+++ b/content/renderer/media/video_capture_impl_manager.cc
@@ -9,10 +9,6 @@
 #include "content/renderer/media/video_capture_impl.h"
 #include "content/renderer/media/video_capture_message_filter.h"
 
-#if defined(ENABLE_WEBRTC)
-#include "content/renderer/media/rtc_encoding_video_capturer_factory.h"
-#endif
-
 namespace content {
 
 VideoCaptureImplManager::VideoCaptureImplManager()
@@ -34,12 +30,6 @@
         new VideoCaptureImpl(id, message_loop_proxy_.get(), filter_.get());
     devices_[id] = new Device(vc, handler);
     vc->Init();
-
-#if defined(ENABLE_WEBRTC)
-    if (encoding_capturer_factory_)
-      encoding_capturer_factory_->OnEncodedVideoSourceAdded(vc);
-#endif
-
     return vc;
   }
 
@@ -69,11 +59,6 @@
   if (size == it->second->clients.size() || size > 1)
     return;
 
-#if defined(ENABLE_WEBRTC)
-  if (encoding_capturer_factory_)
-    encoding_capturer_factory_->OnEncodedVideoSourceRemoved(devices_[id]->vc);
-#endif
-
   devices_[id]->vc->DeInit(base::Bind(&VideoCaptureImplManager::FreeDevice,
                                       this, devices_[id]->vc));
   delete devices_[id];
diff --git a/content/renderer/media/video_capture_impl_manager.h b/content/renderer/media/video_capture_impl_manager.h
index 9b26b20..e942201 100644
--- a/content/renderer/media/video_capture_impl_manager.h
+++ b/content/renderer/media/video_capture_impl_manager.h
@@ -13,17 +13,14 @@
 #include <list>
 #include <map>
 
-#include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
 #include "base/threading/thread.h"
 #include "base/synchronization/lock.h"
 #include "content/common/content_export.h"
 #include "media/video/capture/video_capture.h"
-#include "media/video/encoded_video_source.h"
 
 namespace content {
 
-class RtcEncodingVideoCapturerFactory;
 class VideoCaptureImpl;
 class VideoCaptureMessageFilter;
 
@@ -53,11 +50,6 @@
     return filter_.get();
   }
 
-  void set_encoding_capturer_factory(base::WeakPtr<
-      RtcEncodingVideoCapturerFactory> encoding_capturer_factory) {
-    encoding_capturer_factory_ = encoding_capturer_factory;
-  }
-
  protected:
   virtual ~VideoCaptureImplManager();
 
@@ -82,12 +74,6 @@
   base::Thread thread_;
   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
 
-  // The encoding capturer factory is created by MediaStreamDependencyFactory
-  // and owned by its PeerConnectionFactory. It is passed to the manager
-  // as a weak pointer at CreatePeerConnectionFactory time because the
-  // PeerConnectionFactory may be released earlier than the manager.
-  base::WeakPtr<RtcEncodingVideoCapturerFactory> encoding_capturer_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureImplManager);
 };
 
diff --git a/content/renderer/media/video_capture_impl_unittest.cc b/content/renderer/media/video_capture_impl_unittest.cc
index 440d330..7d347e5 100644
--- a/content/renderer/media/video_capture_impl_unittest.cc
+++ b/content/renderer/media/video_capture_impl_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "base/message_loop/message_loop.h"
 #include "content/child/child_process.h"
-#include "content/common/media/encoded_video_capture_messages.h"
 #include "content/common/media/video_capture_messages.h"
 #include "content/renderer/media/video_capture_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -75,18 +74,6 @@
         IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_Stop, DeviceStopCapture)
         IPC_MESSAGE_HANDLER(VideoCaptureHostMsg_BufferReady,
                             DeviceReceiveEmptyBuffer)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_GetCapabilities,
-                            DeviceGetEncodingCapabilities)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_OpenBitstream,
-                            DeviceOpenEncodedBitstream)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_CloseBitstream,
-                            DeviceCloseEncodedBitstream)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_TryConfigureBitstream,
-                            DeviceSetEncodingConfig)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_RequestKeyFrame,
-                            DeviceRequestKeyFrame)
-        IPC_MESSAGE_HANDLER(EncodedVideoCaptureHostMsg_BitstreamBufferConsumed,
-                            DeviceReturnEncodedBuffer)
         IPC_MESSAGE_UNHANDLED(handled = false)
       IPC_END_MESSAGE_MAP()
       EXPECT_TRUE(handled);
@@ -107,22 +94,6 @@
     }
 
     void DeviceReceiveEmptyBuffer(int device_id, int buffer_id) {}
-
-    void DeviceGetEncodingCapabilities(
-        int device_id, media::VideoCaptureSessionId session_id) {}
-
-    void DeviceOpenEncodedBitstream(int device_id,
-                                    media::VideoCaptureSessionId session_id,
-                                    media::VideoEncodingParameters params) {}
-
-    void DeviceCloseEncodedBitstream(int device_id) {}
-
-    void DeviceSetEncodingConfig(
-        int device_id, media::RuntimeVideoEncodingParameters params) {}
-
-    void DeviceRequestKeyFrame(int device_id) {}
-
-    void DeviceReturnEncodedBuffer(int device_id, int buffer_id) {}
   };
 
   VideoCaptureImplTest()
diff --git a/content/renderer/media/video_capture_message_filter.cc b/content/renderer/media/video_capture_message_filter.cc
index 04c79ab..0ef77fa 100644
--- a/content/renderer/media/video_capture_message_filter.cc
+++ b/content/renderer/media/video_capture_message_filter.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/media/video_capture_message_filter.h"
 
-#include "content/common/media/encoded_video_capture_messages.h"
 #include "content/common/media/video_capture_messages.h"
 #include "content/common/view_messages.h"
 
@@ -62,18 +61,7 @@
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_StateChanged, OnDeviceStateChanged)
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_NewBuffer, OnBufferCreated)
     IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfo, OnDeviceInfoReceived)
-    IPC_MESSAGE_HANDLER(VideoCaptureMsg_DeviceInfoChanged, OnDeviceInfoChanged)
-    IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_CapabilitiesAvailable,
-                        OnCapabilitiesAvailable)
-    IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamOpened,
-                        OnBitstreamOpened)
-    IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamClosed,
-                        OnBitstreamClosed)
-    IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamConfigChanged,
-                        OnBitstreamConfigChanged)
-    IPC_MESSAGE_HANDLER(EncodedVideoCaptureMsg_BitstreamReady,
-                        OnBitstreamReady);
-  IPC_MESSAGE_UNHANDLED(handled = false)
+    IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
 }
@@ -170,76 +158,4 @@
   delegate->OnDeviceInfoReceived(params);
 }
 
-void VideoCaptureMessageFilter::OnDeviceInfoChanged(
-    int device_id,
-    const media::VideoCaptureParams& params) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnDeviceInfoChanged: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnDeviceInfoChanged(params);
-}
-
-void VideoCaptureMessageFilter::OnCapabilitiesAvailable(
-    int device_id,
-    media::VideoEncodingCapabilities capabilities) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnCapabilitiesAvailable: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnEncodingCapabilitiesAvailable(capabilities);
-}
-
-void VideoCaptureMessageFilter::OnBitstreamOpened(
-    int device_id,
-    media::VideoEncodingParameters params,
-    std::vector<base::SharedMemoryHandle> buffers,
-    uint32 buffer_size) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnBitstreamOpened: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnEncodedBitstreamOpened(params, buffers, buffer_size);
-}
-
-void VideoCaptureMessageFilter::OnBitstreamClosed(int device_id) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnBitstreamClosed: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnEncodedBitstreamClosed();
-}
-
-void VideoCaptureMessageFilter::OnBitstreamConfigChanged(
-    int device_id,
-    media::RuntimeVideoEncodingParameters params) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnBitstreamConfigChanged: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnEncodingConfigChanged(params);
-}
-
-void VideoCaptureMessageFilter::OnBitstreamReady(
-    int device_id, int buffer_id, uint32 size,
-    media::BufferEncodingMetadata metadata) {
-  Delegate* delegate = find_delegate(device_id);
-  if (!delegate) {
-    DLOG(WARNING) << "OnBitstreamReady: Got video capture event for a "
-        "non-existent or removed video capture.";
-    return;
-  }
-  delegate->OnEncodedBufferReady(buffer_id, size, metadata);
-}
-
 }  // namespace content
diff --git a/content/renderer/media/video_capture_message_filter.h b/content/renderer/media/video_capture_message_filter.h
index ede6ab6..013e2d0 100644
--- a/content/renderer/media/video_capture_message_filter.h
+++ b/content/renderer/media/video_capture_message_filter.h
@@ -18,7 +18,6 @@
 #include "content/common/media/video_capture.h"
 #include "ipc/ipc_channel_proxy.h"
 #include "media/video/capture/video_capture.h"
-#include "media/video/encoded_video_source.h"
 
 namespace content {
 
@@ -52,31 +51,6 @@
     // |device_id| is the device id for the delegate.
     virtual void OnDelegateAdded(int32 device_id) = 0;
 
-    // Called when the encoding capabilities is received from video capture
-    // device in the browser process.
-    virtual void OnEncodingCapabilitiesAvailable(
-        const media::VideoEncodingCapabilities& capabilities) = 0;
-
-    // Called when a bitstream is opened on a video capture device.
-    virtual void OnEncodedBitstreamOpened(
-        const media::VideoEncodingParameters& params,
-        const std::vector<base::SharedMemoryHandle>& buffers,
-        uint32 buffer_size) = 0;
-
-    // Called when a bitstream is closed on a video capture device.
-    virtual void OnEncodedBitstreamClosed() = 0;
-
-    // Called when encoding parameters has changed.
-    virtual void OnEncodingConfigChanged(
-        const media::RuntimeVideoEncodingParameters& params) = 0;
-
-    // Called when an encoded bitstream buffer is received from video capture
-    // device in the browser process.
-    virtual void OnEncodedBufferReady(
-        int buffer_id,
-        uint32 size,
-        const media::BufferEncodingMetadata& metadata) = 0;
-
    protected:
     virtual ~Delegate() {}
   };
@@ -123,31 +97,6 @@
   void OnDeviceInfoReceived(int device_id,
                             const media::VideoCaptureParams& params);
 
-  // Receive newly changed device info from browser process.
-  void OnDeviceInfoChanged(int device_id,
-                           const media::VideoCaptureParams& params);
-
-  // Receive encoding capabilities from browser process.
-  void OnCapabilitiesAvailable(int device_id,
-                               media::VideoEncodingCapabilities capabilities);
-
-  // Bitstream is opened on video capture device.
-  void OnBitstreamOpened(int device_id,
-                         media::VideoEncodingParameters params,
-                         std::vector<base::SharedMemoryHandle> buffers,
-                         uint32 buffer_size);
-
-  // Bitstream is closed on video capture device.
-  void OnBitstreamClosed(int device_id);
-
-  // Receive current encoding parameters from browser process.
-  void OnBitstreamConfigChanged(int device_id,
-                                media::RuntimeVideoEncodingParameters params);
-
-  // Receive an encoded bitstream buffer from browser process.
-  void OnBitstreamReady(int device_id, int buffer_id, uint32 size,
-                        media::BufferEncodingMetadata metadata);
-
   // Finds the delegate associated with |device_id|, NULL if not found.
   Delegate* find_delegate(int device_id) const;
 
diff --git a/content/renderer/media/video_capture_message_filter_unittest.cc b/content/renderer/media/video_capture_message_filter_unittest.cc
index 5b4c194..222600a 100644
--- a/content/renderer/media/video_capture_message_filter_unittest.cc
+++ b/content/renderer/media/video_capture_message_filter_unittest.cc
@@ -50,21 +50,6 @@
     device_id_ = device_id;
   }
 
-  // TODO(hshi): implement the following methods for encoded video capture.
-  virtual void OnEncodingCapabilitiesAvailable(
-      const media::VideoEncodingCapabilities& capabilities) OVERRIDE {}
-  virtual void OnEncodedBitstreamOpened(
-      const media::VideoEncodingParameters& params,
-      const std::vector<base::SharedMemoryHandle>& buffers,
-      uint32 buffer_size) OVERRIDE {}
-  virtual void OnEncodedBitstreamClosed() OVERRIDE {}
-  virtual void OnEncodingConfigChanged(
-      const media::RuntimeVideoEncodingParameters& params) OVERRIDE {}
-  virtual void OnEncodedBufferReady(
-      int buffer_id,
-      uint32 size,
-      const media::BufferEncodingMetadata& metadata) OVERRIDE {}
-
   void Reset() {
     buffer_created_ = false;
     handle_ = base::SharedMemory::NULLHandle();
diff --git a/content/renderer/media/webrtc_audio_capturer.cc b/content/renderer/media/webrtc_audio_capturer.cc
index 90e2482..238b2a2 100644
--- a/content/renderer/media/webrtc_audio_capturer.cc
+++ b/content/renderer/media/webrtc_audio_capturer.cc
@@ -10,29 +10,31 @@
 #include "base/strings/string_util.h"
 #include "content/child/child_process.h"
 #include "content/renderer/media/audio_device_factory.h"
-#include "content/renderer/media/webrtc_audio_capturer_sink_owner.h"
 #include "content/renderer/media/webrtc_audio_device_impl.h"
+#include "content/renderer/media/webrtc_local_audio_track.h"
 #include "media/audio/audio_util.h"
 #include "media/audio/sample_rates.h"
 
 namespace content {
 
+namespace {
+
 // Supported hardware sample rates for input and output sides.
 #if defined(OS_WIN) || defined(OS_MACOSX)
 // media::GetAudioInputHardwareSampleRate() asks the audio layer
 // for its current sample rate (set by the user) on Windows and Mac OS X.
 // The listed rates below adds restrictions and WebRtcAudioDeviceImpl::Init()
 // will fail if the user selects any rate outside these ranges.
-static int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000};
+const int kValidInputRates[] = {96000, 48000, 44100, 32000, 16000, 8000};
 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
-static int kValidInputRates[] = {48000, 44100};
+const int kValidInputRates[] = {48000, 44100};
 #elif defined(OS_ANDROID)
-static int kValidInputRates[] = {48000, 44100};
+const int kValidInputRates[] = {48000, 44100};
 #else
-static int kValidInputRates[] = {44100};
+const int kValidInputRates[] = {44100};
 #endif
 
-static int GetBufferSizeForSampleRate(int sample_rate) {
+int GetBufferSizeForSampleRate(int sample_rate) {
   int buffer_size = 0;
 #if defined(OS_WIN) || defined(OS_MACOSX)
   // Use a buffer size of 10ms.
@@ -49,6 +51,8 @@
   return buffer_size;
 }
 
+}  // namespace
+
 // This is a temporary audio buffer with parameters used to send data to
 // callbacks.
 class WebRtcAudioCapturer::ConfiguredBuffer :
@@ -87,6 +91,68 @@
   media::AudioParameters params_;
 };
 
+// Reference counted container of WebRtcLocalAudioTrack delegate.
+class WebRtcAudioCapturer::TrackOwner
+    : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> {
+ public:
+  explicit TrackOwner(WebRtcLocalAudioTrack* track)
+      : delegate_(track) {}
+
+  void CaptureData(const int16* audio_data,
+                   int number_of_channels,
+                   int number_of_frames,
+                   int audio_delay_milliseconds,
+                   int volume) {
+    base::AutoLock lock(lock_);
+    if (delegate_) {
+      delegate_->CaptureData(audio_data,
+                             number_of_channels,
+                             number_of_frames,
+                             audio_delay_milliseconds,
+                             volume);
+    }
+  }
+
+  void SetCaptureFormat(const media::AudioParameters& params) {
+    base::AutoLock lock(lock_);
+    if (delegate_)
+      delegate_->SetCaptureFormat(params);
+  }
+
+  void Reset() {
+    base::AutoLock lock(lock_);
+    delegate_ = NULL;
+  }
+
+  // Wrapper which allows to use std::find_if() when adding and removing
+  // sinks to/from the list.
+  struct TrackWrapper {
+    TrackWrapper(WebRtcLocalAudioTrack* track) : track_(track) {}
+    bool operator()(
+        const scoped_refptr<WebRtcAudioCapturer::TrackOwner>& owner) {
+      return owner->IsEqual(track_);
+    }
+    WebRtcLocalAudioTrack* track_;
+  };
+
+ protected:
+  virtual ~TrackOwner() {}
+
+ private:
+  friend class base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner>;
+
+  bool IsEqual(const WebRtcLocalAudioTrack* other) const {
+    base::AutoLock lock(lock_);
+    return (other == delegate_);
+  }
+
+  // Do NOT reference count the |delegate_| to avoid cyclic reference counting.
+  WebRtcLocalAudioTrack* delegate_;
+  mutable base::Lock lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrackOwner);
+};
+
 // static
 scoped_refptr<WebRtcAudioCapturer> WebRtcAudioCapturer::CreateCapturer() {
   scoped_refptr<WebRtcAudioCapturer> capturer = new WebRtcAudioCapturer();
@@ -118,7 +184,8 @@
 bool WebRtcAudioCapturer::Initialize(int render_view_id,
                                      media::ChannelLayout channel_layout,
                                      int sample_rate,
-                                     int session_id) {
+                                     int session_id,
+                                     const std::string& device_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "WebRtcAudioCapturer::Initialize()";
 
@@ -127,6 +194,14 @@
                             channel_layout, media::CHANNEL_LAYOUT_MAX);
 
   session_id_ = session_id;
+  device_id_ = device_id;
+  if (render_view_id == -1) {
+    // This capturer is used by WebAudio, return true without creating a
+    // default capturing source. WebAudio will inject its own source via
+    // SetCapturerSource() at a later state.
+    DCHECK(device_id.empty());
+    return true;
+  }
 
   // Verify that the reported input channel configuration is supported.
   if (channel_layout != media::CHANNEL_LAYOUT_MONO &&
@@ -169,11 +244,11 @@
 }
 
 WebRtcAudioCapturer::WebRtcAudioCapturer()
-    : default_sink_(NULL),
-      source_(NULL),
+    : source_(NULL),
       running_(false),
       agc_is_enabled_(false),
-      session_id_(0) {
+      session_id_(0),
+      volume_(0) {
   DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()";
 }
 
@@ -181,66 +256,39 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(tracks_.empty());
   DCHECK(!running_);
-  DCHECK(!default_sink_);
   DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()";
 }
 
-void WebRtcAudioCapturer::SetDefaultSink(WebRtcAudioCapturerSink* sink) {
-  DVLOG(1) << "WebRtcAudioCapturer::SetDefaultSink()";
-  if (sink) {
-    DCHECK(!default_sink_);
-    default_sink_ = sink;
-    AddSink(sink);
-  } else {
-    DCHECK(default_sink_);
-    RemoveSink(default_sink_);
-    default_sink_ = NULL;
-  }
-}
-
-void WebRtcAudioCapturer::AddSink(WebRtcAudioCapturerSink* track) {
+void WebRtcAudioCapturer::AddTrack(WebRtcLocalAudioTrack* track) {
   DCHECK(track);
-  DVLOG(1) << "WebRtcAudioCapturer::AddSink()";
+  DVLOG(1) << "WebRtcAudioCapturer::AddTrack()";
 
-  // Start the source if an audio track is connected to the capturer.
-  // |default_sink_| is not an audio track.
-  if (track != default_sink_)
-    Start();
+  // Start the source if the first audio track is connected to the capturer.
+  // Start() will do nothing if the capturer has already been started.
+  Start();
 
   base::AutoLock auto_lock(lock_);
   // Verify that |track| is not already added to the list.
-  DCHECK(std::find_if(
-      tracks_.begin(), tracks_.end(),
-      WebRtcAudioCapturerSinkOwner::WrapsSink(track)) == tracks_.end());
+  DCHECK(std::find_if(tracks_.begin(), tracks_.end(),
+                      TrackOwner::TrackWrapper(track)) == tracks_.end());
 
   if (buffer_.get()) {
     track->SetCaptureFormat(buffer_->params());
-  } else {
-    DLOG(WARNING) << "The format of the capturer has not been correctly "
-                  <<  "initialized";
   }
 
-  // Create (and add to the list) a new WebRtcAudioCapturerSinkOwner which owns
-  // the |track| and delagates all calls to the WebRtcAudioCapturerSink
-  // interface.
-  tracks_.push_back(new WebRtcAudioCapturerSinkOwner(track));
-  // TODO(xians): should we call SetCapturerFormat() to each track?
+  tracks_.push_back(new WebRtcAudioCapturer::TrackOwner(track));
 }
 
-void WebRtcAudioCapturer::RemoveSink(
-    WebRtcAudioCapturerSink* track) {
+void WebRtcAudioCapturer::RemoveTrack(WebRtcLocalAudioTrack* track) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DVLOG(1) << "WebRtcAudioCapturer::RemoveSink()";
 
   bool stop_source = false;
   {
     base::AutoLock auto_lock(lock_);
-
     // Get iterator to the first element for which WrapsSink(track) returns
     // true.
     TrackList::iterator it = std::find_if(
-        tracks_.begin(), tracks_.end(),
-        WebRtcAudioCapturerSinkOwner::WrapsSink(track));
+        tracks_.begin(), tracks_.end(), TrackOwner::TrackWrapper(track));
     if (it != tracks_.end()) {
       // Clear the delegate to ensure that no more capture callbacks will
       // be sent to this sink. Also avoids a possible crash which can happen
@@ -250,16 +298,7 @@
     }
 
     // Stop the source if the last audio track is going away.
-    // The |tracks_| might contain the |default_sink_|, we need to stop the
-    // source if the only remaining element is |default_sink_|.
-    if (tracks_.size() == 1 && default_sink_ &&
-        (*tracks_.begin())->IsEqual(default_sink_)) {
-      stop_source = true;
-    } else {
-      // The source might have been stopped, but it is safe to call Stop()
-      // again to make sure the source is stopped correctly.
-      stop_source = tracks_.empty();
-    }
+    stop_source = tracks_.empty();
   }
 
   if (stop_source)
@@ -355,11 +394,22 @@
     source->Stop();
 }
 
-void WebRtcAudioCapturer::SetVolume(double volume) {
+void WebRtcAudioCapturer::SetVolume(int volume) {
   DVLOG(1) << "WebRtcAudioCapturer::SetVolume()";
+  DCHECK_LE(volume, MaxVolume());
+  double normalized_volume = static_cast<double>(volume) / MaxVolume();
   base::AutoLock auto_lock(lock_);
   if (source_.get())
-    source_->SetVolume(volume);
+    source_->SetVolume(normalized_volume);
+}
+
+int WebRtcAudioCapturer::Volume() const {
+  base::AutoLock auto_lock(lock_);
+  return volume_;
+}
+
+int WebRtcAudioCapturer::MaxVolume() const {
+  return WebRtcAudioDeviceImpl::kMaxVolumeLevel;
 }
 
 void WebRtcAudioCapturer::SetAutomaticGainControl(bool enable) {
@@ -378,6 +428,17 @@
   // This callback is driven by AudioInputDevice::AudioThreadCallback if
   // |source_| is AudioInputDevice, otherwise it is driven by client's
   // CaptureCallback.
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  DCHECK_LE(volume, 1.0);
+#elif defined(OS_LINUX) || defined(OS_OPENBSD)
+  // We have a special situation on Linux where the microphone volume can be
+  // "higher than maximum". The input volume slider in the sound preference
+  // allows the user to set a scaling that is higher than 100%. It means that
+  // even if the reported maximum levels is N, the actual microphone level can
+  // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
+  DCHECK_LE(volume, 1.6);
+#endif
+
   TrackList tracks;
   scoped_refptr<ConfiguredBuffer> buffer_ref_while_calling;
   {
@@ -385,6 +446,11 @@
     if (!running_)
       return;
 
+    // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
+    // webrtc::VoiceEngine. webrtc::VoiceEngine will handle the case when the
+    // volume is higher than 255.
+    volume_ = static_cast<int>((volume * MaxVolume()) + 0.5);
+
     // Copy the stuff we will need to local variables. In particular, we grab
     // a reference to the buffer so we can ensure it stays alive even if the
     // buffer is reconfigured while we are calling back.
@@ -406,7 +472,7 @@
        ++it) {
     (*it)->CaptureData(buffer_ref_while_calling->buffer(),
                        audio_source->channels(), audio_source->frames(),
-                       audio_delay_milliseconds, volume);
+                       audio_delay_milliseconds, volume_);
   }
 }
 
diff --git a/content/renderer/media/webrtc_audio_capturer.h b/content/renderer/media/webrtc_audio_capturer.h
index dfadb56..e85ea04 100644
--- a/content/renderer/media/webrtc_audio_capturer.h
+++ b/content/renderer/media/webrtc_audio_capturer.h
@@ -22,9 +22,8 @@
 
 namespace content {
 
-class WebRtcAudioCapturerSink;
-class WebRtcAudioCapturerSinkOwner;
 class WebRtcLocalAudioRenderer;
+class WebRtcLocalAudioTrack;
 
 // This class manages the capture data flow by getting data from its
 // |source_|, and passing it to its |tracks_|.
@@ -46,31 +45,24 @@
   // Creates and configures the default audio capturing source using the
   // provided audio parameters.  |render_view_id| specifies the render view
   // consuming audio for capture.  |session_id| is passed to the browser to
-  // decide which device to use.  Called on the main render thread.
+  // decide which device to use.  |device_id| is used to identify which device
+  // the capturer is created for.  Called on the main render thread.
   bool Initialize(int render_view_id,
                   media::ChannelLayout channel_layout,
                   int sample_rate,
-                  int session_id);
-
-  // Called by the WebRtcAudioDeviceImpl to add the ADM as the default sink to
-  // the capturer. This function is needed since WebRTC supports only one ADM
-  // but multiple audio tracks, so the ADM can't be the sink of certain audio
-  // track now. And we also need to distinguish the WebRtcAudioDeviceImpl from
-  // the audio track in order to start/stop the source of the capturer
-  // correctly.
-  // TODO(xians): Remove this function after WebRtc supports multiple ADMs.
-  void SetDefaultSink(WebRtcAudioCapturerSink* sink);
+                  int session_id,
+                  const std::string& device_id);
 
   // Add a audio track to the sinks of the capturer.
   // WebRtcAudioDeviceImpl calls this method on the main render thread but
   // other clients may call it from other threads. The current implementation
   // does not support multi-thread calling.
   // Called on the main render thread or libjingle working thread.
-  void AddSink(WebRtcAudioCapturerSink* track);
+  void AddTrack(WebRtcLocalAudioTrack* track);
 
   // Remove a audio track from the sinks of the capturer.
   // Called on the main render thread or libjingle working thread.
-  void RemoveSink(WebRtcAudioCapturerSink* track);
+  void RemoveTrack(WebRtcLocalAudioTrack* track);
 
   // SetCapturerSource() is called if the client on the source side desires to
   // provide their own captured audio data. Client is responsible for calling
@@ -81,9 +73,11 @@
       media::ChannelLayout channel_layout,
       float sample_rate);
 
-  // Sets the microphone volume.
+  // Volume APIs used by WebRtcAudioDeviceImpl.
   // Called on the AudioInputDevice audio thread.
-  void SetVolume(double volume);
+  void SetVolume(int volume);
+  int Volume() const;
+  int MaxVolume() const;
 
   // Enables or disables the WebRtc AGC control.
   // Called from a Libjingle working thread.
@@ -99,13 +93,16 @@
   // of this accessor and if we can remove it.
   media::AudioParameters audio_parameters() const;
 
+  const std::string& device_id() const { return device_id_; }
+
  protected:
   friend class base::RefCountedThreadSafe<WebRtcAudioCapturer>;
   WebRtcAudioCapturer();
   virtual ~WebRtcAudioCapturer();
 
  private:
-  typedef std::list<scoped_refptr<WebRtcAudioCapturerSinkOwner> > TrackList;
+  class TrackOwner;
+  typedef std::list<scoped_refptr<TrackOwner> > TrackList;
 
   // AudioCapturerSource::CaptureCallback implementation.
   // Called on the AudioInputDevice audio thread.
@@ -139,10 +136,6 @@
   // A list of audio tracks that the audio data is fed to.
   TrackList tracks_;
 
-  // A pointer to WebRtcAudioDeviceImpl which is the default destination of
-  // all the audio tracks data flow.
-  WebRtcAudioCapturerSink* default_sink_;
-
   // The audio data source from the browser process.
   scoped_refptr<media::AudioCapturerSource> source_;
 
@@ -155,9 +148,17 @@
   // True when automatic gain control is enabled, false otherwise.
   bool agc_is_enabled_;
 
-  // The media session ID used to identify which input device to be started.
+  // The media session ID used to identify which input device to be started by
+  // the browser.
   int session_id_;
 
+  // The device this capturer is given permission to use.
+  std::string device_id_;
+
+  // Stores latest microphone volume received in a CaptureData() callback.
+  // Range is [0, 255].
+  int volume_;
+
   DISALLOW_COPY_AND_ASSIGN(WebRtcAudioCapturer);
 };
 
diff --git a/content/renderer/media/webrtc_audio_capturer_sink_owner.cc b/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
index ab0c3d3..cb6a813 100644
--- a/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
+++ b/content/renderer/media/webrtc_audio_capturer_sink_owner.cc
@@ -11,14 +11,23 @@
     : delegate_(sink) {
 }
 
-void WebRtcAudioCapturerSinkOwner::CaptureData(
-    const int16* audio_data, int number_of_channels, int number_of_frames,
-    int audio_delay_milliseconds, double volume) {
+int WebRtcAudioCapturerSinkOwner::CaptureData(const std::vector<int>& channels,
+                                              const int16* audio_data,
+                                              int sample_rate,
+                                              int number_of_channels,
+                                              int number_of_frames,
+                                              int audio_delay_milliseconds,
+                                              int current_volume,
+                                              bool need_audio_processing) {
   base::AutoLock lock(lock_);
   if (delegate_) {
-    delegate_->CaptureData(audio_data, number_of_channels, number_of_frames,
-                           audio_delay_milliseconds, volume);
+    return delegate_->CaptureData(channels, audio_data, sample_rate,
+                                  number_of_channels, number_of_frames,
+                                  audio_delay_milliseconds, current_volume,
+                                  need_audio_processing);
   }
+
+  return 0;
 }
 
 void WebRtcAudioCapturerSinkOwner::SetCaptureFormat(
diff --git a/content/renderer/media/webrtc_audio_capturer_sink_owner.h b/content/renderer/media/webrtc_audio_capturer_sink_owner.h
index dd6264f..a3641b8 100644
--- a/content/renderer/media/webrtc_audio_capturer_sink_owner.h
+++ b/content/renderer/media/webrtc_audio_capturer_sink_owner.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_RENDERER_MEDIA_WEBRTC_AUDIO_CAPTURER_SINK_OWNER_H_
 #define CONTENT_RENDERER_MEDIA_WEBRTC_AUDIO_CAPTURER_SINK_OWNER_H_
 
-#include <list>
+#include <vector>
 
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
@@ -24,11 +24,15 @@
   explicit WebRtcAudioCapturerSinkOwner(WebRtcAudioCapturerSink* sink);
 
   // WebRtcAudioCapturerSink implementation.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) OVERRIDE;
+  virtual int CaptureData(const std::vector<int>& channels,
+                          const int16* audio_data,
+                          int sample_rate,
+                          int number_of_channels,
+                          int number_of_frames,
+                          int audio_delay_milliseconds,
+                          int current_volume,
+                          bool need_audio_processing) OVERRIDE;
+
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
 
   bool IsEqual(const WebRtcAudioCapturerSink* other) const;
diff --git a/content/renderer/media/webrtc_audio_device_impl.cc b/content/renderer/media/webrtc_audio_device_impl.cc
index 2672a27..c40e0a2 100644
--- a/content/renderer/media/webrtc_audio_device_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_impl.cc
@@ -20,12 +20,6 @@
 
 namespace content {
 
-namespace {
-
-const double kMaxVolumeLevel = 255.0;
-
-}  // namespace
-
 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl()
     : ref_count_(0),
       audio_transport_callback_(NULL),
@@ -58,98 +52,64 @@
   }
   return ret;
 }
-
-void WebRtcAudioDeviceImpl::CaptureData(const int16* audio_data,
-                                        int number_of_channels,
-                                        int number_of_frames,
-                                        int audio_delay_milliseconds,
-                                        double volume) {
-  DCHECK_LE(number_of_frames, input_buffer_size());
-#if defined(OS_WIN) || defined(OS_MACOSX)
-  DCHECK_LE(volume, 1.0);
-#elif defined(OS_LINUX) || defined(OS_OPENBSD)
-  // We have a special situation on Linux where the microphone volume can be
-  // "higher than maximum". The input volume slider in the sound preference
-  // allows the user to set a scaling that is higher than 100%. It means that
-  // even if the reported maximum levels is N, the actual microphone level can
-  // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x.
-  DCHECK_LE(volume, 1.6);
-#endif
-
-  media::AudioParameters input_audio_parameters;
-  int output_delay_ms = 0;
+int WebRtcAudioDeviceImpl::CaptureData(const std::vector<int>& channels,
+                                       const int16* audio_data,
+                                       int sample_rate,
+                                       int number_of_channels,
+                                       int number_of_frames,
+                                       int audio_delay_milliseconds,
+                                       int current_volume,
+                                       bool need_audio_processing) {
+  int total_delay_ms = 0;
   {
     base::AutoLock auto_lock(lock_);
     if (!recording_)
-      return;
-
-    // Take a copy of the input parameters while we are under a lock.
-    input_audio_parameters = input_audio_parameters_;
+      return 0;
 
     // Store the reported audio delay locally.
     input_delay_ms_ = audio_delay_milliseconds;
-    output_delay_ms = output_delay_ms_;
+    total_delay_ms = input_delay_ms_ + output_delay_ms_;
     DVLOG(2) << "total delay: " << input_delay_ms_ + output_delay_ms_;
-
-    // Map internal volume range of [0.0, 1.0] into [0, 255] used by the
-    // webrtc::VoiceEngine.
-    microphone_volume_ = static_cast<uint32_t>(volume * kMaxVolumeLevel);
   }
 
-  const int channels = number_of_channels;
-  DCHECK_LE(channels, input_channels());
-  uint32_t new_mic_level = 0;
-
-  int samples_per_sec = input_sample_rate();
-  const int samples_per_10_msec = (samples_per_sec / 100);
-  int bytes_per_sample = input_audio_parameters.bits_per_sample() / 8;
-  const int bytes_per_10_msec =
-      channels * samples_per_10_msec * bytes_per_sample;
-  int accumulated_audio_samples = 0;
-
-  const uint8* audio_byte_buffer = reinterpret_cast<const uint8*>(audio_data);
-
   // Write audio samples in blocks of 10 milliseconds to the registered
   // webrtc::AudioTransport sink. Keep writing until our internal byte
   // buffer is empty.
   // TODO(niklase): Wire up the key press detection.
+  const int16* audio_buffer = audio_data;
+  const int samples_per_10_msec = (sample_rate / 100);
+  int accumulated_audio_samples = 0;
   bool key_pressed = false;
+  uint32_t new_volume = 0;
   while (accumulated_audio_samples < number_of_frames) {
     // Deliver 10ms of recorded 16-bit linear PCM audio.
-    audio_transport_callback_->RecordedDataIsAvailable(
-        audio_byte_buffer,
+    int new_mic_level = audio_transport_callback_->OnDataAvailable(
+        &channels[0],
+        channels.size(),
+        audio_buffer,
+        sample_rate,
+        number_of_channels,
         samples_per_10_msec,
-        bytes_per_sample,
-        channels,
-        samples_per_sec,
-        input_delay_ms_ + output_delay_ms,
-        0,  // TODO(henrika): |clock_drift| parameter is not utilized today.
-        microphone_volume_,
+        total_delay_ms,
+        current_volume,
         key_pressed,
-        new_mic_level);
+        need_audio_processing);
 
     accumulated_audio_samples += samples_per_10_msec;
-    audio_byte_buffer += bytes_per_10_msec;
+    audio_buffer += samples_per_10_msec * number_of_channels;
+
+    // The latest non-zero new microphone level will be returned.
+    if (new_mic_level)
+      new_volume = new_mic_level;
   }
 
-  // The AGC returns a non-zero microphone level if it has been decided
-  // that a new level should be set.
-  if (new_mic_level != 0) {
-    // Use IPC and set the new level. Note that, it will take some time
-    // before the new level is effective due to the IPC scheme.
-    // During this time, |current_mic_level| will contain "non-valid" values
-    // and it might reduce the AGC performance. Measurements on Windows 7 have
-    // shown that we might receive old volume levels for one or two callbacks.
-    SetMicrophoneVolume(new_mic_level);
-  }
+  return new_volume;
 }
 
 void WebRtcAudioDeviceImpl::SetCaptureFormat(
     const media::AudioParameters& params) {
   DVLOG(1) << "WebRtcAudioDeviceImpl::SetCaptureFormat()";
   DCHECK(thread_checker_.CalledOnValidThread());
-  base::AutoLock auto_lock(lock_);
-  input_audio_parameters_ = params;
 }
 
 void WebRtcAudioDeviceImpl::RenderData(uint8* audio_data,
@@ -217,19 +177,6 @@
   DVLOG(1) << "WebRtcAudioDeviceImpl::Init()";
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  if (initialized_)
-    return 0;
-
-  DCHECK(!capturer_.get());
-  capturer_ = WebRtcAudioCapturer::CreateCapturer();
-
-  // Add itself as an audio track to the |capturer_|. This is because WebRTC
-  // supports only one ADM but multiple audio tracks, so the ADM can't be the
-  // sink of certain audio track now.
-  // TODO(xians): Register the ADM as the sink of the audio track if WebRTC
-  // supports one ADM for each audio track. See http://crbug/247027.
-  capturer_->SetDefaultSink(this);
-
   // We need to return a success to continue the initialization of WebRtc VoE
   // because failure on the capturer_ initialization should not prevent WebRTC
   // from working. See issue http://crbug.com/144421 for details.
@@ -258,12 +205,7 @@
     DCHECK(!renderer_.get());
   }
 
-  if (capturer_.get()) {
-    // |capturer_| is stopped by the media stream, so do not need to
-    // call Stop() here.
-    capturer_->SetDefaultSink(NULL);
-    capturer_ = NULL;
-  }
+  capturers_.clear();
 
   initialized_ = false;
   return 0;
@@ -283,14 +225,14 @@
 }
 
 int32_t WebRtcAudioDeviceImpl::RecordingIsAvailable(bool* available) {
-  *available = (capturer_.get() != NULL);
+  *available = (!capturers_.empty());
   return 0;
 }
 
 bool WebRtcAudioDeviceImpl::RecordingIsInitialized() const {
   DVLOG(1) << "WebRtcAudioDeviceImpl::RecordingIsInitialized()";
   DCHECK(thread_checker_.CalledOnValidThread());
-  return (capturer_.get() != NULL);
+  return (!capturers_.empty());
 }
 
 int32_t WebRtcAudioDeviceImpl::StartPlayout() {
@@ -389,13 +331,17 @@
   if (enable == agc_is_enabled_)
     return 0;
 
+  // Set the AGC on all the capturers. It depends on the source of the
+  // capturer whether AGC is supported or not.
   // The current implementation does not support changing the AGC state while
   // recording. Using this approach simplifies the design and it is also
-  // inline with the  latest WebRTC standard.
-  if (!capturer_.get() || capturer_->is_recording())
-    return -1;
+  // inline with the latest WebRTC standard.
+  for (CapturerList::const_iterator iter = capturers_.begin();
+       iter != capturers_.end(); ++iter) {
+    if (!(*iter)->is_recording())
+      (*iter)->SetAutomaticGainControl(enable);
+  }
 
-  capturer_->SetAutomaticGainControl(enable);
   agc_is_enabled_ = enable;
   return 0;
 }
@@ -411,35 +357,33 @@
 int32_t WebRtcAudioDeviceImpl::SetMicrophoneVolume(uint32_t volume) {
   DVLOG(1) << "WebRtcAudioDeviceImpl::SetMicrophoneVolume(" << volume << ")";
   DCHECK(initialized_);
-  if (!capturer_.get())
+
+  // Only one microphone is supported at the moment, which is represented by
+  // the default capturer.
+  scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
+  if (!capturer.get())
     return -1;
 
-  if (volume > kMaxVolumeLevel)
-    return -1;
-
-  // WebRTC uses a range of [0, 255] to represent the level of the microphone
-  // volume. The IPC channel between the renderer and browser process works
-  // with doubles in the [0.0, 1.0] range and we have to compensate for that.
-  double normalized_volume = static_cast<double>(volume) / kMaxVolumeLevel;
-  capturer_->SetVolume(normalized_volume);
+  capturer->SetVolume(volume);
   return 0;
 }
 
 // TODO(henrika): sort out calling thread once we start using this API.
 int32_t WebRtcAudioDeviceImpl::MicrophoneVolume(uint32_t* volume) const {
   DVLOG(1) << "WebRtcAudioDeviceImpl::MicrophoneVolume()";
-  // The microphone level is fed to this class using the Capture() callback
-  // and cached in the same method, i.e. we don't ask the native audio layer
-  // for the actual micropone level here.
+  // We only support one microphone now, which is accessed via the default
+  // capturer.
   DCHECK(initialized_);
-  if (!capturer_.get())
+  scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
+  if (!capturer.get())
     return -1;
-  base::AutoLock auto_lock(lock_);
-  *volume = microphone_volume_;
+
+  *volume = static_cast<uint32_t>(capturer->Volume());
   return 0;
 }
 
 int32_t WebRtcAudioDeviceImpl::MaxMicrophoneVolume(uint32_t* max_volume) const {
+  DCHECK(initialized_);
   *max_volume = kMaxVolumeLevel;
   return 0;
 }
@@ -458,9 +402,13 @@
 int32_t WebRtcAudioDeviceImpl::StereoRecordingIsAvailable(
     bool* available) const {
   DCHECK(initialized_);
-  if (!capturer_.get())
+  // TODO(xians): These kind of hardware methods do not make much sense since we
+  // support multiple sources. Remove or figure out new APIs for such methods.
+  scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
+  if (!capturer.get())
     return -1;
-  *available = (input_channels() == 2);
+
+  *available = (capturer->audio_parameters().channels() == 2);
   return 0;
 }
 
@@ -478,7 +426,13 @@
 
 int32_t WebRtcAudioDeviceImpl::RecordingSampleRate(
     uint32_t* samples_per_sec) const {
-  *samples_per_sec = static_cast<uint32_t>(input_sample_rate());
+  // We use the default capturer as the recording sample rate.
+  scoped_refptr<WebRtcAudioCapturer> capturer(GetDefaultCapturer());
+  if (!capturer.get())
+    return -1;
+
+  *samples_per_sec = static_cast<uint32_t>(
+      capturer->audio_parameters().sample_rate());
   return 0;
 }
 
@@ -503,4 +457,33 @@
   return true;
 }
 
+void WebRtcAudioDeviceImpl::AddAudioCapturer(
+    const scoped_refptr<WebRtcAudioCapturer>& capturer) {
+  DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(capturer.get());
+
+  // Enable/disable the AGC on the new capture.
+  DCHECK(!capturer->is_recording());
+  capturer->SetAutomaticGainControl(agc_is_enabled_);
+
+  // We only support one microphone today, which means the list can contain
+  // only one capturer with a valid device id.
+  DCHECK(capturer->device_id().empty() || !GetDefaultCapturer());
+  base::AutoLock auto_lock(lock_);
+  capturers_.push_back(capturer);
+}
+
+scoped_refptr<WebRtcAudioCapturer>
+WebRtcAudioDeviceImpl::GetDefaultCapturer() const {
+  base::AutoLock auto_lock(lock_);
+  for (CapturerList::const_iterator iter = capturers_.begin();
+       iter != capturers_.end(); ++iter) {
+    if (!(*iter)->device_id().empty())
+      return *iter;
+  }
+
+  return NULL;
+}
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc_audio_device_impl.h b/content/renderer/media/webrtc_audio_device_impl.h
index 960d0d0..ef3cb7c 100644
--- a/content/renderer/media/webrtc_audio_device_impl.h
+++ b/content/renderer/media/webrtc_audio_device_impl.h
@@ -6,6 +6,7 @@
 #define CONTENT_RENDERER_MEDIA_WEBRTC_AUDIO_DEVICE_IMPL_H_
 
 #include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -204,11 +205,25 @@
 class WebRtcAudioCapturerSink {
  public:
   // Callback to deliver the captured interleaved data.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) = 0;
+  // |channels| contains a vector of WebRtc VoE channels.
+  // |audio_data| is the pointer to the audio data.
+  // |sample_rate| is the sample frequency of audio data.
+  // |number_of_channels| is the number of channels reflecting the order of
+  // surround sound channels.
+  // |audio_delay_milliseconds| is recording delay value.
+  // |current_volume| is current microphone volume, in range of |0, 255].
+  // |need_audio_processing| indicates if the audio needs WebRtc AEC/NS/AGC
+  // audio processing.
+  // The return value is the new microphone volume, in the range of |0, 255].
+  // When the volume does not need to be updated, it returns 0.
+  virtual int CaptureData(const std::vector<int>& channels,
+                          const int16* audio_data,
+                          int sample_rate,
+                          int number_of_channels,
+                          int number_of_frames,
+                          int audio_delay_milliseconds,
+                          int current_volume,
+                          bool need_audio_processing) = 0;
 
   // Set the format for the capture audio parameters.
   virtual void SetCaptureFormat(const media::AudioParameters& params) = 0;
@@ -225,6 +240,9 @@
       NON_EXPORTED_BASE(public WebRtcAudioCapturerSink),
       NON_EXPORTED_BASE(public WebRtcAudioRendererSource) {
  public:
+  // The maximum volume value WebRtc uses.
+  static const int kMaxVolumeLevel = 255;
+
   // Instances of this object are created on the main render thread.
   WebRtcAudioDeviceImpl();
 
@@ -283,43 +301,45 @@
   // Called on the main renderer thread.
   bool SetAudioRenderer(WebRtcAudioRenderer* renderer);
 
-  const scoped_refptr<WebRtcAudioCapturer>& capturer() const {
-    return capturer_;
-  }
+  // Adds the capturer to the ADM.
+  void AddAudioCapturer(const scoped_refptr<WebRtcAudioCapturer>& capturer);
+
+  // Gets the default capturer, which is the capturer in the list with
+  // a valid |device_id|. Microphones are represented by capturers with a valid
+  // |device_id|, since only one microphone is supported today, only one
+  // capturer in the |capturers_| can have a valid |device_id|.
+  scoped_refptr<WebRtcAudioCapturer> GetDefaultCapturer() const;
+
   const scoped_refptr<WebRtcAudioRenderer>& renderer() const {
     return renderer_;
   }
-  int input_buffer_size() const {
-    return input_audio_parameters_.frames_per_buffer();
-  }
   int output_buffer_size() const {
     return output_audio_parameters_.frames_per_buffer();
   }
-  int input_channels() const {
-    return input_audio_parameters_.channels();
-  }
   int output_channels() const {
     return output_audio_parameters_.channels();
   }
-  int input_sample_rate() const {
-    return input_audio_parameters_.sample_rate();
-  }
   int output_sample_rate() const {
     return output_audio_parameters_.sample_rate();
   }
 
  private:
+  typedef std::list<scoped_refptr<WebRtcAudioCapturer> > CapturerList;
+
   // Make destructor private to ensure that we can only be deleted by Release().
   virtual ~WebRtcAudioDeviceImpl();
 
   // WebRtcAudioCapturerSink implementation.
 
   // Called on the AudioInputDevice worker thread.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) OVERRIDE;
+  virtual int CaptureData(const std::vector<int>& channels,
+                          const int16* audio_data,
+                          int sample_rate,
+                          int number_of_channels,
+                          int number_of_frames,
+                          int audio_delay_milliseconds,
+                          int current_volume,
+                          bool need_audio_processing) OVERRIDE;
 
   // Called on the main render thread.
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
@@ -341,8 +361,9 @@
 
   int ref_count_;
 
-  // Provides access to the native audio input layer in the browser process.
-  scoped_refptr<WebRtcAudioCapturer> capturer_;
+  // List of captures which provides access to the native audio input layer
+  // in the browser process.
+  CapturerList capturers_;
 
   // Provides access to the audio renderer in the browser process.
   scoped_refptr<WebRtcAudioRenderer> renderer_;
@@ -352,8 +373,7 @@
   // RegisterAudioCallback().
   webrtc::AudioTransport* audio_transport_callback_;
 
-  // Cached values of utilized audio parameters. Platform dependent.
-  media::AudioParameters input_audio_parameters_;
+  // Cached values of used output audio parameters. Platform dependent.
   media::AudioParameters output_audio_parameters_;
 
   // Cached value of the current audio delay on the input/capture side.
diff --git a/content/renderer/media/webrtc_audio_device_unittest.cc b/content/renderer/media/webrtc_audio_device_unittest.cc
index ead1d70..6746ab6 100644
--- a/content/renderer/media/webrtc_audio_device_unittest.cc
+++ b/content/renderer/media/webrtc_audio_device_unittest.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
 #include "base/environment.h"
 #include "base/file_util.h"
 #include "base/files/file_path.h"
@@ -101,14 +103,13 @@
   return true;
 }
 
-// Utility method which initializes the audio capturer contained in the
-// WebRTC audio device. This method should be used in tests where
+// Utility method which creates and initializes the audio capturer and adds it
+// to WebRTC audio device. This method should be used in tests where
 // HardwareSampleRatesAreValid() has been called and returned true.
-bool InitializeCapturer(WebRtcAudioDeviceImpl* webrtc_audio_device) {
-  // Access the capturer owned and created by the audio device.
-  WebRtcAudioCapturer* capturer = webrtc_audio_device->capturer().get();
-  if (!capturer)
-    return false;
+bool CreateAndInitializeCapturer(WebRtcAudioDeviceImpl* webrtc_audio_device) {
+  DCHECK(webrtc_audio_device);
+  scoped_refptr<WebRtcAudioCapturer> capturer(
+      WebRtcAudioCapturer::CreateCapturer());
 
   media::AudioHardwareConfig* hardware_config =
       RenderThreadImpl::current()->GetAudioHardwareConfig();
@@ -118,12 +119,30 @@
   int sample_rate = hardware_config->GetInputSampleRate();
   media::ChannelLayout channel_layout =
       hardware_config->GetInputChannelLayout();
-  if (!capturer->Initialize(kRenderViewId, channel_layout, sample_rate, 1))
+  if (!capturer->Initialize(kRenderViewId, channel_layout, sample_rate, 1,
+                            media::AudioManagerBase::kDefaultDeviceId)) {
     return false;
+  }
+
+  // Add the capturer to the WebRtcAudioDeviceImpl.
+  webrtc_audio_device->AddAudioCapturer(capturer);
 
   return true;
 }
 
+// Create and start a local audio track. Starting the audio track will connect
+// the audio track to the capturer and also start the source of the capturer.
+// Also, connect the sink to the audio track.
+scoped_refptr<WebRtcLocalAudioTrack>
+CreateAndStartLocalAudioTrack(WebRtcAudioCapturer* capturer,
+                              WebRtcAudioCapturerSink* sink) {
+  scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
+      WebRtcLocalAudioTrack::Create(std::string(), capturer, NULL));
+  local_audio_track->AddSink(sink);
+  local_audio_track->Start();
+  return local_audio_track;
+}
+
 class WebRTCMediaProcessImpl : public webrtc::VoEMediaProcess {
  public:
   explicit WebRTCMediaProcessImpl(base::WaitableEvent* event)
@@ -195,13 +214,17 @@
   virtual ~MockWebRtcAudioCapturerSink() {}
 
   // WebRtcAudioCapturerSink implementation.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) OVERRIDE {
+  virtual int CaptureData(const std::vector<int>& channels,
+                          const int16* audio_data,
+                          int sample_rate,
+                          int number_of_channels,
+                          int number_of_frames,
+                          int audio_delay_milliseconds,
+                          int current_volume,
+                          bool need_audio_processing) OVERRIDE {
     // Signal that a callback has been received.
     event_->Signal();
+    return 0;
   }
 
   // Set the format for the capture audio parameters.
@@ -312,7 +335,6 @@
       48000, 2, 480);
   WebRtcAudioCapturerSink* capturer_sink =
       static_cast<WebRtcAudioCapturerSink*>(webrtc_audio_device.get());
-  capturer_sink->SetCaptureFormat(params);
   WebRtcAudioRendererSource* renderer_source =
       static_cast<WebRtcAudioRendererSource*>(webrtc_audio_device.get());
   renderer_source->SetRenderFormat(params);
@@ -339,9 +361,8 @@
   EXPECT_EQ(0, base->StartSend(channel));
 
   // Read speech data from a speech test file.
-  const int num_input_channels = webrtc_audio_device->input_channels();
-  const int input_packet_size = webrtc_audio_device->input_buffer_size() * 2 *
-      num_input_channels;
+  const int input_packet_size =
+      params.frames_per_buffer() * 2 * params.channels();
   const int num_output_channels = webrtc_audio_device->output_channels();
   const int output_packet_size = webrtc_audio_device->output_buffer_size() * 2 *
       num_output_channels;
@@ -353,12 +374,15 @@
   scoped_ptr<uint8[]> buffer(new uint8[output_packet_size]);
   base::Time start_time = base::Time::Now();
   int delay = 0;
+  std::vector<int> voe_channels;
+  voe_channels.push_back(channel);
   for (int j = 0; j < kNumberOfPacketsForLoopbackTest; ++j) {
     // Sending fake capture data to WebRtc.
     capturer_sink->CaptureData(
+        voe_channels,
         reinterpret_cast<int16*>(capture_data.get() + input_packet_size * j),
-        num_input_channels, webrtc_audio_device->input_buffer_size(),
-        kHardwareLatencyInMs, 1.0);
+        params.sample_rate(), params.channels(), params.frames_per_buffer(),
+        kHardwareLatencyInMs, 1.0, enable_apm);
 
     // Receiving data from WebRtc.
     renderer_source->RenderData(
@@ -451,16 +475,12 @@
   scoped_refptr<WebRtcAudioDeviceImpl> webrtc_audio_device(
       new WebRtcAudioDeviceImpl());
 
-  // The capturer is not created until after the WebRtcAudioDeviceImpl has
-  // been initialized.
-  EXPECT_FALSE(InitializeCapturer(webrtc_audio_device.get()));
-
   WebRTCAutoDelete<webrtc::VoiceEngine> engine(webrtc::VoiceEngine::Create());
   ASSERT_TRUE(engine.valid());
 
   ScopedWebRTCPtr<webrtc::VoEBase> base(engine.get());
   int err = base->Init(webrtc_audio_device.get());
-  EXPECT_TRUE(InitializeCapturer(webrtc_audio_device.get()));
+  EXPECT_TRUE(CreateAndInitializeCapturer(webrtc_audio_device.get()));
   EXPECT_EQ(0, err);
   EXPECT_EQ(0, base->Terminate());
 }
@@ -593,16 +613,6 @@
   int err = base->Init(webrtc_audio_device.get());
   ASSERT_EQ(0, err);
 
-  EXPECT_TRUE(InitializeCapturer(webrtc_audio_device.get()));
-
-  // Create and start a local audio track. Starting the audio track will connect
-  // the audio track to the capturer and also start the source of the capturer.
-  scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
-      WebRtcLocalAudioTrack::Create(std::string(),
-                                    webrtc_audio_device->capturer(),
-                                    NULL));
-  local_audio_track->Start();
-
   int ch = base->CreateChannel();
   EXPECT_NE(-1, ch);
 
@@ -624,6 +634,20 @@
   EXPECT_EQ(0, network->RegisterExternalTransport(ch, *transport.get()));
   EXPECT_EQ(0, base->StartSend(ch));
 
+  // Create and initialize the capturer which starts the source of the data
+  // flow.
+  EXPECT_TRUE(CreateAndInitializeCapturer(webrtc_audio_device.get()));
+
+  // Create and start a local audio track which is bridging the data flow
+  // between the capturer and WebRtcAudioDeviceImpl.
+  scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
+      CreateAndStartLocalAudioTrack(webrtc_audio_device->GetDefaultCapturer(),
+                                    webrtc_audio_device));
+  // connect the VoE voice channel to the audio track
+  static_cast<webrtc::AudioTrackInterface*>(local_audio_track.get())->
+      GetRenderer()->AddChannel(ch);
+
+  // Verify we get the data flow.
   EXPECT_TRUE(event.TimedWait(TestTimeouts::action_timeout()));
   WaitForIOThreadCompletion();
 
@@ -722,7 +746,8 @@
 // TODO(henrika): improve quality by using a wideband codec, enabling noise-
 // suppressions etc.
 // FullDuplexAudioWithAGC is flaky on Android, disable it for now.
-#if defined(OS_ANDROID)
+// Also flakily hangs on Windows: crbug.com/269348.
+#if defined(OS_ANDROID) || defined(OS_WIN)
 #define MAYBE_FullDuplexAudioWithAGC DISABLED_FullDuplexAudioWithAGC
 #else
 #define MAYBE_FullDuplexAudioWithAGC FullDuplexAudioWithAGC
@@ -763,15 +788,6 @@
   int err = base->Init(webrtc_audio_device.get());
   ASSERT_EQ(0, err);
 
-  EXPECT_TRUE(InitializeCapturer(webrtc_audio_device.get()));
-  // Create and start a local audio track. Starting the audio track will connect
-  // the audio track to the capturer and also start the source of the capturer.
-  scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
-      WebRtcLocalAudioTrack::Create(std::string(),
-                                    webrtc_audio_device->capturer(),
-                                    NULL));
-  local_audio_track->Start();
-
   ScopedWebRTCPtr<webrtc::VoEAudioProcessing> audio_processing(engine.get());
   ASSERT_TRUE(audio_processing.valid());
 #if defined(OS_ANDROID)
@@ -791,6 +807,14 @@
   int ch = base->CreateChannel();
   EXPECT_NE(-1, ch);
 
+  EXPECT_TRUE(CreateAndInitializeCapturer(webrtc_audio_device.get()));
+  scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
+      CreateAndStartLocalAudioTrack(webrtc_audio_device->GetDefaultCapturer(),
+                                    webrtc_audio_device));
+  // connect the VoE voice channel to the audio track
+  static_cast<webrtc::AudioTrackInterface*>(local_audio_track.get())->
+      GetRenderer()->AddChannel(ch);
+
   ScopedWebRTCPtr<webrtc::VoENetwork> network(engine.get());
   ASSERT_TRUE(network.valid());
   scoped_ptr<WebRTCTransportImpl> transport(
@@ -840,23 +864,23 @@
   int err = base->Init(webrtc_audio_device.get());
   ASSERT_EQ(0, err);
 
-  EXPECT_TRUE(InitializeCapturer(webrtc_audio_device.get()));
+  int ch = base->CreateChannel();
+  EXPECT_NE(-1, ch);
+
+  EXPECT_TRUE(CreateAndInitializeCapturer(webrtc_audio_device.get()));
+  base::WaitableEvent event(false, false);
+  scoped_ptr<MockWebRtcAudioCapturerSink> sink(
+      new MockWebRtcAudioCapturerSink(&event));
+
   // Create and start a local audio track. Starting the audio track will connect
   // the audio track to the capturer and also start the source of the capturer.
   scoped_refptr<WebRtcLocalAudioTrack> local_audio_track(
-      WebRtcLocalAudioTrack::Create(std::string(),
-                                    webrtc_audio_device->capturer(),
-                                    NULL));
-  local_audio_track->Start();
+      CreateAndStartLocalAudioTrack(
+          webrtc_audio_device->GetDefaultCapturer().get(), sink.get()));
 
-  base::WaitableEvent event(false, false);
-  scoped_ptr<MockWebRtcAudioCapturerSink> capturer_sink(
-      new MockWebRtcAudioCapturerSink(&event));
-  WebRtcAudioCapturer* capturer = webrtc_audio_device->capturer().get();
-  capturer->AddSink(capturer_sink.get());
-
-  int ch = base->CreateChannel();
-  EXPECT_NE(-1, ch);
+  // connect the VoE voice channel to the audio track.
+  static_cast<webrtc::AudioTrackInterface*>(local_audio_track.get())->
+      GetRenderer()->AddChannel(ch);
 
   base::Time start_time = base::Time::Now();
   EXPECT_EQ(0, base->StartSend(ch));
@@ -865,7 +889,7 @@
   int delay = (base::Time::Now() - start_time).InMilliseconds();
   PrintPerfResultMs("webrtc_recording_setup_c", "t", delay);
 
-  capturer->RemoveSink(capturer_sink.get());
+  local_audio_track->RemoveSink(sink.get());
   local_audio_track->Stop();
   EXPECT_EQ(0, base->StopSend(ch));
   EXPECT_EQ(0, base->DeleteChannel(ch));
diff --git a/content/renderer/media/webrtc_local_audio_renderer.cc b/content/renderer/media/webrtc_local_audio_renderer.cc
index c5ca67b..11c125f 100644
--- a/content/renderer/media/webrtc_local_audio_renderer.cc
+++ b/content/renderer/media/webrtc_local_audio_renderer.cc
@@ -51,16 +51,19 @@
 }
 
 // content::WebRtcAudioCapturerSink implementation
-void WebRtcLocalAudioRenderer::CaptureData(const int16* audio_data,
+int WebRtcLocalAudioRenderer::CaptureData(const std::vector<int>& channels,
+                                           const int16* audio_data,
+                                           int sample_rate,
                                            int number_of_channels,
                                            int number_of_frames,
                                            int audio_delay_milliseconds,
-                                           double volume) {
+                                           int current_volume,
+                                           bool need_audio_processing) {
   TRACE_EVENT0("audio", "WebRtcLocalAudioRenderer::CaptureData");
   base::AutoLock auto_lock(thread_lock_);
 
   if (!playing_)
-    return;
+    return 0;
 
   // Push captured audio to FIFO so it can be read by a local sink.
   if (loopback_fifo_) {
@@ -80,6 +83,8 @@
       DVLOG(1) << "FIFO is full";
     }
   }
+
+  return 0;
 }
 
 void WebRtcLocalAudioRenderer::SetCaptureFormat(
diff --git a/content/renderer/media/webrtc_local_audio_renderer.h b/content/renderer/media/webrtc_local_audio_renderer.h
index c62fef1..2930393 100644
--- a/content/renderer/media/webrtc_local_audio_renderer.h
+++ b/content/renderer/media/webrtc_local_audio_renderer.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_RENDERER_MEDIA_WEBRTC_LOCAL_AUDIO_RENDERER_H_
 #define CONTENT_RENDERER_MEDIA_WEBRTC_LOCAL_AUDIO_RENDERER_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/lock.h"
@@ -69,11 +71,14 @@
   // WebRtcAudioCapturerSink implementation.
 
   // Called on the AudioInputDevice worker thread.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) OVERRIDE;
+  virtual int CaptureData(const std::vector<int>& channels,
+                          const int16* audio_data,
+                          int sample_rate,
+                          int number_of_channels,
+                          int number_of_frames,
+                          int audio_delay_milliseconds,
+                          int current_volume,
+                          bool need_audio_processing) OVERRIDE;
 
   // Can be called on different user thread.
   virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
diff --git a/content/renderer/media/webrtc_local_audio_track.cc b/content/renderer/media/webrtc_local_audio_track.cc
index fc89468..de86a3c 100644
--- a/content/renderer/media/webrtc_local_audio_track.cc
+++ b/content/renderer/media/webrtc_local_audio_track.cc
@@ -28,27 +28,29 @@
     webrtc::AudioSourceInterface* track_source)
     : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label),
       capturer_(capturer),
-      track_source_(track_source) {
+      track_source_(track_source),
+      need_audio_processing_(!capturer->device_id().empty()) {
+  // The capturer with a valid device id is using microphone as source,
+  // and APM (AudioProcessingModule) is turned on only for microphone data.
   DCHECK(capturer.get());
   DVLOG(1) << "WebRtcLocalAudioTrack::WebRtcLocalAudioTrack()";
 }
 
 WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  DCHECK(sinks_.empty());
   DVLOG(1) << "WebRtcLocalAudioTrack::~WebRtcLocalAudioTrack()";
-
   // Users might not call Stop() on the track.
-  if (capturer_.get())
-    Stop();
+  Stop();
 }
 
-// Content::WebRtcAudioCapturerSink implementation.
 void WebRtcLocalAudioTrack::CaptureData(const int16* audio_data,
                                         int number_of_channels,
                                         int number_of_frames,
                                         int audio_delay_milliseconds,
-                                        double volume) {
+                                        int volume) {
+  scoped_refptr<WebRtcAudioCapturer> capturer;
+  std::vector<int> voe_channels;
+  int sample_rate = 0;
   SinkList sinks;
   {
     base::AutoLock auto_lock(lock_);
@@ -58,15 +60,20 @@
     if (!enabled())
       return;
 
+    capturer = capturer_;
+    voe_channels = voe_channels_;
+    sample_rate = params_.sample_rate(),
     sinks = sinks_;
   }
 
   // Feed the data to the sinks.
-  for (SinkList::const_iterator it = sinks.begin();
-       it != sinks.end();
-       ++it) {
-    (*it)->CaptureData(audio_data, number_of_channels, number_of_frames,
-                       audio_delay_milliseconds, volume);
+  for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it) {
+    int new_volume = (*it)->CaptureData(voe_channels, audio_data, sample_rate,
+                                        number_of_channels, number_of_frames,
+                                        audio_delay_milliseconds, volume,
+                                        need_audio_processing_);
+    if (new_volume != 0 && capturer.get())
+      capturer->SetVolume(new_volume);
   }
 }
 
@@ -81,11 +88,39 @@
     (*it)->SetCaptureFormat(params);
 }
 
+void WebRtcLocalAudioTrack::AddChannel(int channel_id) {
+  DVLOG(1) << "WebRtcLocalAudioTrack::AddChannel(channel_id="
+           << channel_id << ")";
+  base::AutoLock auto_lock(lock_);
+  if (std::find(voe_channels_.begin(), voe_channels_.end(), channel_id) !=
+      voe_channels_.end()) {
+    // We need to handle the case when the same channel is connected to the
+    // track more than once.
+    return;
+  }
+
+  voe_channels_.push_back(channel_id);
+}
+
+void WebRtcLocalAudioTrack::RemoveChannel(int channel_id) {
+  DVLOG(1) << "WebRtcLocalAudioTrack::RemoveChannel(channel_id="
+           << channel_id << ")";
+  base::AutoLock auto_lock(lock_);
+  std::vector<int>::iterator iter =
+      std::find(voe_channels_.begin(), voe_channels_.end(), channel_id);
+  DCHECK(iter != voe_channels_.end());
+  voe_channels_.erase(iter);
+}
+
 // webrtc::AudioTrackInterface implementation.
 webrtc::AudioSourceInterface* WebRtcLocalAudioTrack::GetSource() const {
   return track_source_;
 }
 
+cricket::AudioRenderer* WebRtcLocalAudioTrack::GetRenderer() {
+  return this;
+}
+
 std::string WebRtcLocalAudioTrack::kind() const {
   return kAudioTrackKind;
 }
@@ -113,7 +148,6 @@
   DVLOG(1) << "WebRtcLocalAudioTrack::RemoveSink()";
 
   base::AutoLock auto_lock(lock_);
-
   // Get iterator to the first element for which WrapsSink(sink) returns true.
   SinkList::iterator it = std::find_if(
       sinks_.begin(), sinks_.end(),
@@ -131,16 +165,28 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "WebRtcLocalAudioTrack::Start()";
   if (capturer_.get())
-    capturer_->AddSink(this);
+    capturer_->AddTrack(this);
 }
 
 void WebRtcLocalAudioTrack::Stop() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "WebRtcLocalAudioTrack::Stop()";
-  if (capturer_.get()) {
-    capturer_->RemoveSink(this);
+  if (!capturer_.get())
+    return;
+
+  capturer_->RemoveTrack(this);
+
+  // Protect the pointers using the lock when accessing |sinks_| and
+  // setting the |capturer_| to NULL.
+  SinkList sinks;
+  {
+    base::AutoLock auto_lock(lock_);
+    sinks = sinks_;
     capturer_ = NULL;
   }
+
+  for (SinkList::const_iterator it = sinks.begin(); it != sinks.end(); ++it)
+    (*it)->Reset();
 }
 
 }  // namespace content
diff --git a/content/renderer/media/webrtc_local_audio_track.h b/content/renderer/media/webrtc_local_audio_track.h
index 5881d8a..7cb8c85 100644
--- a/content/renderer/media/webrtc_local_audio_track.h
+++ b/content/renderer/media/webrtc_local_audio_track.h
@@ -13,6 +13,7 @@
 #include "content/renderer/media/webrtc_audio_device_impl.h"
 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
 #include "third_party/libjingle/source/talk/app/webrtc/mediastreamtrack.h"
+#include "third_party/libjingle/source/talk/media/base/audiorenderer.h"
 
 namespace cricket {
 class AudioRenderer;
@@ -29,7 +30,7 @@
 // WebRtcAudioCapturer to get the captured data, and forward the data to
 // its |sinks_|. The data flow can be stopped by disabling the audio track.
 class CONTENT_EXPORT WebRtcLocalAudioTrack
-    : NON_EXPORTED_BASE(public WebRtcAudioCapturerSink),
+    : NON_EXPORTED_BASE(public cricket::AudioRenderer),
       NON_EXPORTED_BASE(
           public webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>) {
  public:
@@ -55,28 +56,34 @@
   // should be called only once when audio track going away.
   void Stop();
 
+  // Method called by the capturer to deliever the capture data.
+  void CaptureData(const int16* audio_data,
+                   int number_of_channels,
+                   int number_of_frames,
+                   int audio_delay_milliseconds,
+                   int volume);
+
+  // Method called by the capturer to set the audio parameters used by source
+  // of the capture data..
+  // Can be called on different user threads.
+  void SetCaptureFormat(const media::AudioParameters& params);
+
  protected:
   WebRtcLocalAudioTrack(const std::string& label,
                         const scoped_refptr<WebRtcAudioCapturer>& capturer,
-                        webrtc::AudioSourceInterface* stream_source);
+                        webrtc::AudioSourceInterface* track_source);
   virtual ~WebRtcLocalAudioTrack();
 
  private:
   typedef std::list<scoped_refptr<WebRtcAudioCapturerSinkOwner> > SinkList;
 
-  // content::WebRtcAudioCapturerSink implementation.
-  // Called on the AudioInputDevice worker thread.
-  virtual void CaptureData(const int16* audio_data,
-                           int number_of_channels,
-                           int number_of_frames,
-                           int audio_delay_milliseconds,
-                           double volume) OVERRIDE;
-
-  // Can be called on different user threads.
-  virtual void SetCaptureFormat(const media::AudioParameters& params) OVERRIDE;
+  // cricket::AudioCapturer implementation.
+  virtual void AddChannel(int channel_id) OVERRIDE;
+  virtual void RemoveChannel(int channel_id) OVERRIDE;
 
   // webrtc::AudioTrackInterface implementation.
   virtual webrtc::AudioSourceInterface* GetSource() const OVERRIDE;
+  virtual cricket::AudioRenderer* GetRenderer() OVERRIDE;
 
   // webrtc::MediaStreamTrack implementation.
   virtual std::string kind() const OVERRIDE;
@@ -101,6 +108,11 @@
   // Protects |params_| and |sinks_|.
   mutable base::Lock lock_;
 
+  // A vector of WebRtc VoE channels that the capturer sends datat to.
+  std::vector<int> voe_channels_;
+
+  bool need_audio_processing_;
+
   DISALLOW_COPY_AND_ASSIGN(WebRtcLocalAudioTrack);
 };
 
diff --git a/content/renderer/media/webrtc_local_audio_track_unittest.cc b/content/renderer/media/webrtc_local_audio_track_unittest.cc
index 1638feb..4720e45 100644
--- a/content/renderer/media/webrtc_local_audio_track_unittest.cc
+++ b/content/renderer/media/webrtc_local_audio_track_unittest.cc
@@ -11,6 +11,7 @@
 #include "media/base/audio_capturer_source.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
 
 using ::testing::_;
 using ::testing::AnyNumber;
@@ -95,11 +96,27 @@
  public:
   MockWebRtcAudioCapturerSink() {}
   ~MockWebRtcAudioCapturerSink() {}
-  MOCK_METHOD5(CaptureData, void(const int16* audio_data,
+  int CaptureData(const std::vector<int>& channels,
+                  const int16* audio_data,
+                  int sample_rate,
+                  int number_of_channels,
+                  int number_of_frames,
+                  int audio_delay_milliseconds,
+                  int current_volume,
+                  bool need_audio_processing) OVERRIDE {
+    CaptureData(channels.size(), sample_rate, number_of_channels,
+                number_of_frames, audio_delay_milliseconds, current_volume,
+                need_audio_processing);
+    return 0;
+  }
+  MOCK_METHOD7(CaptureData, void(int number_of_network_channels,
+                                 int sample_rate,
                                  int number_of_channels,
                                  int number_of_frames,
                                  int audio_delay_milliseconds,
-                                 double volume));
+                                 int current_volume,
+                                 bool need_audio_processing));
+
   MOCK_METHOD1(SetCaptureFormat, void(const media::AudioParameters& params));
 };
 
@@ -118,6 +135,8 @@
 
     EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(false))
         .WillOnce(Return());
+
+    // Start the audio thread used by the |capturer_source_|.
     audio_thread_.reset(new FakeAudioThread(capturer_));
     audio_thread_->Start();
   }
@@ -142,13 +161,21 @@
       WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
   track->Start();
   EXPECT_TRUE(track->enabled());
+
+  // Connect a number of network channels to the audio track.
+  static const int kNumberOfNetworkChannels = 4;
+  for (int i = 0; i < kNumberOfNetworkChannels; ++i) {
+    static_cast<webrtc::AudioTrackInterface*>(track.get())->
+        GetRenderer()->AddChannel(i);
+  }
   scoped_ptr<MockWebRtcAudioCapturerSink> sink(
       new MockWebRtcAudioCapturerSink());
   const media::AudioParameters params = capturer_->audio_parameters();
   base::WaitableEvent event(false, false);
   EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return());
   EXPECT_CALL(*sink, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      kNumberOfNetworkChannels, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event));
   track->AddSink(sink.get());
 
@@ -171,6 +198,8 @@
   scoped_refptr<WebRtcLocalAudioTrack> track =
     WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
   track->Start();
+  static_cast<webrtc::AudioTrackInterface*>(track.get())->
+      GetRenderer()->AddChannel(0);
   EXPECT_TRUE(track->enabled());
   EXPECT_TRUE(track->set_enabled(false));
   scoped_ptr<MockWebRtcAudioCapturerSink> sink(
@@ -179,14 +208,16 @@
   base::WaitableEvent event(false, false);
   EXPECT_CALL(*sink, SetCaptureFormat(_)).WillOnce(Return());
   EXPECT_CALL(*sink, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      1, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(0);
   track->AddSink(sink.get());
   EXPECT_FALSE(event.TimedWait(TestTimeouts::tiny_timeout()));
 
   event.Reset();
   EXPECT_CALL(*sink, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      1, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event));
   EXPECT_TRUE(track->set_enabled(true));
   EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
@@ -204,6 +235,8 @@
   scoped_refptr<WebRtcLocalAudioTrack> track_1 =
     WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
   track_1->Start();
+  static_cast<webrtc::AudioTrackInterface*>(track_1.get())->
+      GetRenderer()->AddChannel(0);
   EXPECT_TRUE(track_1->enabled());
   scoped_ptr<MockWebRtcAudioCapturerSink> sink_1(
       new MockWebRtcAudioCapturerSink());
@@ -211,7 +244,8 @@
   base::WaitableEvent event_1(false, false);
   EXPECT_CALL(*sink_1, SetCaptureFormat(_)).WillOnce(Return());
   EXPECT_CALL(*sink_1, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      1, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_1));
   track_1->AddSink(sink_1.get());
   EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout()));
@@ -219,6 +253,8 @@
   scoped_refptr<WebRtcLocalAudioTrack> track_2 =
     WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
   track_2->Start();
+  static_cast<webrtc::AudioTrackInterface*>(track_2.get())->
+      GetRenderer()->AddChannel(1);
   EXPECT_TRUE(track_2->enabled());
 
   // Verify both |sink_1| and |sink_2| get data.
@@ -229,10 +265,12 @@
         new MockWebRtcAudioCapturerSink());
   EXPECT_CALL(*sink_2, SetCaptureFormat(_)).WillOnce(Return());
   EXPECT_CALL(*sink_1, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      1, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_1));
   EXPECT_CALL(*sink_2, CaptureData(
-      _, params.channels(), params.frames_per_buffer(), 0, 0))
+      1, params.sample_rate(), params.channels(),
+      params.frames_per_buffer(), 0, 0, false))
       .Times(AtLeast(1)).WillRepeatedly(SignalEvent(&event_2));
   track_2->AddSink(sink_2.get());
   EXPECT_TRUE(event_1.TimedWait(TestTimeouts::tiny_timeout()));
@@ -260,55 +298,63 @@
   // When the track goes away, it will automatically stop the
   // |capturer_source_|.
   EXPECT_CALL(*capturer_source_.get(), Stop());
+  track->Stop();
   track = NULL;
 }
 
 // Start/Stop tracks and verify the capturer is correctly starting/stopping
 // its source.
 TEST_F(WebRtcLocalAudioTrackTest, StartAndStopAudioTracks) {
-  // SetDefaultSink() should not trigger the Start() on |capturer_source_|.
-  base::WaitableEvent event(false, false);
-  scoped_ptr<MockWebRtcAudioCapturerSink> default_sink(
-      new MockWebRtcAudioCapturerSink());
-  EXPECT_CALL(*default_sink, SetCaptureFormat(_)).WillOnce(Return());
-  EXPECT_CALL(*default_sink, CaptureData(_, _, _, 0, 0))
-      .Times(AnyNumber()).WillRepeatedly(Return());
-  capturer_->SetDefaultSink(default_sink.get());
-  EXPECT_CALL(*capturer_source_.get(), Start()).Times(0);
-  EXPECT_FALSE(event.TimedWait(TestTimeouts::tiny_timeout()));
-
   // Starting the first audio track will start the |capturer_source_|.
-  event.Reset();
+  base::WaitableEvent event(false, false);
   EXPECT_CALL(*capturer_source_.get(), Start()).WillOnce(SignalEvent(&event));
   scoped_refptr<WebRtcLocalAudioTrack> track_1 =
       WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
+  static_cast<webrtc::AudioTrackInterface*>(track_1.get())->
+      GetRenderer()->AddChannel(0);
   track_1->Start();
   EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
 
+  // Verify the data flow by connecting the sink to |track_1|.
+  scoped_ptr<MockWebRtcAudioCapturerSink> sink(
+      new MockWebRtcAudioCapturerSink());
+  event.Reset();
+  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false))
+      .Times(AnyNumber()).WillRepeatedly(Return());
+  EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1);
+  track_1->AddSink(sink.get());
+
   // Start the second audio track will not start the |capturer_source_|
   // since it has been started.
   EXPECT_CALL(*capturer_source_.get(), Start()).Times(0);
   scoped_refptr<WebRtcLocalAudioTrack> track_2 =
       WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
   track_2->Start();
+  static_cast<webrtc::AudioTrackInterface*>(track_2.get())->
+      GetRenderer()->AddChannel(1);
 
   // Stop the first audio track will not stop the |capturer_source_|.
   EXPECT_CALL(*capturer_source_.get(), Stop()).Times(0);
+  track_1->RemoveSink(sink.get());
   track_1->Stop();
   track_1 = NULL;
 
+  EXPECT_CALL(*sink, CaptureData(_, _, _, _, 0, 0, false))
+      .Times(AnyNumber()).WillRepeatedly(Return());
+  EXPECT_CALL(*sink, SetCaptureFormat(_)).Times(1);
+  track_2->AddSink(sink.get());
+
   // Stop the last audio track will stop the |capturer_source_|.
   event.Reset();
   EXPECT_CALL(*capturer_source_.get(), Stop())
       .Times(1).WillOnce(SignalEvent(&event));
   track_2->Stop();
+  track_2->RemoveSink(sink.get());
   track_2 = NULL;
   EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
-
-  capturer_->SetDefaultSink(NULL);
 }
 
-// Set new source to the capturer.
+// Set new source to the existing capturer.
 TEST_F(WebRtcLocalAudioTrackTest, SetNewSourceForCapturerAfterStartTrack) {
   // Setup the audio track and start the track.
   EXPECT_CALL(*capturer_source_.get(), Start()).Times(1);
@@ -333,4 +379,80 @@
   track = NULL;
 }
 
+// Create a new capturer with new source, connect it to a new audio track.
+TEST_F(WebRtcLocalAudioTrackTest, ConnectTracksToDifferentCapturers) {
+  // Setup the first audio track and start it.
+  EXPECT_CALL(*capturer_source_.get(), Start()).Times(1);
+  scoped_refptr<WebRtcLocalAudioTrack> track_1 =
+      WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL);
+  track_1->Start();
+
+  // Connect a number of network channels to the |track_1|.
+  static const int kNumberOfNetworkChannelsForTrack1 = 2;
+  for (int i = 0; i < kNumberOfNetworkChannelsForTrack1; ++i) {
+    static_cast<webrtc::AudioTrackInterface*>(track_1.get())->
+        GetRenderer()->AddChannel(i);
+  }
+  // Verify the data flow by connecting the |sink_1| to |track_1|.
+  scoped_ptr<MockWebRtcAudioCapturerSink> sink_1(
+      new MockWebRtcAudioCapturerSink());
+  EXPECT_CALL(*sink_1.get(), CaptureData(kNumberOfNetworkChannelsForTrack1,
+                                         48000, 2, _, 0, 0, false))
+      .Times(AnyNumber()).WillRepeatedly(Return());
+  EXPECT_CALL(*sink_1.get(), SetCaptureFormat(_)).Times(1);
+  track_1->AddSink(sink_1.get());
+
+  // Create a new capturer with new source with different audio format.
+  scoped_refptr<WebRtcAudioCapturer> new_capturer(
+      WebRtcAudioCapturer::CreateCapturer());
+  scoped_refptr<MockCapturerSource> new_source(new MockCapturerSource());
+  EXPECT_CALL(*new_source.get(), Initialize(_, new_capturer.get(), 0))
+      .WillOnce(Return());
+  EXPECT_CALL(*new_source.get(), SetAutomaticGainControl(false))
+      .WillOnce(Return());
+  new_capturer->SetCapturerSource(new_source,
+                                  media::CHANNEL_LAYOUT_MONO,
+                                  44100);
+
+  // Start the audio thread used by the new source.
+  scoped_ptr<FakeAudioThread> audio_thread(new FakeAudioThread(new_capturer));
+  audio_thread->Start();
+
+  // Setup the second audio track, connect it to the new capturer and start it.
+  EXPECT_CALL(*new_source.get(), Start()).Times(1);
+  scoped_refptr<WebRtcLocalAudioTrack> track_2 =
+      WebRtcLocalAudioTrack::Create(std::string(), new_capturer, NULL);
+  track_2->Start();
+
+  // Connect a number of network channels to the |track_2|.
+  static const int kNumberOfNetworkChannelsForTrack2 = 3;
+  for (int i = 0; i < kNumberOfNetworkChannelsForTrack2; ++i) {
+    static_cast<webrtc::AudioTrackInterface*>(track_2.get())->
+        GetRenderer()->AddChannel(i);
+  }
+  // Verify the data flow by connecting the |sink_2| to |track_2|.
+  scoped_ptr<MockWebRtcAudioCapturerSink> sink_2(
+      new MockWebRtcAudioCapturerSink());
+  EXPECT_CALL(*sink_2, CaptureData(kNumberOfNetworkChannelsForTrack2,
+                                     44100, 1, _, 0, 0, false))
+      .Times(AnyNumber()).WillRepeatedly(Return());
+  EXPECT_CALL(*sink_2, SetCaptureFormat(_)).Times(1);
+  track_2->AddSink(sink_2.get());
+
+  // Stop the second audio track will stop the new source.
+  base::WaitableEvent event(false, false);
+  EXPECT_CALL(*new_source.get(), Stop()).Times(1).WillOnce(SignalEvent(&event));
+  track_2->Stop();
+  track_2->RemoveSink(sink_2.get());
+  track_2 = NULL;
+  EXPECT_TRUE(event.TimedWait(TestTimeouts::tiny_timeout()));
+  audio_thread->Stop();
+  audio_thread.reset();
+
+  // Stop the first audio track.
+  EXPECT_CALL(*capturer_source_.get(), Stop());
+  track_1->Stop();
+  track_1 = NULL;
+}
+
 }  // namespace content
diff --git a/content/renderer/plugin_channel_host.cc b/content/renderer/npapi/plugin_channel_host.cc
similarity index 98%
rename from content/renderer/plugin_channel_host.cc
rename to content/renderer/npapi/plugin_channel_host.cc
index b3005bb..c276d33 100644
--- a/content/renderer/plugin_channel_host.cc
+++ b/content/renderer/npapi/plugin_channel_host.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/plugin_channel_host.h"
+#include "content/renderer/npapi/plugin_channel_host.h"
 
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
diff --git a/content/renderer/plugin_channel_host.h b/content/renderer/npapi/plugin_channel_host.h
similarity index 92%
rename from content/renderer/plugin_channel_host.h
rename to content/renderer/npapi/plugin_channel_host.h
index 2cc901c..6e61346 100644
--- a/content/renderer/plugin_channel_host.h
+++ b/content/renderer/npapi/plugin_channel_host.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 CONTENT_RENDERER_PLUGIN_CHANNEL_HOST_H_
-#define CONTENT_RENDERER_PLUGIN_CHANNEL_HOST_H_
+#ifndef CONTENT_RENDERER_NPAPI_PLUGIN_CHANNEL_HOST_H_
+#define CONTENT_RENDERER_NPAPI_PLUGIN_CHANNEL_HOST_H_
 
 #include "base/containers/hash_tables.h"
 #include "content/child/npapi/np_channel_base.h"
@@ -72,4 +72,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_PLUGIN_CHANNEL_HOST_H_
+#endif  // CONTENT_RENDERER_NPAPI_PLUGIN_CHANNEL_HOST_H_
diff --git a/content/renderer/webplugin_delegate_proxy.cc b/content/renderer/npapi/webplugin_delegate_proxy.cc
similarity index 99%
rename from content/renderer/webplugin_delegate_proxy.cc
rename to content/renderer/npapi/webplugin_delegate_proxy.cc
index 7ed03fc..f1da1d8 100644
--- a/content/renderer/webplugin_delegate_proxy.cc
+++ b/content/renderer/npapi/webplugin_delegate_proxy.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/webplugin_delegate_proxy.h"
+#include "content/renderer/npapi/webplugin_delegate_proxy.h"
 
 #if defined(TOOLKIT_GTK)
 #include <gtk/gtk.h>
@@ -32,7 +32,7 @@
 #include "content/child/plugin_messages.h"
 #include "content/common/view_messages.h"
 #include "content/public/renderer/content_renderer_client.h"
-#include "content/renderer/plugin_channel_host.h"
+#include "content/renderer/npapi/plugin_channel_host.h"
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "ipc/ipc_channel_handle.h"
diff --git a/content/renderer/webplugin_delegate_proxy.h b/content/renderer/npapi/webplugin_delegate_proxy.h
similarity index 98%
rename from content/renderer/webplugin_delegate_proxy.h
rename to content/renderer/npapi/webplugin_delegate_proxy.h
index 46bf027..7c7b0ae 100644
--- a/content/renderer/webplugin_delegate_proxy.h
+++ b/content/renderer/npapi/webplugin_delegate_proxy.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 CONTENT_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H_
-#define CONTENT_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H_
+#ifndef CONTENT_RENDERER_NPAPI_WEBPLUGIN_DELEGATE_PROXY_H_
+#define CONTENT_RENDERER_NPAPI_WEBPLUGIN_DELEGATE_PROXY_H_
 
 #include <string>
 #include <vector>
@@ -296,4 +296,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_WEBPLUGIN_DELEGATE_PROXY_H_
+#endif  // CONTENT_RENDERER_NPAPI_WEBPLUGIN_DELEGATE_PROXY_H_
diff --git a/content/renderer/webplugin_impl.cc b/content/renderer/npapi/webplugin_impl.cc
similarity index 99%
rename from content/renderer/webplugin_impl.cc
rename to content/renderer/npapi/webplugin_impl.cc
index 9c9b0b0..ae71c44 100644
--- a/content/renderer/webplugin_impl.cc
+++ b/content/renderer/npapi/webplugin_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/webplugin_impl.h"
+#include "content/renderer/npapi/webplugin_impl.h"
 
 #include "base/bind.h"
 #include "base/debug/crash_logging.h"
@@ -18,9 +18,9 @@
 #include "content/child/npapi/webplugin_delegate_impl.h"
 #include "content/common/view_messages.h"
 #include "content/public/renderer/content_renderer_client.h"
+#include "content/renderer/npapi/webplugin_delegate_proxy.h"
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_view_impl.h"
-#include "content/renderer/webplugin_delegate_proxy.h"
 #include "net/base/escape.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
diff --git a/content/renderer/webplugin_impl.h b/content/renderer/npapi/webplugin_impl.h
similarity index 98%
rename from content/renderer/webplugin_impl.h
rename to content/renderer/npapi/webplugin_impl.h
index aa66169..63f85fb 100644
--- a/content/renderer/webplugin_impl.h
+++ b/content/renderer/npapi/webplugin_impl.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 CONTENT_RENDERER_WEBPLUGIN_IMPL_H_
-#define CONTENT_RENDERER_WEBPLUGIN_IMPL_H_
+#ifndef CONTENT_RENDERER_NPAPI_WEBPLUGIN_IMPL_H_
+#define CONTENT_RENDERER_NPAPI_WEBPLUGIN_IMPL_H_
 
 #include <map>
 #include <string>
@@ -339,4 +339,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_WEBPLUGIN_IMPL_H_
+#endif  // CONTENT_RENDERER_NPAPI_WEBPLUGIN_IMPL_H_
diff --git a/content/renderer/webplugin_impl_unittest.cc b/content/renderer/npapi/webplugin_impl_unittest.cc
similarity index 99%
rename from content/renderer/webplugin_impl_unittest.cc
rename to content/renderer/npapi/webplugin_impl_unittest.cc
index 98d0f7b..df1371c 100644
--- a/content/renderer/webplugin_impl_unittest.cc
+++ b/content/renderer/npapi/webplugin_impl_unittest.cc
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/strings/string_util.h"
-#include "content/renderer/webplugin_impl.h"
+#include "content/renderer/npapi/webplugin_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebCString.h"
 #include "third_party/WebKit/public/platform/WebString.h"
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index c90f888..fdc0df6 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -26,7 +26,6 @@
 #include "content/renderer/render_thread_impl.h"
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/renderer_webapplicationcachehost_impl.h"
-#include "content/renderer/webplugin_impl.h"
 #include "content/renderer/websharedworker_proxy.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_util.h"
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index e341e5d..fd86944 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -40,7 +40,7 @@
 #include "content/common/child_process_messages.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/database_messages.h"
-#include "content/common/dom_storage_messages.h"
+#include "content/common/dom_storage/dom_storage_messages.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
 #include "content/common/gpu/gpu_messages.h"
@@ -75,7 +75,6 @@
 #include "content/renderer/media/webrtc_identity_service.h"
 #include "content/renderer/memory_benchmarking_extension.h"
 #include "content/renderer/p2p/socket_dispatcher.h"
-#include "content/renderer/plugin_channel_host.h"
 #include "content/renderer/render_process_impl.h"
 #include "content/renderer/render_process_visibility_manager.h"
 #include "content/renderer/render_view_impl.h"
@@ -131,6 +130,10 @@
 #include "content/renderer/android/synchronous_compositor_factory.h"
 #endif
 
+#if defined(ENABLE_PLUGINS)
+#include "content/renderer/npapi/plugin_channel_host.h"
+#endif
+
 using base::ThreadRestrictions;
 using WebKit::WebDocument;
 using WebKit::WebFrame;
@@ -509,7 +512,9 @@
   bool notify_webkit_of_modal_loop = true;  // default value
   std::swap(notify_webkit_of_modal_loop, notify_webkit_of_modal_loop_);
 
+#if defined(ENABLE_PLUGINS)
   int render_view_id = MSG_ROUTING_NONE;
+#endif
 
   if (pumping_events) {
     if (suspend_webkit_shared_timer)
@@ -517,7 +522,7 @@
 
     if (notify_webkit_of_modal_loop)
       WebView::willEnterModalLoop();
-
+#if defined(ENABLE_PLUGINS)
     RenderViewImpl* render_view =
         RenderViewImpl::FromRoutingID(msg->routing_id());
     if (render_view) {
@@ -525,15 +530,18 @@
       PluginChannelHost::Broadcast(
           new PluginMsg_SignalModalDialogEvent(render_view_id));
     }
+#endif
   }
 
   bool rv = ChildThread::Send(msg);
 
   if (pumping_events) {
+#if defined(ENABLE_PLUGINS)
     if (render_view_id != MSG_ROUTING_NONE) {
       PluginChannelHost::Broadcast(
           new PluginMsg_ResetModalDialogEvent(render_view_id));
     }
+#endif
 
     if (notify_webkit_of_modal_loop)
       WebView::didExitModalLoop();
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 0117924..5299bdd 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -39,6 +39,7 @@
 #include "content/child/webmessageportchannel_impl.h"
 #include "content/common/clipboard_messages.h"
 #include "content/common/database_messages.h"
+#include "content/common/dom_storage/dom_storage_types.h"
 #include "content/common/drag_messages.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
 #include "content/common/input_messages.h"
@@ -124,8 +125,6 @@
 #include "content/renderer/v8_value_converter_impl.h"
 #include "content/renderer/web_ui_extension.h"
 #include "content/renderer/web_ui_extension_data.h"
-#include "content/renderer/webplugin_delegate_proxy.h"
-#include "content/renderer/webplugin_impl.h"
 #include "content/renderer/websharedworker_proxy.h"
 #include "media/audio/audio_output_device.h"
 #include "media/base/audio_renderer_mixer_input.h"
@@ -206,7 +205,6 @@
 #include "ui/shell_dialogs/selected_file_info.h"
 #include "v8/include/v8.h"
 #include "webkit/child/weburlresponse_extradata_impl.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
 #include "webkit/renderer/appcache/web_application_cache_host_impl.h"
 #include "webkit/renderer/webpreferences_renderer.h"
 
@@ -245,6 +243,8 @@
 #endif
 
 #if defined(ENABLE_PLUGINS)
+#include "content/renderer/npapi/webplugin_delegate_proxy.h"
+#include "content/renderer/npapi/webplugin_impl.h"
 #include "content/renderer/pepper/pepper_browser_connection.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/pepper/pepper_plugin_registry.h"
@@ -842,8 +842,7 @@
       handling_select_range_(false),
       next_snapshot_id_(0),
       allow_partial_swap_(params->allow_partial_swap),
-      context_menu_source_type_(ui::MENU_SOURCE_MOUSE),
-      inflight_console_message_count_(0) {
+      context_menu_source_type_(ui::MENU_SOURCE_MOUSE) {
 }
 
 void RenderViewImpl::Initialize(RenderViewImplParams* params) {
@@ -1008,12 +1007,6 @@
     file_chooser_completions_.pop_front();
   }
 
-  // There may be unsent console log messages, but it is OK.
-  while (!deferred_console_messages_.empty()) {
-    delete deferred_console_messages_.front();
-    deferred_console_messages_.pop_front();
-  }
-
 #if defined(OS_ANDROID)
   // The date/time picker client is both a scoped_ptr member of this class and
   // a RenderViewObserver. Reset it to prevent double deletion.
@@ -1236,8 +1229,6 @@
   return focused_pepper_plugin_->IsPluginAcceptingCompositionEvents();
 }
 
-#endif  // ENABLE_PLUGINS
-
 void RenderViewImpl::PluginCrashed(const base::FilePath& plugin_path,
                                    base::ProcessId plugin_pid) {
   Send(new ViewHostMsg_CrashedPlugin(routing_id_, plugin_path, plugin_pid));
@@ -1276,6 +1267,45 @@
   return found;
 }
 
+void RenderViewImpl::SimulateImeSetComposition(
+    const string16& text,
+    const std::vector<WebKit::WebCompositionUnderline>& underlines,
+    int selection_start,
+    int selection_end) {
+  OnImeSetComposition(text, underlines, selection_start, selection_end);
+}
+
+void RenderViewImpl::SimulateImeConfirmComposition(
+    const string16& text,
+    const ui::Range& replacement_range) {
+  OnImeConfirmComposition(text, replacement_range, false);
+}
+
+#if defined(OS_WIN)
+void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
+  if (focused)
+    focused_plugin_id_ = plugin_id;
+  else
+    focused_plugin_id_ = -1;
+}
+#endif
+
+#if defined(OS_MACOSX)
+void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
+  Send(new ViewHostMsg_PluginFocusChanged(routing_id(), focused, plugin_id));
+}
+
+void RenderViewImpl::StartPluginIme() {
+  IPC::Message* msg = new ViewHostMsg_StartPluginIme(routing_id());
+  // This message can be sent during event-handling, and needs to be delivered
+  // within that context.
+  msg->set_unblock(true);
+  Send(msg);
+}
+#endif  // defined(OS_MACOSX)
+
+#endif  // ENABLE_PLUGINS
+
 void RenderViewImpl::TransferActiveWheelFlingAnimation(
     const WebKit::WebActiveWheelFlingParameters& params) {
   if (webview())
@@ -1419,8 +1449,6 @@
                         OnReleaseDisambiguationPopupDIB)
     IPC_MESSAGE_HANDLER(ViewMsg_WindowSnapshotCompleted,
                         OnWindowSnapshotCompleted)
-    IPC_MESSAGE_HANDLER(ViewMsg_AddMessageToConsole_ACK,
-                        OnConsoleMessageAck)
 
     // Have the super handle all other messages.
     IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
@@ -1679,16 +1707,6 @@
   target_url_status_ = TARGET_NONE;
 }
 
-void RenderViewImpl::OnConsoleMessageAck() {
-  if (!deferred_console_messages_.empty()) {
-    Send(deferred_console_messages_.front());
-    deferred_console_messages_.pop_front();
-    return;
-  }
-  --inflight_console_message_count_;
-  DCHECK(inflight_console_message_count_ >= 0);
-}
-
 void RenderViewImpl::OnCopy() {
   if (!webview())
     return;
@@ -2366,15 +2384,13 @@
 }
 
 WebStorageNamespace* RenderViewImpl::createSessionStorageNamespace() {
-  CHECK(session_storage_namespace_id_ !=
-        dom_storage::kInvalidSessionStorageNamespaceId);
+  CHECK(session_storage_namespace_id_ != kInvalidSessionStorageNamespaceId);
   return new WebStorageNamespaceImpl(session_storage_namespace_id_);
 }
 
 void RenderViewImpl::didAddMessageToConsole(
     const WebConsoleMessage& message, const WebString& source_name,
     unsigned source_line) {
-  static const int kMaximumInflightConsoleMessages = 10;
   logging::LogSeverity log_severity = logging::LOG_VERBOSE;
   switch (message.level) {
     case WebConsoleMessage::LevelDebug:
@@ -2393,19 +2409,11 @@
       NOTREACHED();
   }
 
-  IPC::Message* msg = new ViewHostMsg_AddMessageToConsole(
-      routing_id_, static_cast<int32>(log_severity), message.text,
-      static_cast<int32>(source_line), source_name);
-
-  if (RenderThreadImpl::current() &&
-      !RenderThreadImpl::current()->layout_test_mode() &&
-      inflight_console_message_count_ >= kMaximumInflightConsoleMessages) {
-    deferred_console_messages_.push_back(msg);
-    return;
-  }
-
-  Send(msg);
-  ++inflight_console_message_count_;
+  Send(new ViewHostMsg_AddMessageToConsole(routing_id_,
+                                           static_cast<int32>(log_severity),
+                                           message.text,
+                                           static_cast<int32>(source_line),
+                                           source_name));
 }
 
 void RenderViewImpl::printPage(WebFrame* frame) {
@@ -5635,7 +5643,7 @@
   if (webview())
     webview()->setIsActive(active);
 
-#if defined(OS_MACOSX)
+#if defined(ENABLE_PLUGINS) && defined(OS_MACOSX)
   std::set<WebPluginDelegateProxy*>::iterator plugin_it;
   for (plugin_it = plugin_delegates_.begin();
        plugin_it != plugin_delegates_.end(); ++plugin_it) {
@@ -5646,22 +5654,26 @@
 
 #if defined(OS_MACOSX)
 void RenderViewImpl::OnSetWindowVisibility(bool visible) {
+#if defined(ENABLE_PLUGINS)
   // Inform plugins that their container has changed visibility.
   std::set<WebPluginDelegateProxy*>::iterator plugin_it;
   for (plugin_it = plugin_delegates_.begin();
        plugin_it != plugin_delegates_.end(); ++plugin_it) {
     (*plugin_it)->SetContainerVisibility(visible);
   }
+#endif
 }
 
 void RenderViewImpl::OnWindowFrameChanged(const gfx::Rect& window_frame,
                                           const gfx::Rect& view_frame) {
+#if defined(ENABLE_PLUGINS)
   // Inform plugins that their window's frame has changed.
   std::set<WebPluginDelegateProxy*>::iterator plugin_it;
   for (plugin_it = plugin_delegates_.begin();
        plugin_it != plugin_delegates_.end(); ++plugin_it) {
     (*plugin_it)->WindowFrameChanged(window_frame, view_frame);
   }
+#endif
 }
 
 void RenderViewImpl::OnPluginImeCompositionCompleted(const string16& text,
@@ -5765,7 +5777,6 @@
   for (PepperPluginSet::iterator i = active_pepper_instances_.begin();
        i != active_pepper_instances_.end(); ++i)
     (*i)->PageVisibilityChanged(false);
-#endif
 
 #if defined(OS_MACOSX)
   // Inform NPAPI plugins that their container is no longer visible.
@@ -5775,6 +5786,7 @@
     (*plugin_it)->SetContainerVisibility(false);
   }
 #endif  // OS_MACOSX
+#endif // ENABLE_PLUGINS
 }
 
 void RenderViewImpl::OnWasShown(bool needs_repainting) {
@@ -5793,7 +5805,6 @@
   for (PepperPluginSet::iterator i = active_pepper_instances_.begin();
        i != active_pepper_instances_.end(); ++i)
     (*i)->PageVisibilityChanged(true);
-#endif
 
 #if defined(OS_MACOSX)
   // Inform NPAPI plugins that their container is now visible.
@@ -5803,6 +5814,7 @@
     (*plugin_it)->SetContainerVisibility(true);
   }
 #endif  // OS_MACOSX
+#endif  // ENABLE_PLUGINS
 }
 
 GURL RenderViewImpl::GetURLForGraphicsContext3D() {
@@ -5820,6 +5832,7 @@
 void RenderViewImpl::OnSetFocus(bool enable) {
   RenderWidget::OnSetFocus(enable);
 
+#if defined(ENABLE_PLUGINS)
   if (webview() && webview()->isActive()) {
     // Notify all NPAPI plugins.
     std::set<WebPluginDelegateProxy*>::iterator plugin_it;
@@ -5834,7 +5847,6 @@
       (*plugin_it)->SetContentAreaFocus(enable);
     }
   }
-#if defined(ENABLE_PLUGINS)
   // Notify all Pepper plugins.
   for (PepperPluginSet::iterator i = active_pepper_instances_.begin();
        i != active_pepper_instances_.end(); ++i)
@@ -5845,20 +5857,6 @@
     browser_plugin_manager_->UpdateFocusState();
 }
 
-void RenderViewImpl::SimulateImeSetComposition(
-    const string16& text,
-    const std::vector<WebKit::WebCompositionUnderline>& underlines,
-    int selection_start,
-    int selection_end) {
-  OnImeSetComposition(text, underlines, selection_start, selection_end);
-}
-
-void RenderViewImpl::SimulateImeConfirmComposition(
-    const string16& text,
-    const ui::Range& replacement_range) {
-  OnImeConfirmComposition(text, replacement_range, false);
-}
-
 void RenderViewImpl::OnImeSetComposition(
     const string16& text,
     const std::vector<WebKit::WebCompositionUnderline>& underlines,
@@ -5891,7 +5889,6 @@
     }
     return;
   }
-#endif
 
 #if defined(OS_WIN)
   // When a plug-in has focus, we create platform-specific IME data used by
@@ -5917,7 +5914,8 @@
     }
     return;
   }
-#endif
+#endif  // OS_WIN
+#endif  // ENABLE_PLUGINS
   RenderWidget::OnImeSetComposition(text,
                                     underlines,
                                     selection_start,
@@ -5962,7 +5960,6 @@
     pepper_composition_text_.clear();
     return;
   }
-#endif
 #if defined(OS_WIN)
   // Same as OnImeSetComposition(), we send the text from IMEs directly to
   // plug-ins. When we send IME text directly to plug-ins, we should not send
@@ -5976,7 +5973,8 @@
     }
     return;
   }
-#endif
+#endif  // OS_WIN
+#endif  // ENABLE_PLUGINS
   if (replacement_range.IsValid() && webview()) {
     // Select the text in |replacement_range|, it will then be replaced by
     // text added by the call to RenderWidget::OnImeConfirmComposition().
@@ -6129,29 +6127,6 @@
   return allow_partial_swap_;
 }
 
-#if defined(OS_WIN)
-void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
-  if (focused)
-    focused_plugin_id_ = plugin_id;
-  else
-    focused_plugin_id_ = -1;
-}
-#endif
-
-#if defined(OS_MACOSX)
-void RenderViewImpl::PluginFocusChanged(bool focused, int plugin_id) {
-  Send(new ViewHostMsg_PluginFocusChanged(routing_id(), focused, plugin_id));
-}
-
-void RenderViewImpl::StartPluginIme() {
-  IPC::Message* msg = new ViewHostMsg_StartPluginIme(routing_id());
-  // This message can be sent during event-handling, and needs to be delivered
-  // within that context.
-  msg->set_unblock(true);
-  Send(msg);
-}
-#endif  // defined(OS_MACOSX)
-
 bool RenderViewImpl::ScheduleFileChooser(
     const FileChooserParams& params,
     WebFileChooserCompletion* completion) {
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 46d9fe8..c57c03a 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -330,7 +330,6 @@
   bool GetPepperCaretBounds(gfx::Rect* rect);
 
   bool IsPepperAcceptingCompositionEvents() const;
-#endif
 
   // Notification that the given plugin has crashed.
   void PluginCrashed(const base::FilePath& plugin_path,
@@ -369,6 +368,8 @@
                      WebPluginInfo* plugin_info,
                      std::string* actual_mime_type);
 
+#endif  // ENABLE_PLUGINS
+
   void TransferActiveWheelFlingAnimation(
       const WebKit::WebActiveWheelFlingParameters& params);
 
@@ -932,7 +933,6 @@
   // The documentation for these functions should be in
   // content/common/*_messages.h for the message that the function is handling.
 
-  void OnConsoleMessageAck();
   void OnCopy();
   void OnCut();
   void OnDelete();
@@ -1565,12 +1565,6 @@
   ui::MenuSourceType context_menu_source_type_;
   gfx::Point touch_editing_context_menu_location_;
 
-  // Console log message throttling. Ensures that the memory bloat from
-  // runaway logging occurs in the renderer, evenutaly crashing it, rather
-  // than in the browser.
-  int inflight_console_message_count_;
-  std::deque<IPC::Message*> deferred_console_messages_;
-
   // ---------------------------------------------------------------------------
   // ADDING NEW DATA? Please see if it fits appropriately in one of the above
   // sections rather than throwing it randomly at the end. If you're adding a
diff --git a/content/renderer/text_input_client_observer.cc b/content/renderer/text_input_client_observer.cc
index ceeb023..1494ebb 100644
--- a/content/renderer/text_input_client_observer.cc
+++ b/content/renderer/text_input_client_observer.cc
@@ -56,18 +56,24 @@
 #endif
   {
     WebKit::WebFrame* frame = webview()->focusedFrame();
-    WebKit::WebRect web_rect;
-    frame->firstRectForCharacterRange(range.start(), range.length(), web_rect);
-    rect = web_rect;
+    if (frame) {
+      WebKit::WebRect web_rect;
+      frame->firstRectForCharacterRange(range.start(), range.length(),
+                                        web_rect);
+      rect = web_rect;
+    }
   }
   Send(new TextInputClientReplyMsg_GotFirstRectForRange(routing_id(), rect));
 }
 
 void TextInputClientObserver::OnStringForRange(ui::Range range) {
 #if defined(OS_MACOSX)
-  NSAttributedString* string =
-      WebKit::WebSubstringUtil::attributedSubstringInRange(
-          webview()->focusedFrame(), range.start(), range.length());
+  NSAttributedString* string = nil;
+  WebKit::WebFrame* frame = webview()->focusedFrame();
+  if (frame) {
+    string = WebKit::WebSubstringUtil::attributedSubstringInRange(
+        frame, range.start(), range.length());
+  }
   scoped_ptr<const mac::AttributedStringCoder::EncodedString> encoded(
       mac::AttributedStringCoder::Encode(string));
   Send(new TextInputClientReplyMsg_GotStringForRange(routing_id(),
diff --git a/webkit/renderer/cpp_binding_example.cc b/content/test/cpp_binding_example.cc
similarity index 92%
rename from webkit/renderer/cpp_binding_example.cc
rename to content/test/cpp_binding_example.cc
index 43b4ede..3c7630d 100644
--- a/webkit/renderer/cpp_binding_example.cc
+++ b/content/test/cpp_binding_example.cc
@@ -1,18 +1,19 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
 
-// This file contains the definition for CppBindingExample, which is used in
-// cpp_bound_class_unittest.
-
-#include "cpp_binding_example.h"
+#include "content/test/cpp_binding_example.h"
 
 #include <stdio.h>
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 
-namespace webkit_glue {
+using webkit_glue::CppArgumentList;
+using webkit_glue::CppBoundClass;
+using webkit_glue::CppVariant;
+
+namespace content {
 
 namespace {
 
@@ -32,7 +33,7 @@
   CppVariant value_;
 };
 
-}
+}  // namespace
 
 CppBindingExample::CppBindingExample() {
   // Map properties.  It's recommended, but not required, that the JavaScript
@@ -134,4 +135,4 @@
   printf("Error: unknown JavaScript method invoked.\n");
 }
 
-}  // namespace webkit_glue
+}  // namespace content
diff --git a/webkit/renderer/cpp_binding_example.h b/content/test/cpp_binding_example.h
similarity index 73%
rename from webkit/renderer/cpp_binding_example.h
rename to content/test/cpp_binding_example.h
index ee8568d..f594ae7 100644
--- a/webkit/renderer/cpp_binding_example.h
+++ b/content/test/cpp_binding_example.h
@@ -1,7 +1,10 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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 CONTENT_TEST_CPP_BINDING_EXAMPLE_H_
+#define CONTENT_TEST_CPP_BINDING_EXAMPLE_H_
+
 /*
   CppBindingExample class:
   This provides an example of how to use the CppBoundClass to create methods
@@ -30,14 +33,11 @@
   </script>
 */
 
-#ifndef CPP_BINDING_EXAMPLE_H__
-#define CPP_BINDING_EXAMPLE_H__
-
 #include "webkit/renderer/cpp_bound_class.h"
 
-namespace webkit_glue {
+namespace content {
 
-class CppBindingExample : public CppBoundClass {
+class CppBindingExample : public webkit_glue::CppBoundClass {
  public:
   // The default constructor initializes the property and method lists needed
   // to bind this class to a JS object.
@@ -55,28 +55,32 @@
   //
 
   // Returns the value that was passed in as its first (only) argument.
-  void echoValue(const CppArgumentList& args, CppVariant* result);
+  void echoValue(const webkit_glue::CppArgumentList& args,
+                 webkit_glue::CppVariant* result);
 
   // Returns a hard-coded value of the same type (bool, number (double),
   // string, or null) that was passed in as an argument.
-  void echoType(const CppArgumentList& args, CppVariant* result);
+  void echoType(const webkit_glue::CppArgumentList& args,
+                webkit_glue::CppVariant* result);
 
   // Returns the sum of the (first) two arguments as a double, if they are both
   // numbers (integers or doubles).  Otherwise returns null.
-  void plus(const CppArgumentList& args, CppVariant* result);
+  void plus(const webkit_glue::CppArgumentList& args,
+            webkit_glue::CppVariant* result);
 
   // Always returns the same value -- an example of a read-only property.
-  void same(CppVariant* result);
+  void same(webkit_glue::CppVariant* result);
 
   // Invoked when a nonexistent method is called on this example object, this
   // prints an error message.
-  void fallbackMethod(const CppArgumentList& args, CppVariant* result);
+  void fallbackMethod(const webkit_glue::CppArgumentList& args,
+                      webkit_glue::CppVariant* result);
 
   // These properties will also be exposed to JavaScript.
-  CppVariant my_value;
-  CppVariant my_other_value;
+  webkit_glue::CppVariant my_value;
+  webkit_glue::CppVariant my_other_value;
 };
 
-}  // namespace webkit_glue
+}  // namespace content
 
-#endif  // CPP_BINDING_EXAMPLE_H__
+#endif  // CONTENT_TEST_CPP_BINDING_EXAMPLE_H_
diff --git a/content/test/data/media/peerconnection-call.html b/content/test/data/media/peerconnection-call.html
index 6a9219d..f979006 100644
--- a/content/test/data/media/peerconnection-call.html
+++ b/content/test/data/media/peerconnection-call.html
@@ -234,6 +234,14 @@
     }
   }
 
+  // Test call with a stream that has been created by getUserMedia, clone
+  // the stream to a cloned stream, send them via the same peer connection.
+  function addTwoMediaStreamsToOneConnection() {
+    createConnections(null);
+    navigator.webkitGetUserMedia({audio:true, video:true},
+        CloneStreamAndAddTwoStreamstoOneConnection, printGetUserMediaError);
+  }
+
   function onToneChange(tone) {
     gSentTones += tone.tone;
     document.title = gSentTones;
@@ -281,6 +289,45 @@
     negotiate();
   }
 
+  function verifyHasOneAudioAndVideoTrack(stream) {    
+    expectEquals(1, stream.getAudioTracks().length);
+    expectEquals(1, stream.getVideoTracks().length);
+  }
+
+  // Called if getUserMedia succeeds, then clone the stream, send two streams
+  // from one peer connection.
+  function CloneStreamAndAddTwoStreamstoOneConnection(localStream) {
+    displayAndRemember(localStream);
+    var clonedStream = new webkitMediaStream();
+    clonedStream.addTrack(localStream.getVideoTracks()[0]);
+    clonedStream.addTrack(localStream.getAudioTracks()[0]);
+    gFirstConnection.addStream(localStream);
+    gFirstConnection.addStream(clonedStream);
+
+    // Verify the local streams are correct.
+    expectEquals(2, gFirstConnection.getLocalStreams().length);
+    verifyHasOneAudioAndVideoTrack(gFirstConnection.getLocalStreams()[0]);
+    verifyHasOneAudioAndVideoTrack(gFirstConnection.getLocalStreams()[1]);
+
+    // The remote side should receive two streams. After that, verify the
+    // remote side has the correct number of streams and tracks.
+    addExpectedEvent();
+    addExpectedEvent();
+    gSecondConnection.onaddstream = function(event) {
+      eventOccured();
+    }
+    setAllEventsOccuredHandler(function() {
+      // Negotiation complete, verify remote streams on the receiving side.
+      expectEquals(2, gSecondConnection.getRemoteStreams().length);
+      verifyHasOneAudioAndVideoTrack(gSecondConnection.getRemoteStreams()[0]);
+      verifyHasOneAudioAndVideoTrack(gSecondConnection.getRemoteStreams()[1]);
+
+      document.title = "OK";
+    });
+
+    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.
@@ -389,7 +436,7 @@
       <!-- Canvases are named after their corresponding video elements. -->
       <td><canvas width="320" height="240" id="remote-view-1-canvas"
           style="display:none"></canvas></td>
-      <td><canvas width="320" height="240" id="remote-view-2-canvas">
+      <td><canvas width="320" height="240" id="remote-view-2-canvas"
           style="display:none"></canvas></td>
     </tr>
   </table>
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 2fb6cff..069d5b6 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -384,23 +384,17 @@
     base::TimeTicks start_time = base::TimeTicks::Now();
     EnsureNSPRInit();
 
-    // We *must* have NSS >= 3.12.3.  See bug 26448.
+    // We *must* have NSS >= 3.14.3.
     COMPILE_ASSERT(
-        (NSS_VMAJOR == 3 && NSS_VMINOR == 12 && NSS_VPATCH >= 3) ||
-        (NSS_VMAJOR == 3 && NSS_VMINOR > 12) ||
+        (NSS_VMAJOR == 3 && NSS_VMINOR == 14 && NSS_VPATCH >= 3) ||
+        (NSS_VMAJOR == 3 && NSS_VMINOR > 14) ||
         (NSS_VMAJOR > 3),
         nss_version_check_failed);
     // Also check the run-time NSS version.
     // NSS_VersionCheck is a >= check, not strict equality.
-    if (!NSS_VersionCheck("3.12.3")) {
-      // It turns out many people have misconfigured NSS setups, where
-      // their run-time NSPR doesn't match the one their NSS was compiled
-      // against.  So rather than aborting, complain loudly.
-      LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed.  "
-                    "We depend on NSS >= 3.12.3, and this error is not fatal "
-                    "only because many people have busted NSS setups (for "
-                    "example, using the wrong version of NSPR). "
-                    "Please upgrade to the latest NSS and NSPR, and if you "
+    if (!NSS_VersionCheck("3.14.3")) {
+      LOG(FATAL) << "NSS_VersionCheck(\"3.14.3\") failed. NSS >= 3.14.3 is "
+                    "required. Please upgrade to the latest NSS, and if you "
                     "still get this error, contact your distribution "
                     "maintainer.";
     }
diff --git a/crypto/signature_creator_nss.cc b/crypto/signature_creator_nss.cc
index 5a9ad2e..bc8dc44 100644
--- a/crypto/signature_creator_nss.cc
+++ b/crypto/signature_creator_nss.cc
@@ -67,11 +67,7 @@
 }
 
 bool SignatureCreator::Update(const uint8* data_part, int data_part_len) {
-  // TODO(wtc): Remove this const_cast when we require NSS 3.12.5.
-  // See NSS bug https://bugzilla.mozilla.org/show_bug.cgi?id=518255
-  SECStatus rv = SGN_Update(sign_context_,
-                            const_cast<unsigned char*>(data_part),
-                            data_part_len);
+  SECStatus rv = SGN_Update(sign_context_, data_part, data_part_len);
   if (rv != SECSuccess) {
     NOTREACHED();
     return false;
diff --git a/extensions/OWNERS b/extensions/OWNERS
index 16f17f1..a6cd87d 100644
--- a/extensions/OWNERS
+++ b/extensions/OWNERS
@@ -5,6 +5,7 @@
 jyasskin@chromium.org
 kalman@chromium.org
 koz@chromium.org
+mek@chromium.org
 miket@chromium.org
 mpcomplete@chromium.org
 yoz@chromium.org
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index 97f1715..cdbfc9f 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -53,16 +53,17 @@
   explicit GLInProcessContextImpl();
   virtual ~GLInProcessContextImpl();
 
-  bool Initialize(bool is_offscreen,
+  bool Initialize(scoped_refptr<gfx::GLSurface> surface,
+                  bool is_offscreen,
                   bool share_resources,
                   gfx::AcceleratedWidget window,
                   const gfx::Size& size,
                   const char* allowed_extensions,
-                  const int32* attrib_list,
-                  gfx::GpuPreference gpu_preference,
-                  const base::Closure& context_lost_callback);
+                  const GLInProcessContextAttribs& attribs,
+                  gfx::GpuPreference gpu_preference);
 
   // GLInProcessContext implementation:
+  virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
   virtual void SignalSyncPoint(unsigned sync_point,
                                const base::Closure& callback) OVERRIDE;
   virtual void SignalQuery(unsigned query, const base::Closure& callback)
@@ -79,7 +80,7 @@
   void Destroy();
   void PollQueryCallbacks();
   void CallQueryCallback(size_t index);
-  void OnContextLost(const base::Closure& callback);
+  void OnContextLost();
   void OnSignalSyncPoint(const base::Closure& callback);
 
   scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
@@ -92,6 +93,7 @@
 
   unsigned int share_group_id_;
   bool context_lost_;
+  base::Closure context_lost_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
 };
@@ -147,9 +149,16 @@
   return gles2_implementation_.get();
 }
 
-void GLInProcessContextImpl::OnContextLost(const base::Closure& callback) {
+void GLInProcessContextImpl::SetContextLostCallback(
+    const base::Closure& callback) {
+  context_lost_callback_ = callback;
+}
+
+void GLInProcessContextImpl::OnContextLost() {
   context_lost_ = true;
-  callback.Run();
+  if (!context_lost_callback_.is_null()) {
+    context_lost_callback_.Run();
+  }
 }
 
 void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) {
@@ -159,47 +168,63 @@
 }
 
 bool GLInProcessContextImpl::Initialize(
+    scoped_refptr<gfx::GLSurface> surface,
     bool is_offscreen,
     bool share_resources,
     gfx::AcceleratedWidget window,
     const gfx::Size& size,
     const char* allowed_extensions,
-    const int32* attrib_list,
-    gfx::GpuPreference gpu_preference,
-    const base::Closure& context_lost_callback) {
+    const GLInProcessContextAttribs& attribs,
+    gfx::GpuPreference gpu_preference) {
   DCHECK(size.width() >= 0 && size.height() >= 0);
 
-  std::vector<int32> attribs;
-  while (attrib_list) {
-    int32 attrib = *attrib_list++;
-    switch (attrib) {
-      // Known attributes
-      case ALPHA_SIZE:
-      case BLUE_SIZE:
-      case GREEN_SIZE:
-      case RED_SIZE:
-      case DEPTH_SIZE:
-      case STENCIL_SIZE:
-      case SAMPLES:
-      case SAMPLE_BUFFERS:
-        attribs.push_back(attrib);
-        attribs.push_back(*attrib_list++);
-        break;
-      case NONE:
-        attribs.push_back(attrib);
-        attrib_list = NULL;
-        break;
-      default:
-        attribs.push_back(NONE);
-        attrib_list = NULL;
-        break;
-    }
+  const int32 ALPHA_SIZE     = 0x3021;
+  const int32 BLUE_SIZE      = 0x3022;
+  const int32 GREEN_SIZE     = 0x3023;
+  const int32 RED_SIZE       = 0x3024;
+  const int32 DEPTH_SIZE     = 0x3025;
+  const int32 STENCIL_SIZE   = 0x3026;
+  const int32 SAMPLES        = 0x3031;
+  const int32 SAMPLE_BUFFERS = 0x3032;
+  const int32 NONE           = 0x3038;
+
+  std::vector<int32> attrib_vector;
+  if (attribs.alpha_size >= 0) {
+    attrib_vector.push_back(ALPHA_SIZE);
+    attrib_vector.push_back(attribs.alpha_size);
   }
+  if (attribs.blue_size >= 0) {
+    attrib_vector.push_back(BLUE_SIZE);
+    attrib_vector.push_back(attribs.blue_size);
+  }
+  if (attribs.green_size >= 0) {
+    attrib_vector.push_back(GREEN_SIZE);
+    attrib_vector.push_back(attribs.green_size);
+  }
+  if (attribs.red_size >= 0) {
+    attrib_vector.push_back(RED_SIZE);
+    attrib_vector.push_back(attribs.red_size);
+  }
+  if (attribs.depth_size >= 0) {
+    attrib_vector.push_back(DEPTH_SIZE);
+    attrib_vector.push_back(attribs.depth_size);
+  }
+  if (attribs.stencil_size >= 0) {
+    attrib_vector.push_back(STENCIL_SIZE);
+    attrib_vector.push_back(attribs.stencil_size);
+  }
+  if (attribs.samples >= 0) {
+    attrib_vector.push_back(SAMPLES);
+    attrib_vector.push_back(attribs.samples);
+  }
+  if (attribs.sample_buffers >= 0) {
+    attrib_vector.push_back(SAMPLE_BUFFERS);
+    attrib_vector.push_back(attribs.sample_buffers);
+  }
+  attrib_vector.push_back(NONE);
 
   base::Closure wrapped_callback =
-      base::Bind(&GLInProcessContextImpl::OnContextLost,
-                 AsWeakPtr(),
-                 context_lost_callback);
+      base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr());
   command_buffer_.reset(new InProcessCommandBuffer());
 
   scoped_ptr<base::AutoLock> scoped_shared_context_lock;
@@ -223,15 +248,16 @@
     if (!share_group && !++share_group_id_)
         ++share_group_id_;
   }
-  if (!command_buffer_->Initialize(is_offscreen,
-                              share_resources,
-                              window,
-                              size,
-                              allowed_extensions,
-                              attribs,
-                              gpu_preference,
-                              wrapped_callback,
-                              share_group_id_)) {
+  if (!command_buffer_->Initialize(surface,
+                                   is_offscreen,
+                                   share_resources,
+                                   window,
+                                   size,
+                                   allowed_extensions,
+                                   attrib_vector,
+                                   gpu_preference,
+                                   wrapped_callback,
+                                   share_group_id_)) {
     LOG(INFO) << "Failed to initialize InProcessCommmandBuffer";
     return false;
   }
@@ -337,6 +363,16 @@
 
 }  // anonymous namespace
 
+GLInProcessContextAttribs::GLInProcessContextAttribs()
+    : alpha_size(-1),
+      blue_size(-1),
+      green_size(-1),
+      red_size(-1),
+      depth_size(-1),
+      stencil_size(-1),
+      samples(-1),
+      sample_buffers(-1) {}
+
 // static
 GLInProcessContext* GLInProcessContext::CreateContext(
     bool is_offscreen,
@@ -344,20 +380,42 @@
     const gfx::Size& size,
     bool share_resources,
     const char* allowed_extensions,
-    const int32* attrib_list,
-    gfx::GpuPreference gpu_preference,
-    const base::Closure& callback) {
+    const GLInProcessContextAttribs& attribs,
+    gfx::GpuPreference gpu_preference) {
   scoped_ptr<GLInProcessContextImpl> context(
       new GLInProcessContextImpl());
   if (!context->Initialize(
+      NULL /* surface */,
       is_offscreen,
       share_resources,
       window,
       size,
       allowed_extensions,
-      attrib_list,
-      gpu_preference,
-      callback))
+      attribs,
+      gpu_preference))
+    return NULL;
+
+  return context.release();
+}
+
+// static
+GLInProcessContext* GLInProcessContext::CreateWithSurface(
+    scoped_refptr<gfx::GLSurface> surface,
+    bool share_resources,
+    const char* allowed_extensions,
+    const GLInProcessContextAttribs& attribs,
+    gfx::GpuPreference gpu_preference) {
+  scoped_ptr<GLInProcessContextImpl> context(
+      new GLInProcessContextImpl());
+  if (!context->Initialize(
+      surface,
+      surface->IsOffscreen(),
+      share_resources,
+      gfx::kNullAcceleratedWidget,
+      surface->GetSize(),
+      allowed_extensions,
+      attribs,
+      gpu_preference))
     return NULL;
 
   return context.release();
diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h
index 2d0754b..09f8140 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "gles2_impl_export.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_preference.h"
 
 namespace gfx {
@@ -23,6 +24,20 @@
 
 class GpuMemoryBufferFactory;
 
+// The default uninitialized value is -1.
+struct GLES2_IMPL_EXPORT GLInProcessContextAttribs {
+  GLInProcessContextAttribs();
+
+  int32 alpha_size;
+  int32 blue_size;
+  int32 green_size;
+  int32 red_size;
+  int32 depth_size;
+  int32 stencil_size;
+  int32 samples;
+  int32 sample_buffers;
+};
+
 class GLES2_IMPL_EXPORT GLInProcessContext {
  public:
   virtual ~GLInProcessContext() {}
@@ -30,20 +45,6 @@
   // Must be called before any GLInProcessContext instances are created.
   static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
 
-  // GLInProcessContext configuration attributes. These are the same as used by
-  // EGL. Attributes are matched using a closest fit algorithm.
-  enum Attribute {
-    ALPHA_SIZE     = 0x3021,
-    BLUE_SIZE      = 0x3022,
-    GREEN_SIZE     = 0x3023,
-    RED_SIZE       = 0x3024,
-    DEPTH_SIZE     = 0x3025,
-    STENCIL_SIZE   = 0x3026,
-    SAMPLES        = 0x3031,
-    SAMPLE_BUFFERS = 0x3032,
-    NONE           = 0x3038  // Attrib list = terminator
-  };
-
   // Create a GLInProcessContext, if |is_offscreen| is true, renders to an
   // offscreen context. |attrib_list| must be NULL or a NONE-terminated list
   // of attribute/value pairs.
@@ -53,9 +54,21 @@
       const gfx::Size& size,
       bool share_resources,
       const char* allowed_extensions,
-      const int32* attrib_list,
-      gfx::GpuPreference gpu_preference,
-      const base::Closure& callback);
+      const GLInProcessContextAttribs& attribs,
+      gfx::GpuPreference gpu_preference);
+
+  // Create context with the provided GLSurface. All other arguments match
+  // CreateContext factory above. Can only be called if the command buffer
+  // service runs on the same thread as this client because GLSurface is not
+  // thread safe.
+  static GLInProcessContext* CreateWithSurface(
+      scoped_refptr<gfx::GLSurface> surface,
+      bool share_resources,
+      const char* allowed_extensions,
+      const GLInProcessContextAttribs& attribs,
+      gfx::GpuPreference gpu_preference);
+
+  virtual void SetContextLostCallback(const base::Closure& callback) = 0;
 
   virtual void SignalSyncPoint(unsigned sync_point,
                                const base::Closure& callback) = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4f63037..a9b1f1e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1584,8 +1584,6 @@
   void ProcessPendingReadPixels();
   void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer);
 
-  void ForceCompileShaderIfPending(Shader* shader);
-
   // Generate a member function prototype for each command in an automated and
   // typesafe way.
   #define GLES2_CMD_OP(name) \
@@ -5652,23 +5650,6 @@
                      std::string("PERFORMANCE WARNING: ") + msg);
 }
 
-void GLES2DecoderImpl::ForceCompileShaderIfPending(Shader* shader) {
-  if (shader->compilation_status() ==
-      Shader::PENDING_DEFERRED_COMPILE) {
-    ShaderTranslator* translator = NULL;
-    if (use_shader_translator_) {
-      translator = shader->shader_type() == GL_VERTEX_SHADER ?
-          vertex_translator_.get() : fragment_translator_.get();
-    }
-    // We know there will be no errors, because we only defer compilation on
-    // shaders that were previously compiled successfully.
-    program_manager()->ForceCompileShader(shader->deferred_compilation_source(),
-                                          shader,
-                                          translator,
-                                          feature_info_.get());
-  }
-}
-
 void GLES2DecoderImpl::UpdateStreamTextureIfNeeded(Texture* texture) {
   if (texture && texture->IsStreamTexture()) {
     DCHECK(stream_texture_manager());
@@ -6366,7 +6347,6 @@
       *params = shader->log_info() ? shader->log_info()->size() + 1 : 0;
       return;
     case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
-      ForceCompileShaderIfPending(shader);
       *params = shader->translated_source() ?
           shader->translated_source()->size() + 1 : 0;
       return;
@@ -6402,7 +6382,6 @@
     bucket->SetSize(0);
     return error::kNoError;
   }
-  ForceCompileShaderIfPending(shader);
 
   bucket->SetFromString(shader->translated_source() ?
       shader->translated_source()->c_str() : NULL);
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 766a7e0..ccbfb32 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -20,6 +20,7 @@
 #include "base/logging.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop_proxy.h"
+#include "base/sequence_checker.h"
 #include "base/threading/thread.h"
 #include "gpu/command_buffer/common/id_allocator.h"
 #include "gpu/command_buffer/service/command_buffer_service.h"
@@ -32,7 +33,6 @@
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_image.h"
 #include "ui/gl/gl_share_group.h"
-#include "ui/gl/gl_surface.h"
 
 namespace gpu {
 
@@ -244,6 +244,7 @@
 }
 
 bool InProcessCommandBuffer::IsContextLost() {
+  CheckSequencedThread();
   if (context_lost_ || !command_buffer_) {
     return true;
   }
@@ -252,11 +253,13 @@
 }
 
 void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) {
+  CheckSequencedThread();
   DCHECK(!surface_->IsOffscreen());
   surface_->Resize(size);
 }
 
 bool InProcessCommandBuffer::MakeCurrent() {
+  CheckSequencedThread();
   command_buffer_lock_.AssertAcquired();
 
   if (!context_lost_ && decoder_->MakeCurrent())
@@ -268,6 +271,7 @@
 }
 
 void InProcessCommandBuffer::PumpCommands() {
+  CheckSequencedThread();
   command_buffer_lock_.AssertAcquired();
 
   if (!MakeCurrent())
@@ -277,12 +281,14 @@
 }
 
 bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) {
+  CheckSequencedThread();
   command_buffer_lock_.AssertAcquired();
   command_buffer_->SetGetBuffer(transfer_buffer_id);
   return true;
 }
 
 bool InProcessCommandBuffer::Initialize(
+    scoped_refptr<gfx::GLSurface> surface,
     bool is_offscreen,
     bool share_resources,
     gfx::AcceleratedWidget window,
@@ -297,8 +303,13 @@
   context_lost_callback_ = WrapCallback(context_lost_callback);
   share_group_id_ = share_group_id;
 
-  base::WaitableEvent completion(true, false);
-  bool result = false;
+  if (surface) {
+    // GPU thread must be the same as client thread due to GLSurface not being
+    // thread safe.
+    sequence_checker_.reset(new base::SequenceChecker);
+    surface_ = surface;
+  }
+
   base::Callback<bool(void)> init_task =
       base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread,
                  base::Unretained(this),
@@ -308,6 +319,9 @@
                  allowed_extensions,
                  attribs,
                  gpu_preference);
+
+  base::WaitableEvent completion(true, false);
+  bool result = false;
   QueueTask(
       base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion));
   completion.Wait();
@@ -321,6 +335,7 @@
     const char* allowed_extensions,
     const std::vector<int32>& attribs,
     gfx::GpuPreference gpu_preference) {
+  CheckSequencedThread();
   // Use one share group for all contexts.
   CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group,
                          (new gfx::GLShareGroup));
@@ -377,10 +392,12 @@
 
   decoder_->set_engine(gpu_scheduler_.get());
 
-  if (is_offscreen)
-    surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
-  else
-    surface_ = gfx::GLSurface::CreateViewGLSurface(window);
+  if (!surface_) {
+    if (is_offscreen)
+      surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
+    else
+      surface_ = gfx::GLSurface::CreateViewGLSurface(window);
+  }
 
   if (!surface_.get()) {
     LOG(ERROR) << "Could not create GLSurface.";
@@ -448,6 +465,7 @@
 }
 
 void InProcessCommandBuffer::Destroy() {
+  CheckSequencedThread();
   base::WaitableEvent completion(true, false);
   bool result = false;
   base::Callback<bool(void)> destroy_task = base::Bind(
@@ -458,6 +476,7 @@
 }
 
 bool InProcessCommandBuffer::DestroyOnGpuThread() {
+  CheckSequencedThread();
   command_buffer_.reset();
   // Clean up GL resources if possible.
   bool have_context = context_ && context_->MakeCurrent(surface_);
@@ -472,9 +491,15 @@
   return true;
 }
 
+void InProcessCommandBuffer::CheckSequencedThread() {
+  DCHECK(!sequence_checker_ ||
+         sequence_checker_->CalledOnValidSequencedThread());
+}
+
 unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer(
     gfx::GpuMemoryBufferHandle buffer,
     gfx::Size size) {
+  CheckSequencedThread();
   unsigned int image_id;
   {
     // TODO: ID allocation should go through CommandBuffer
@@ -494,12 +519,14 @@
     gfx::GpuMemoryBufferHandle buffer,
     gfx::Size size,
     unsigned int image_id) {
+  CheckSequencedThread();
   scoped_refptr<gfx::GLImage> gl_image =
       gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size);
    decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id);
 }
 
 void InProcessCommandBuffer::RemoveImage(unsigned int image_id) {
+  CheckSequencedThread();
   {
     // TODO: ID allocation should go through CommandBuffer
     base::AutoLock lock(command_buffer_lock_);
@@ -514,10 +541,12 @@
 }
 
 void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) {
+  CheckSequencedThread();
   decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id);
 }
 
 void InProcessCommandBuffer::OnContextLost() {
+  CheckSequencedThread();
   if (!context_lost_callback_.is_null()) {
     context_lost_callback_.Run();
     context_lost_callback_.Reset();
@@ -535,6 +564,7 @@
 }
 
 CommandBuffer::State InProcessCommandBuffer::GetStateFast() {
+  CheckSequencedThread();
   base::AutoLock lock(state_after_last_flush_lock_);
   if (state_after_last_flush_.generation - last_state_.generation < 0x80000000U)
     last_state_ = state_after_last_flush_;
@@ -542,19 +572,23 @@
 }
 
 CommandBuffer::State InProcessCommandBuffer::GetState() {
+  CheckSequencedThread();
   return GetStateFast();
 }
 
 CommandBuffer::State InProcessCommandBuffer::GetLastState() {
+  CheckSequencedThread();
   return last_state_;
 }
 
 int32 InProcessCommandBuffer::GetLastToken() {
+  CheckSequencedThread();
   GetStateFast();
   return last_state_.token;
 }
 
 void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) {
+  CheckSequencedThread();
   ScopedEvent handle_flush(&flush_event_);
   base::AutoLock lock(command_buffer_lock_);
   command_buffer_->Flush(put_offset);
@@ -568,6 +602,7 @@
 }
 
 void InProcessCommandBuffer::Flush(int32 put_offset) {
+  CheckSequencedThread();
   if (last_state_.error != gpu::error::kNoError)
     return;
 
@@ -583,6 +618,7 @@
 
 CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset,
                                                        int32 last_known_get) {
+  CheckSequencedThread();
   if (put_offset == last_known_get || last_state_.error != gpu::error::kNoError)
     return last_state_;
 
@@ -598,6 +634,7 @@
 }
 
 void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) {
+  CheckSequencedThread();
   if (last_state_.error != gpu::error::kNoError)
     return;
 
@@ -614,11 +651,13 @@
 
 gpu::Buffer InProcessCommandBuffer::CreateTransferBuffer(size_t size,
                                                          int32* id) {
+  CheckSequencedThread();
   base::AutoLock lock(command_buffer_lock_);
   return command_buffer_->CreateTransferBuffer(size, id);
 }
 
 void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) {
+  CheckSequencedThread();
   base::Closure task = base::Bind(&CommandBuffer::DestroyTransferBuffer,
                                   base::Unretained(command_buffer_.get()),
                                   id);
@@ -637,10 +676,12 @@
 }
 void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point,
                                              const base::Closure& callback) {
+  CheckSequencedThread();
   QueueTask(WrapCallback(callback));
 }
 
 gpu::error::Error InProcessCommandBuffer::GetLastError() {
+  CheckSequencedThread();
   return last_state_.error;
 }
 
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index d2e103a..9bdbd49 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -17,8 +17,13 @@
 #include "gpu/gpu_export.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_preference.h"
 
+namespace base {
+class SequenceChecker;
+}
+
 namespace gfx {
 class GLContext;
 class GLImage;
@@ -57,7 +62,11 @@
 
   static void EnableVirtualizedContext();
 
-  bool Initialize(bool is_offscreen,
+  // If |surface| is not NULL, use it directly; in this case, the command
+  // buffer gpu thread must be the same as the client thread. Otherwise create
+  // a new GLSurface.
+  bool Initialize(scoped_refptr<gfx::GLSurface> surface,
+                  bool is_offscreen,
                   bool share_resources,
                   gfx::AcceleratedWidget window,
                   const gfx::Size& size,
@@ -118,6 +127,7 @@
   base::Closure WrapCallback(const base::Closure& callback);
   State GetStateFast();
   void QueueTask(const base::Closure& task) { queue_->QueueTask(task); }
+  void CheckSequencedThread();
 
   // Callbacks:
   void OnContextLost();
@@ -149,6 +159,10 @@
   State state_after_last_flush_;
   base::Lock state_after_last_flush_lock_;
 
+  // Only used with explicit scheduling and the gpu thread is the same as
+  // the client thread.
+  scoped_ptr<base::SequenceChecker> sequence_checker_;
+
   DISALLOW_COPY_AND_ASSIGN(InProcessCommandBuffer);
 };
 
diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc
index 3207f7c..e09d132 100644
--- a/gpu/command_buffer/service/memory_program_cache.cc
+++ b/gpu/command_buffer/service/memory_program_cache.cc
@@ -117,10 +117,12 @@
     const ShaderCacheCallback& shader_callback) {
   char a_sha[kHashLength];
   char b_sha[kHashLength];
+  DCHECK(shader_a && shader_a->signature_source() &&
+         shader_b && shader_b->signature_source());
   ComputeShaderHash(
-      *shader_a->deferred_compilation_source(), translator_a, a_sha);
+      *shader_a->signature_source(), translator_a, a_sha);
   ComputeShaderHash(
-      *shader_b->deferred_compilation_source(), translator_b, b_sha);
+      *shader_b->signature_source(), translator_b, b_sha);
 
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
@@ -189,10 +191,12 @@
 
   char a_sha[kHashLength];
   char b_sha[kHashLength];
+  DCHECK(shader_a && shader_a->signature_source() &&
+         shader_b && shader_b->signature_source());
   ComputeShaderHash(
-      *shader_a->deferred_compilation_source(), translator_a, a_sha);
+      *shader_a->signature_source(), translator_a, a_sha);
   ComputeShaderHash(
-      *shader_b->deferred_compilation_source(), translator_b, b_sha);
+      *shader_b->signature_source(), translator_b, b_sha);
 
   char sha[kHashLength];
   ComputeProgramHash(a_sha,
@@ -243,7 +247,7 @@
                                    this));
 
   UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
-                         curr_size_bytes_ / 1024);
+                       curr_size_bytes_ / 1024);
 }
 
 void MemoryProgramCache::LoadProgram(const std::string& program) {
@@ -289,10 +293,6 @@
                                      fragment_uniforms,
                                      this));
 
-    ShaderCompilationSucceededSha(proto->sha());
-    ShaderCompilationSucceededSha(proto->vertex_shader().sha());
-    ShaderCompilationSucceededSha(proto->fragment_shader().sha());
-
     UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
                          curr_size_bytes_ / 1024);
   } else {
@@ -324,14 +324,12 @@
       uniform_map_1_(uniform_map_1),
       program_cache_(program_cache) {
   program_cache_->curr_size_bytes_ += length_;
-  program_cache_->LinkedProgramCacheSuccess(program_hash,
-                                            shader_0_hash_,
-                                            shader_1_hash_);
+  program_cache_->LinkedProgramCacheSuccess(program_hash);
 }
 
 MemoryProgramCache::ProgramCacheValue::~ProgramCacheValue() {
   program_cache_->curr_size_bytes_ -= length_;
-  program_cache_->Evict(program_hash_, shader_0_hash_, shader_1_hash_);
+  program_cache_->Evict(program_hash_);
 }
 
 }  // namespace gles2
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index 603c21e..83fc12a 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -124,8 +124,6 @@
 
     vertex_shader_->UpdateSource("bbbalsldkdkdkd");
     fragment_shader_->UpdateSource("bbbal   sldkdkdkas 134 ad");
-    vertex_shader_->FlagSourceAsCompiled(true);
-    fragment_shader_->FlagSourceAsCompiled(true);
 
     vertex_shader_->SetStatus(true, NULL, NULL);
     fragment_shader_->SetStatus(true, NULL, NULL);
@@ -202,9 +200,9 @@
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
   EXPECT_EQ(1, shader_cache_count());
@@ -227,9 +225,9 @@
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
   EXPECT_EQ(1, shader_cache_count());
@@ -238,9 +236,9 @@
 
   cache_->LoadProgram(shader_cache_shader());
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
 }
@@ -391,9 +389,9 @@
                                        base::Unretained(this)));
 
   const std::string vertex_orig_source =
-      *vertex_shader_->deferred_compilation_source();
+      *vertex_shader_->signature_source();
   vertex_shader_->UpdateSource("different!");
-  vertex_shader_->FlagSourceAsCompiled(true);
+  vertex_shader_->SetStatus(true, NULL, NULL);
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
@@ -405,9 +403,9 @@
                  base::Unretained(this))));
 
   vertex_shader_->UpdateSource(vertex_orig_source.c_str());
-  vertex_shader_->FlagSourceAsCompiled(true);
+  vertex_shader_->SetStatus(true, NULL, NULL);
   fragment_shader_->UpdateSource("different!");
-  fragment_shader_->FlagSourceAsCompiled(true);
+  fragment_shader_->SetStatus(true, NULL, NULL);
   EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
       kProgramId,
       vertex_shader_,
@@ -485,9 +483,9 @@
 
   // save old source and modify for new program
   const std::string old_source =
-      *fragment_shader_->deferred_compilation_source();
+      *fragment_shader_->signature_source();
   fragment_shader_->UpdateSource("al sdfkjdk");
-  fragment_shader_->FlagSourceAsCompiled(true);
+  fragment_shader_->SetStatus(true, NULL, NULL);
 
   scoped_ptr<char[]> bigTestBinary =
       scoped_ptr<char[]>(new char[kEvictingBinaryLength]);
@@ -509,15 +507,15 @@
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(
       old_source,
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
 }
@@ -540,9 +538,9 @@
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
 }
@@ -564,9 +562,9 @@
                                        base::Unretained(this)));
 
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
-      *vertex_shader_->deferred_compilation_source(),
+      *vertex_shader_->signature_source(),
       NULL,
-      *fragment_shader_->deferred_compilation_source(),
+      *fragment_shader_->signature_source(),
       NULL,
       NULL));
 
diff --git a/gpu/command_buffer/service/program_cache.cc b/gpu/command_buffer/service/program_cache.cc
index f0adf6e..6599d4a 100644
--- a/gpu/command_buffer/service/program_cache.cc
+++ b/gpu/command_buffer/service/program_cache.cc
@@ -16,45 +16,9 @@
 
 void ProgramCache::Clear() {
   ClearBackend();
-  shader_status_.clear();
   link_status_.clear();
 }
 
-ProgramCache::CompiledShaderStatus ProgramCache::GetShaderCompilationStatus(
-    const std::string& shader_src,
-    const ShaderTranslatorInterface* translator) const {
-  char sha[kHashLength];
-  ComputeShaderHash(shader_src, translator, sha);
-  const std::string sha_string(sha, kHashLength);
-
-  CompileStatusMap::const_iterator found = shader_status_.find(sha_string);
-
-  if (found == shader_status_.end()) {
-    return ProgramCache::COMPILATION_UNKNOWN;
-  } else {
-    return found->second.status;
-  }
-}
-
-void ProgramCache::ShaderCompilationSucceeded(
-    const std::string& shader_src,
-    const ShaderTranslatorInterface* translator) {
-  char sha[kHashLength];
-  ComputeShaderHash(shader_src, translator, sha);
-  const std::string sha_string(sha, kHashLength);
-  ShaderCompilationSucceededSha(sha_string);
-}
-
-void ProgramCache::ShaderCompilationSucceededSha(
-    const std::string& sha_string) {
-  CompileStatusMap::iterator it = shader_status_.find(sha_string);
-  if (it == shader_status_.end()) {
-    shader_status_[sha_string] = CompiledShaderInfo(COMPILATION_SUCCEEDED);
-  } else {
-    it->second.status = COMPILATION_SUCCEEDED;
-  }
-}
-
 ProgramCache::LinkedProgramStatus ProgramCache::GetLinkedProgramStatus(
     const std::string& untranslated_a,
     const ShaderTranslatorInterface* translator_a,
@@ -98,17 +62,11 @@
                      sha);
   const std::string sha_string(sha, kHashLength);
 
-  LinkedProgramCacheSuccess(sha_string,
-                            std::string(a_sha, kHashLength),
-                            std::string(b_sha, kHashLength));
+  LinkedProgramCacheSuccess(sha_string);
 }
 
-void ProgramCache::LinkedProgramCacheSuccess(const std::string& program_hash,
-                                             const std::string& shader_a_hash,
-                                             const std::string& shader_b_hash) {
+void ProgramCache::LinkedProgramCacheSuccess(const std::string& program_hash) {
   link_status_[program_hash] = LINK_SUCCEEDED;
-  shader_status_[shader_a_hash].ref_count++;
-  shader_status_[shader_b_hash].ref_count++;
 }
 
 void ProgramCache::ComputeShaderHash(
@@ -122,21 +80,7 @@
                       s.length(), reinterpret_cast<unsigned char*>(result));
 }
 
-void ProgramCache::Evict(const std::string& program_hash,
-                         const std::string& shader_0_hash,
-                         const std::string& shader_1_hash) {
-  CompileStatusMap::iterator info0 = shader_status_.find(shader_0_hash);
-  CompileStatusMap::iterator info1 = shader_status_.find(shader_1_hash);
-  DCHECK(info0 != shader_status_.end());
-  DCHECK(info1 != shader_status_.end());
-  DCHECK(info0->second.ref_count > 0);
-  DCHECK(info1->second.ref_count > 0);
-  if (--info0->second.ref_count <= 0) {
-    shader_status_.erase(shader_0_hash);
-  }
-  if (--info1->second.ref_count <= 0) {
-    shader_status_.erase(shader_1_hash);
-  }
+void ProgramCache::Evict(const std::string& program_hash) {
   link_status_.erase(program_hash);
 }
 
diff --git a/gpu/command_buffer/service/program_cache.h b/gpu/command_buffer/service/program_cache.h
index a8b9f91..3fb5687 100644
--- a/gpu/command_buffer/service/program_cache.h
+++ b/gpu/command_buffer/service/program_cache.h
@@ -27,11 +27,6 @@
 
   typedef std::map<std::string, GLint> LocationMap;
 
-  enum CompiledShaderStatus {
-    COMPILATION_UNKNOWN,
-    COMPILATION_SUCCEEDED
-  };
-
   enum LinkedProgramStatus {
     LINK_UNKNOWN,
     LINK_SUCCEEDED
@@ -45,13 +40,6 @@
   ProgramCache();
   virtual ~ProgramCache();
 
-  CompiledShaderStatus GetShaderCompilationStatus(
-      const std::string& shader_src,
-      const ShaderTranslatorInterface* translator) const;
-  void ShaderCompilationSucceeded(const std::string& shader_src,
-                                  const ShaderTranslatorInterface* translator);
-  void ShaderCompilationSucceededSha(const std::string& sha_string);
-
   LinkedProgramStatus GetLinkedProgramStatus(
       const std::string& untranslated_shader_a,
       const ShaderTranslatorInterface* translator_a,
@@ -95,9 +83,7 @@
 
  protected:
   // called by implementing class after a shader was successfully cached
-  void LinkedProgramCacheSuccess(const std::string& program_hash,
-                                 const std::string& shader_a_hash,
-                                 const std::string& shader_b_hash);
+  void LinkedProgramCacheSuccess(const std::string& program_hash);
 
   // result is not null terminated
   void ComputeShaderHash(const std::string& shader,
@@ -112,30 +98,15 @@
       const LocationMap* bind_attrib_location_map,
       char* result) const;
 
-  void Evict(const std::string& program_hash,
-             const std::string& shader_0_hash,
-             const std::string& shader_1_hash);
+  void Evict(const std::string& program_hash);
 
  private:
-  struct CompiledShaderInfo {
-    CompiledShaderInfo() : status(COMPILATION_UNKNOWN), ref_count(0) { }
-    explicit CompiledShaderInfo(CompiledShaderStatus status_)
-        : status(status_),
-          ref_count(0) { }
-
-    CompiledShaderStatus status;
-    size_t ref_count;
-  };
-
-  typedef base::hash_map<std::string,
-                         CompiledShaderInfo> CompileStatusMap;
   typedef base::hash_map<std::string,
                          LinkedProgramStatus> LinkStatusMap;
 
   // called to clear the backend cache
   virtual void ClearBackend() = 0;
 
-  CompileStatusMap shader_status_;
   LinkStatusMap link_status_;
 
   DISALLOW_COPY_AND_ASSIGN(ProgramCache);
diff --git a/gpu/command_buffer/service/program_cache_unittest.cc b/gpu/command_buffer/service/program_cache_unittest.cc
index 9ff6da9..4e2abc3 100644
--- a/gpu/command_buffer/service/program_cache_unittest.cc
+++ b/gpu/command_buffer/service/program_cache_unittest.cc
@@ -55,9 +55,7 @@
                        sha);
     const std::string shaString(sha, kHashLength);
 
-    LinkedProgramCacheSuccess(shaString,
-                              std::string(a_sha, kHashLength),
-                              std::string(b_sha, kHashLength));
+    LinkedProgramCacheSuccess(shaString);
   }
 
   void ComputeShaderHash(const std::string& shader,
@@ -76,10 +74,8 @@
                                      result);
   }
 
-  void Evict(const std::string& program_hash,
-             const std::string& shader_0_hash,
-             const std::string& shader_1_hash) {
-    ProgramCache::Evict(program_hash, shader_0_hash, shader_1_hash);
+  void Evict(const std::string& program_hash) {
+    ProgramCache::Evict(program_hash);
   }
 };
 
@@ -92,54 +88,6 @@
   scoped_ptr<NoBackendProgramCache> cache_;
 };
 
-TEST_F(ProgramCacheTest, CompilationStatusSave) {
-  const std::string shader1 = "abcd1234";
-  {
-    std::string shader = shader1;
-    EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-              cache_->GetShaderCompilationStatus(shader, NULL));
-    cache_->ShaderCompilationSucceeded(shader, NULL);
-    shader.clear();
-  }
-  // make sure it was copied
-  EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-}
-
-TEST_F(ProgramCacheTest, CompilationStatusTranslatorOptionDependent) {
-  MockShaderTranslator translator;
-
-  EXPECT_CALL(translator, GetStringForOptionsThatWouldEffectCompilation())
-      .WillOnce(Return("foo"))   // GetShaderCompilationStatus
-      .WillOnce(Return("foo"))   // ShaderCompilationSucceeded
-      .WillOnce(Return("foo"))   // GetShaderCompilationStatus
-      .WillOnce(Return("bar"));  // GetShaderCompilationStatus
-
-  const std::string shader1 = "abcd1234";
-  {
-    std::string shader = shader1;
-    EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-              cache_->GetShaderCompilationStatus(shader, &translator));
-    cache_->ShaderCompilationSucceeded(shader, &translator);
-    shader.clear();
-  }
-  // make sure it was copied
-  EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED,
-            cache_->GetShaderCompilationStatus(shader1, &translator));
-  // make sure if the options change it's not copied.
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader1, &translator));
-}
-
-TEST_F(ProgramCacheTest, CompilationUnknownOnSourceChange) {
-  std::string shader1 = "abcd1234";
-  cache_->ShaderCompilationSucceeded(shader1, NULL);
-
-  shader1 = "different!";
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-}
-
 TEST_F(ProgramCacheTest, LinkStatusSave) {
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
@@ -183,8 +131,6 @@
 TEST_F(ProgramCacheTest, StatusEviction) {
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
-  cache_->ShaderCompilationSucceeded(shader1, NULL);
-  cache_->ShaderCompilationSucceeded(shader2, NULL);
   cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
   char a_sha[ProgramCache::kHashLength];
   char b_sha[ProgramCache::kHashLength];
@@ -196,13 +142,7 @@
                              b_sha,
                              NULL,
                              sha);
-  cache_->Evict(std::string(sha, ProgramCache::kHashLength),
-                std::string(a_sha, ProgramCache::kHashLength),
-                std::string(b_sha, ProgramCache::kHashLength));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader2, NULL));
+  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
             cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
 }
@@ -211,11 +151,7 @@
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
   const std::string shader3 = "asbjbbjj239a";
-  cache_->ShaderCompilationSucceeded(shader1, NULL);
-  cache_->ShaderCompilationSucceeded(shader2, NULL);
   cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
-  cache_->ShaderCompilationSucceeded(shader1, NULL);
-  cache_->ShaderCompilationSucceeded(shader3, NULL);
   cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
 
   char a_sha[ProgramCache::kHashLength];
@@ -230,15 +166,7 @@
                              b_sha,
                              NULL,
                              sha);
-  cache_->Evict(std::string(sha, ProgramCache::kHashLength),
-                std::string(a_sha, ProgramCache::kHashLength),
-                std::string(b_sha, ProgramCache::kHashLength));
-  EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader2, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED,
-            cache_->GetShaderCompilationStatus(shader3, NULL));
+  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
             cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
   EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
@@ -249,15 +177,7 @@
                              c_sha,
                              NULL,
                              sha);
-  cache_->Evict(std::string(sha, ProgramCache::kHashLength),
-                std::string(a_sha, ProgramCache::kHashLength),
-                std::string(c_sha, ProgramCache::kHashLength));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader2, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader3, NULL));
+  cache_->Evict(std::string(sha, ProgramCache::kHashLength));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
             cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
@@ -268,18 +188,9 @@
   const std::string shader1 = "abcd1234";
   const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
   const std::string shader3 = "asbjbbjj239a";
-  cache_->ShaderCompilationSucceeded(shader1, NULL);
-  cache_->ShaderCompilationSucceeded(shader2, NULL);
   cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
-  cache_->ShaderCompilationSucceeded(shader3, NULL);
   cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
   cache_->Clear();
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader1, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader2, NULL));
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(shader3, NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
             cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
   EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index d7ced0a..8b1eede 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -443,38 +443,9 @@
 void ProgramManager::DoCompileShader(Shader* shader,
                                      ShaderTranslator* translator,
                                      FeatureInfo* feature_info) {
-  TimeTicks before = TimeTicks::HighResNow();
-  if (program_cache_ &&
-      program_cache_->GetShaderCompilationStatus(
-          shader->source() ? *shader->source() : std::string(),
-          translator) == ProgramCache::COMPILATION_SUCCEEDED) {
-    shader->SetStatus(true, "", translator);
-    shader->FlagSourceAsCompiled(false);
-    UMA_HISTOGRAM_CUSTOM_COUNTS(
-        "GPU.ProgramCache.CompilationCacheHitTime",
-        (TimeTicks::HighResNow() - before).InMicroseconds(),
-        0,
-        TimeDelta::FromSeconds(1).InMicroseconds(),
-        50);
-    return;
-  }
-  ForceCompileShader(shader->source(), shader, translator, feature_info);
-  UMA_HISTOGRAM_CUSTOM_COUNTS(
-      "GPU.ProgramCache.CompilationCacheMissTime",
-      (TimeTicks::HighResNow() - before).InMicroseconds(),
-      0,
-      TimeDelta::FromSeconds(1).InMicroseconds(),
-      50);
-}
-
-void ProgramManager::ForceCompileShader(const std::string* source,
-                                        Shader* shader,
-                                        ShaderTranslator* translator,
-                                        FeatureInfo* feature_info) {
-  shader->FlagSourceAsCompiled(true);
-
   // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
   // glShaderSource and then glCompileShader.
+  const std::string* source = shader->source();
   const char* shader_src = source ? source->c_str() : "";
   if (translator) {
     if (!translator->Translate(shader_src)) {
@@ -506,11 +477,6 @@
   glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status);
   if (status) {
     shader->SetStatus(true, "", translator);
-    if (program_cache_) {
-      const char* untranslated_source = source ? source->c_str() : "";
-      program_cache_->ShaderCompilationSucceeded(
-          untranslated_source, translator);
-    }
   } else {
     // We cannot reach here if we are using the shader translator.
     // All invalid shaders must be rejected by the translator.
@@ -551,10 +517,12 @@
   bool link = true;
   ProgramCache* cache = manager_->program_cache_;
   if (cache) {
+    DCHECK(attached_shaders_[0]->signature_source() &&
+           attached_shaders_[1]->signature_source());
     ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
-        *attached_shaders_[0]->deferred_compilation_source(),
+        *attached_shaders_[0]->signature_source(),
         vertex_translator,
-        *attached_shaders_[1]->deferred_compilation_source(),
+        *attached_shaders_[1]->signature_source(),
         fragment_translator,
         &bind_attrib_location_map_);
 
@@ -570,26 +538,6 @@
       link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
       UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
     }
-
-    if (link) {
-      // compile our shaders if they're pending
-      const int kShaders = Program::kMaxAttachedShaders;
-      for (int i = 0; i < kShaders; ++i) {
-        Shader* shader = attached_shaders_[i].get();
-        if (shader->compilation_status() ==
-            Shader::PENDING_DEFERRED_COMPILE) {
-          ShaderTranslator* translator = ShaderIndexToTranslator(
-              i,
-              vertex_translator,
-              fragment_translator);
-          manager_->ForceCompileShader(shader->deferred_compilation_source(),
-                                       attached_shaders_[i].get(),
-                                       translator,
-                                       feature_info);
-          DCHECK(shader->IsValid());
-        }
-      }
-    }
   }
 
   if (link) {
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 16dd97d..dca232b 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -358,18 +358,10 @@
 
   static int32 MakeFakeLocation(int32 index, int32 element);
 
-  // Cache-aware shader compiling.  If no cache or if the shader wasn't
-  // previously compiled, ForceCompileShader is called
   void DoCompileShader(Shader* shader,
                        ShaderTranslator* translator,
                        FeatureInfo* feature_info);
 
-  // Actually compiles the shader
-  void ForceCompileShader(const std::string* source,
-                          Shader* shader,
-                          ShaderTranslator* translator,
-                          FeatureInfo* feature_info);
-
  private:
   friend class Program;
 
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index f7598c8..90ce0af 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -1192,18 +1192,8 @@
   }
 
   void SetShadersCompiled() {
-    cache_->ShaderCompilationSucceeded(*vertex_shader_->source(), NULL);
-    cache_->ShaderCompilationSucceeded(*fragment_shader_->source(), NULL);
     vertex_shader_->SetStatus(true, NULL, NULL);
     fragment_shader_->SetStatus(true, NULL, NULL);
-    vertex_shader_->FlagSourceAsCompiled(true);
-    fragment_shader_->FlagSourceAsCompiled(true);
-  }
-
-  void SetShadersNotCompiledButCached() {
-    SetShadersCompiled();
-    vertex_shader_->FlagSourceAsCompiled(false);
-    fragment_shader_->FlagSourceAsCompiled(false);
   }
 
   void SetProgramCached() {
@@ -1363,31 +1353,6 @@
 const GLuint ProgramManagerWithCacheTest::kFragmentShaderServiceId;
 #endif
 
-TEST_F(ProgramManagerWithCacheTest, CacheSuccessAfterShaderCompile) {
-  SetExpectationsForSuccessCompile(vertex_shader_);
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  manager_.DoCompileShader(vertex_shader_, NULL, info.get());
-  EXPECT_EQ(ProgramCache::COMPILATION_SUCCEEDED,
-            cache_->GetShaderCompilationStatus(
-                *vertex_shader_->source(), NULL));
-}
-
-TEST_F(ProgramManagerWithCacheTest, CacheUnknownAfterShaderError) {
-  SetExpectationsForErrorCompile(vertex_shader_);
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  manager_.DoCompileShader(vertex_shader_, NULL, info.get());
-  EXPECT_EQ(ProgramCache::COMPILATION_UNKNOWN,
-            cache_->GetShaderCompilationStatus(
-                *vertex_shader_->source(), NULL));
-}
-
-TEST_F(ProgramManagerWithCacheTest, NoCompileWhenShaderCached) {
-  cache_->ShaderCompilationSucceeded(vertex_shader_->source()->c_str(), NULL);
-  SetExpectationsForNoCompile(vertex_shader_);
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  manager_.DoCompileShader(vertex_shader_, NULL, info.get());
-}
-
 TEST_F(ProgramManagerWithCacheTest, CacheProgramOnSuccessfulLink) {
   SetShadersCompiled();
   SetExpectationsForProgramLink();
@@ -1396,21 +1361,8 @@
                              base::Bind(&ShaderCacheCb)));
 }
 
-TEST_F(ProgramManagerWithCacheTest, CompileShaderOnLinkCacheMiss) {
-  SetShadersCompiled();
-  vertex_shader_->FlagSourceAsCompiled(false);
-
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-
-  SetExpectationsForSuccessCompile(vertex_shader_);
-  SetExpectationsForProgramLink();
-  SetExpectationsForProgramCached();
-  EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL,
-                             info.get(), base::Bind(&ShaderCacheCb)));
-}
-
 TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) {
-  SetShadersNotCompiledButCached();
+  SetShadersCompiled();
   SetProgramCached();
 
   SetExpectationsForNoCompile(vertex_shader_);
@@ -1423,126 +1375,5 @@
                              base::Bind(&ShaderCacheCb)));
 }
 
-TEST_F(ProgramManagerWithCacheTest, CompileAndLinkOnProgramCacheError) {
-  SetShadersNotCompiledButCached();
-  SetProgramCached();
-
-  SetExpectationsForSuccessCompile(vertex_shader_);
-  SetExpectationsForSuccessCompile(fragment_shader_);
-  SetExpectationsForProgramLoad(ProgramCache::PROGRAM_LOAD_FAILURE);
-  SetExpectationsForProgramLink();
-  SetExpectationsForProgramCached();
-
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  EXPECT_TRUE(program_->Link(&shader_manager_, NULL, NULL, info.get(),
-                             base::Bind(&ShaderCacheCb)));
-}
-
-TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeNoCompile) {
-  SetShadersNotCompiledButCached();
-  SetProgramCached();
-
-  const GLuint kNewShaderClientId = 4;
-  const GLuint kNewShaderServiceId = 40;
-  const GLuint kNewProgramClientId = 5;
-  const GLuint kNewProgramServiceId = 50;
-
-  Shader* new_vertex_shader =
-      shader_manager_.CreateShader(kNewShaderClientId,
-                                       kNewShaderServiceId,
-                                       GL_VERTEX_SHADER);
-
-  const std::string original_source = *vertex_shader_->source();
-  new_vertex_shader->UpdateSource(original_source.c_str());
-
-  Program* program = manager_.CreateProgram(
-      kNewProgramClientId, kNewProgramServiceId);
-  ASSERT_TRUE(program != NULL);
-  program->AttachShader(&shader_manager_, new_vertex_shader);
-  program->AttachShader(&shader_manager_, fragment_shader_);
-
-  SetExpectationsForNoCompile(new_vertex_shader);
-
-  manager_.DoCompileShader(new_vertex_shader, NULL, NULL);
-  EXPECT_EQ(Shader::PENDING_DEFERRED_COMPILE,
-            new_vertex_shader->compilation_status());
-
-  new_vertex_shader->UpdateSource("different!");
-  EXPECT_EQ(original_source,
-            *new_vertex_shader->deferred_compilation_source());
-
-  EXPECT_EQ(Shader::PENDING_DEFERRED_COMPILE,
-            new_vertex_shader->compilation_status());
-  EXPECT_EQ(Shader::PENDING_DEFERRED_COMPILE,
-            fragment_shader_->compilation_status());
-
-  SetExpectationsForNoCompile(fragment_shader_);
-  SetExpectationsForNotCachingProgram(program,
-                                      new_vertex_shader,
-                                      fragment_shader_);
-  SetExpectationsForProgramLoad(kNewProgramServiceId,
-                                program,
-                                new_vertex_shader,
-                                fragment_shader_,
-                                ProgramCache::PROGRAM_LOAD_SUCCESS);
-  SetExpectationsForProgramLoadSuccess(kNewProgramServiceId);
-
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL, info.get(),
-                            base::Bind(&ShaderCacheCb)));
-}
-
-TEST_F(ProgramManagerWithCacheTest, CorrectCompileOnSourceChangeWithCompile) {
-  SetShadersNotCompiledButCached();
-  SetProgramCached();
-
-  const GLuint kNewShaderClientId = 4;
-  const GLuint kNewShaderServiceId = 40;
-  const GLuint kNewProgramClientId = 5;
-  const GLuint kNewProgramServiceId = 50;
-
-  Shader* new_vertex_shader =
-      shader_manager_.CreateShader(kNewShaderClientId,
-                                       kNewShaderServiceId,
-                                       GL_VERTEX_SHADER);
-
-  new_vertex_shader->UpdateSource(vertex_shader_->source()->c_str());
-
-  Program* program = manager_.CreateProgram(
-      kNewProgramClientId, kNewProgramServiceId);
-  ASSERT_TRUE(program != NULL);
-  program->AttachShader(&shader_manager_, new_vertex_shader);
-  program->AttachShader(&shader_manager_, fragment_shader_);
-
-  SetExpectationsForNoCompile(new_vertex_shader);
-
-  manager_.DoCompileShader(new_vertex_shader, NULL, NULL);
-
-  const std::string differentSource = "different!";
-  new_vertex_shader->UpdateSource(differentSource.c_str());
-  SetExpectationsForSuccessCompile(new_vertex_shader);
-
-  scoped_refptr<FeatureInfo> info(new FeatureInfo());
-  manager_.DoCompileShader(new_vertex_shader, NULL, info.get());
-  EXPECT_EQ(differentSource,
-            *new_vertex_shader->deferred_compilation_source());
-
-  EXPECT_EQ(Shader::COMPILED,
-            new_vertex_shader->compilation_status());
-  EXPECT_EQ(Shader::PENDING_DEFERRED_COMPILE,
-            fragment_shader_->compilation_status());
-
-  // so we don't recompile because we were pending originally
-  SetExpectationsForNoCompile(new_vertex_shader);
-  SetExpectationsForSuccessCompile(fragment_shader_);
-  SetExpectationsForProgramCached(program,
-                                  new_vertex_shader,
-                                  fragment_shader_);
-  SetExpectationsForProgramLink(kNewProgramServiceId);
-
-  EXPECT_TRUE(program->Link(&shader_manager_, NULL, NULL,
-                            info.get(), base::Bind(&ShaderCacheCb)));
-}
-
 }  // namespace gles2
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 590b3a2..a95b04c 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -16,8 +16,7 @@
       : use_count_(0),
         service_id_(service_id),
         shader_type_(shader_type),
-        valid_(false),
-        compilation_status_(NOT_COMPILED) {
+        valid_(false) {
 }
 
 Shader::~Shader() {
@@ -50,6 +49,11 @@
     uniform_map_.clear();
     name_map_.clear();
   }
+  if (valid && source_.get()) {
+    signature_source_.reset(new std::string(source_->c_str()));
+  } else {
+    signature_source_.reset();
+  }
 }
 
 const Shader::VariableInfo*
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h
index 31d5572..bc68868 100644
--- a/gpu/command_buffer/service/shader_manager.h
+++ b/gpu/command_buffer/service/shader_manager.h
@@ -26,19 +26,7 @@
  public:
   typedef ShaderTranslator::VariableInfo VariableInfo;
 
-  enum CompilationStatus {
-    NOT_COMPILED,
-    // We're pending compilation for a cache hit with the program cache.
-    PENDING_DEFERRED_COMPILE,
-    COMPILED
-  };
-
   void UpdateSource(const char* source) {
-    // If the source is flagged as compiled, then store our previous source
-    // for deferred compile and caching.
-    if (!deferred_compilation_source_.get()) {
-      deferred_compilation_source_.reset(source_.release());
-    }
     source_.reset(source ? new std::string(source) : NULL);
   }
 
@@ -63,31 +51,14 @@
     return translated_source_.get();
   }
 
+  const std::string* signature_source() const {
+    return signature_source_.get();
+  }
+
   void SetStatus(
       bool valid, const char* log,
       ShaderTranslatorInterface* translator);
 
-  CompilationStatus compilation_status() const {
-    return compilation_status_;
-  }
-
-  // The source that was used when the user called CompileShader.
-  // This is used for a deferred compile and in the program cache
-  const std::string* deferred_compilation_source() const {
-    return deferred_compilation_source_.get() != NULL ?
-        deferred_compilation_source_.get() :
-        source_.get();
-  }
-
-  // Resets our deferred compilation source and stores if the source was
-  // actually compiled, or if we're expecting a cache hit
-  void FlagSourceAsCompiled(bool actually_compiled) {
-    compilation_status_ = actually_compiled ?
-        COMPILED :
-        PENDING_DEFERRED_COMPILE;
-    deferred_compilation_source_.reset();
-  }
-
   const VariableInfo* GetAttribInfo(const std::string& name) const;
   const VariableInfo* GetUniformInfo(const std::string& name) const;
 
@@ -165,6 +136,9 @@
   // The shader source as passed to glShaderSource.
   scoped_ptr<std::string> source_;
 
+  // The source the last compile used.
+  scoped_ptr<std::string> signature_source_;
+
   // The translated shader source.
   scoped_ptr<std::string> translated_source_;
 
@@ -177,12 +151,6 @@
 
   // The name hashing info when the shader was last compiled.
   NameMap name_map_;
-
-  // The current compilation status of the shader
-  CompilationStatus compilation_status_;
-
-  // Holds on to the source for a deferred compile.
-  scoped_ptr<std::string> deferred_compilation_source_;
 };
 
 // Tracks the Shaders.
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc
index 0971bf1..a225a3c 100644
--- a/gpu/command_buffer/service/shader_manager_unittest.cc
+++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -248,45 +248,5 @@
   EXPECT_TRUE(shader2 == NULL);
 }
 
-TEST_F(ShaderManagerTest, ShaderInfoStoreCompilationStatus) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 11;
-  const GLenum kShaderType = GL_VERTEX_SHADER;
-  Shader* shader = manager_.CreateShader(
-      kClientId, kServiceId, kShaderType);
-  ASSERT_TRUE(shader != NULL);
-
-  EXPECT_EQ(Shader::NOT_COMPILED,
-            shader->compilation_status());
-  shader->UpdateSource("original source");
-  EXPECT_EQ(Shader::NOT_COMPILED,
-            shader->compilation_status());
-  shader->FlagSourceAsCompiled(false);
-  EXPECT_EQ(Shader::PENDING_DEFERRED_COMPILE,
-            shader->compilation_status());
-  shader->FlagSourceAsCompiled(true);
-  EXPECT_EQ(Shader::COMPILED,
-            shader->compilation_status());
-}
-
-TEST_F(ShaderManagerTest, ShaderInfoStoreDeferredSource) {
-  const GLuint kClientId = 1;
-  const GLuint kServiceId = 11;
-  const GLenum kShaderType = GL_VERTEX_SHADER;
-  Shader* shader = manager_.CreateShader(
-      kClientId, kServiceId, kShaderType);
-  ASSERT_TRUE(shader != NULL);
-
-  shader->UpdateSource("original source");
-  shader->FlagSourceAsCompiled(false);
-
-  EXPECT_EQ("original source", *shader->deferred_compilation_source());
-  shader->UpdateSource("different!");
-  EXPECT_EQ("original source", *shader->deferred_compilation_source());
-
-  shader->FlagSourceAsCompiled(true);
-  EXPECT_EQ("different!", *shader->deferred_compilation_source());
-}
-
 }  // namespace gles2
 }  // namespace gpu
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 745acb0..f583301 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -86,7 +86,6 @@
   WebSocketMsgStart,
   NaClHostMsgStart,
   WebRTCIdentityMsgStart,
-  EncodedVideoCaptureMsgStart,
   LocalDiscoveryMsgStart,
   PowerMonitorMsgStart,
   LastIPCMsgStart      // Must come last.
diff --git a/media/base/encoded_bitstream_buffer.cc b/media/base/encoded_bitstream_buffer.cc
deleted file mode 100644
index 3689015..0000000
--- a/media/base/encoded_bitstream_buffer.cc
+++ /dev/null
@@ -1,50 +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 "media/base/encoded_bitstream_buffer.h"
-
-#include "base/logging.h"
-
-namespace media {
-
-EncodedBitstreamBuffer::EncodedBitstreamBuffer(
-    int buffer_id,
-    uint8* buffer,
-    uint32 size,
-    base::SharedMemoryHandle handle,
-    const media::BufferEncodingMetadata& metadata,
-    const base::Closure& destroy_cb)
-    : buffer_id_(buffer_id),
-      buffer_(buffer),
-      size_(size),
-      shared_memory_handle_(handle),
-      metadata_(metadata),
-      destroy_cb_(destroy_cb) {
-}
-
-EncodedBitstreamBuffer::~EncodedBitstreamBuffer() {
-  destroy_cb_.Run();
-}
-
-int EncodedBitstreamBuffer::buffer_id() const {
-  return buffer_id_;
-}
-
-const uint8* EncodedBitstreamBuffer::buffer() const {
-  return buffer_;
-}
-
-uint32 EncodedBitstreamBuffer::size() const {
-  return size_;
-}
-
-base::SharedMemoryHandle EncodedBitstreamBuffer::shared_memory_handle() const {
-  return shared_memory_handle_;
-}
-
-const media::BufferEncodingMetadata& EncodedBitstreamBuffer::metadata() const {
-  return metadata_;
-}
-
-}  // namespace media
diff --git a/media/base/encoded_bitstream_buffer.h b/media/base/encoded_bitstream_buffer.h
deleted file mode 100644
index bfefbe5..0000000
--- a/media/base/encoded_bitstream_buffer.h
+++ /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.
-
-#ifndef MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_
-#define MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/time/time.h"
-#include "media/base/media_export.h"
-#include "media/video/video_encode_types.h"
-
-namespace media {
-
-// General encoded video bitstream buffer.
-class MEDIA_EXPORT EncodedBitstreamBuffer :
-    public base::RefCountedThreadSafe<EncodedBitstreamBuffer> {
- public:
-  EncodedBitstreamBuffer(int buffer_id,
-                         uint8* buffer,
-                         uint32 size,
-                         base::SharedMemoryHandle handle,
-                         const media::BufferEncodingMetadata& metadata,
-                         const base::Closure& destroy_cb);
-  // Accessors for properties.
-  int buffer_id() const;
-  const uint8* buffer() const;
-  uint32 size() const;
-  base::SharedMemoryHandle shared_memory_handle() const;
-  const media::BufferEncodingMetadata& metadata() const;
-
- protected:
-  // Destructor that deallocates the buffers.
-  virtual ~EncodedBitstreamBuffer();
-  friend class base::RefCountedThreadSafe<EncodedBitstreamBuffer>;
-
- private:
-  int buffer_id_;
-  uint8* buffer_;
-  uint32 size_;
-  const base::SharedMemoryHandle shared_memory_handle_;
-  media::BufferEncodingMetadata metadata_;
-  const base::Closure destroy_cb_;
-
-  DISALLOW_COPY_AND_ASSIGN(EncodedBitstreamBuffer);
-};
-
-}  // namespace media
-
-#endif  // MEDIA_BASE_ENCODED_BITSTREAM_BUFFER_H_
diff --git a/media/media.gyp b/media/media.gyp
index cb77036..b2bde3d 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -257,8 +257,6 @@
         'base/demuxer_stream.h',
         'base/djb2.cc',
         'base/djb2.h',
-        'base/encoded_bitstream_buffer.cc',
-        'base/encoded_bitstream_buffer.h',
         'base/filter_collection.cc',
         'base/filter_collection.h',
         'base/media.cc',
@@ -412,12 +410,10 @@
         'video/capture/win/video_capture_device_mf_win.h',
         'video/capture/win/video_capture_device_win.cc',
         'video/capture/win/video_capture_device_win.h',
-        'video/encoded_video_source.h',
         'video/picture.cc',
         'video/picture.h',
         'video/video_decode_accelerator.cc',
         'video/video_decode_accelerator.h',
-        'video/video_encode_types.h',
         'webm/webm_audio_client.cc',
         'webm/webm_audio_client.h',
         'webm/webm_cluster_parser.cc',
diff --git a/media/media.target.darwin-arm.mk b/media/media.target.darwin-arm.mk
index f27ae0b..9a453af 100644
--- a/media/media.target.darwin-arm.mk
+++ b/media/media.target.darwin-arm.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/media.target.darwin-mips.mk b/media/media.target.darwin-mips.mk
index 236c0f3..0df3761 100644
--- a/media/media.target.darwin-mips.mk
+++ b/media/media.target.darwin-mips.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/media.target.darwin-x86.mk b/media/media.target.darwin-x86.mk
index ec84b75..665877b 100644
--- a/media/media.target.darwin-x86.mk
+++ b/media/media.target.darwin-x86.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/media.target.linux-arm.mk b/media/media.target.linux-arm.mk
index f27ae0b..9a453af 100644
--- a/media/media.target.linux-arm.mk
+++ b/media/media.target.linux-arm.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/media.target.linux-mips.mk b/media/media.target.linux-mips.mk
index 236c0f3..0df3761 100644
--- a/media/media.target.linux-mips.mk
+++ b/media/media.target.linux-mips.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/media.target.linux-x86.mk b/media/media.target.linux-x86.mk
index ec84b75..665877b 100644
--- a/media/media.target.linux-x86.mk
+++ b/media/media.target.linux-x86.mk
@@ -89,7 +89,6 @@
 	media/base/demuxer.cc \
 	media/base/demuxer_stream.cc \
 	media/base/djb2.cc \
-	media/base/encoded_bitstream_buffer.cc \
 	media/base/filter_collection.cc \
 	media/base/media.cc \
 	media/base/media_keys.cc \
diff --git a/media/video/encoded_video_source.h b/media/video/encoded_video_source.h
deleted file mode 100644
index f0c9a13..0000000
--- a/media/video/encoded_video_source.h
+++ /dev/null
@@ -1,79 +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 MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_
-#define MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_
-
-#include "base/memory/ref_counted.h"
-#include "media/base/encoded_bitstream_buffer.h"
-#include "media/video/video_encode_types.h"
-
-namespace media {
-
-// Class to represent any encoded video source. Anything that provides encoded
-// video can be an EncodedVideoSource. Notable examples of this can be video
-// encoder and webcam that has encoding capabilities.
-// TODO(hshi): merge this with VEA interface. http://crbug.com/248334.
-class EncodedVideoSource {
- public:
-  class Client {
-   public:
-    // Notifies client that bitstream is opened successfully. The |params|
-    // contains the actual encoding parameters chosen by the browser process.
-    // It may be different from the params requested in OpenBitstream().
-    virtual void OnOpened(const VideoEncodingParameters& params) = 0;
-
-    // Notifies client that bitstream is closed. After this call it is
-    // guaranteed that client will not receive further calls.
-    virtual void OnClosed() = 0;
-
-    // Delivers an encoded bitstream buffer to the client.
-    virtual void OnBufferReady(
-        scoped_refptr<const EncodedBitstreamBuffer> buffer) = 0;
-
-    // Notifies client that encoding parameters has changed. The |params|
-    // contains the current encoding parameters chosen by the browser process.
-    // It may be different from the params requested in TrySetBitstreamConfig().
-    virtual void OnConfigChanged(
-        const RuntimeVideoEncodingParameters& params) = 0;
-  };
-
-  // Callback is invoked once RequestCapabilities() is complete.
-  typedef base::Callback<void(const VideoEncodingCapabilities& capabilities)>
-      RequestCapabilitiesCallback;
-
-  // RequestCapabilities initiates an asynchronous query for the types of
-  // encoded bitstream supported by the encoder. This call should be invoked
-  // only once. EncodedVideoSource will invoke |callback| when capabilities
-  // become available.
-  virtual void RequestCapabilities(
-      const RequestCapabilitiesCallback& callback) = 0;
-
-  // OpenBitstream opens the bitstream on the encoded video source. Only one
-  // bitstream can be opened for an encoded video source.
-  virtual void OpenBitstream(Client* client,
-                             const VideoEncodingParameters& params) = 0;
-
-  // CloseBitstream closes the bitstream.
-  virtual void CloseBitstream() = 0;
-
-  // ReturnBitstreamBuffer notifies that the data within the buffer has been
-  // processed and it can be reused to encode upcoming bitstream.
-  virtual void ReturnBitstreamBuffer(
-      scoped_refptr<const media::EncodedBitstreamBuffer> buffer) = 0;
-
-  // TrySetBitstreamConfig requests to change encoding parameters. Old config
-  // must be considered valid until OnConfigChanged is invoked on the client
-  // signaling successful change.
-  virtual void TrySetBitstreamConfig(
-      const RuntimeVideoEncodingParameters& params) = 0;
-
-  // RequestKeyFrame requests a key frame.
-  virtual void RequestKeyFrame() = 0;
-};
-
-}  // namespace media
-
-#endif  // MEDIA_VIDEO_ENCODED_VIDEO_SOURCE_H_
-
diff --git a/media/video/video_encode_types.h b/media/video/video_encode_types.h
deleted file mode 100644
index 15effab..0000000
--- a/media/video/video_encode_types.h
+++ /dev/null
@@ -1,53 +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 MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_
-#define MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_
-
-#include <map>
-#include <ostream>
-#include <vector>
-
-#include "base/time/time.h"
-#include "media/base/video_decoder_config.h"
-#include "ui/gfx/size.h"
-
-namespace media {
-
-// Data to represent limitations for a particular encoder config.
-// The |max_bitrate| value is in bits per second.
-struct VideoEncodingConfig {
-  VideoCodec codec_type;
-  std::string codec_name;
-  gfx::Size max_resolution;
-  uint32 max_frames_per_second;
-  uint32 max_bitrate;
-};
-
-typedef std::vector<VideoEncodingConfig> VideoEncodingCapabilities;
-
-// Encoding parameters that can be configured during streaming without removing
-// the bitstream first. The |target_bitrate| and |max_bitrate| values are in
-// bits per second.
-struct RuntimeVideoEncodingParameters {
-  uint32 target_bitrate;
-  uint32 max_bitrate;
-  uint32 frames_per_second;
-};
-
-// Generic video encoding parameters to be configured during initialization
-// time.
-struct VideoEncodingParameters {
-  std::string codec_name;
-  gfx::Size resolution;
-  RuntimeVideoEncodingParameters runtime_params;
-};
-
-struct BufferEncodingMetadata {
-  base::Time timestamp;
-  bool key_frame;
-};
-
-}  // namespace media
-
-#endif  // MEDIA_VIDEO_VIDEO_ENCODE_TYPES_H_
diff --git a/native_client_sdk/src/build_tools/sdk_files.list b/native_client_sdk/src/build_tools/sdk_files.list
index c3fd830..f4e890a 100644
--- a/native_client_sdk/src/build_tools/sdk_files.list
+++ b/native_client_sdk/src/build_tools/sdk_files.list
@@ -314,6 +314,8 @@
 include/nacl_io/error.h
 include/nacl_io/event_emitter.h
 include/nacl_io/event_listener.h
+include/nacl_io/error.h
+include/nacl_io/host_resolver.h
 include/nacl_io/inode_pool.h
 include/nacl_io/ioctl.h
 include/nacl_io/kernel_handle.h
@@ -340,6 +342,7 @@
 include/nacl_io/osmman.h
 include/nacl_io/ossocket.h
 include/nacl_io/osstat.h
+include/nacl_io/ostermios.h
 include/nacl_io/ostime.h
 include/nacl_io/ostypes.h
 include/nacl_io/osunistd.h
@@ -358,6 +361,7 @@
 include/newlib/poll.h
 include/newlib/sys/select.h
 include/newlib/sys/socket.h
+include/newlib/sys/termios.h
 include/newlib/sys/utsname.h
 include/pnacl/arpa/inet.h
 include/pnacl/netdb.h
@@ -366,6 +370,7 @@
 include/pnacl/poll.h
 include/pnacl/sys/select.h
 include/pnacl/sys/socket.h
+include/pnacl/sys/termios.h
 include/pnacl/sys/utsname.h
 include/ppapi/c/dev/deprecated_bool.h
 include/ppapi/c/dev/pp_cursor_type_dev.h
@@ -832,7 +837,8 @@
 src/Makefile
 src/nacl_io/event_emitter.cc
 src/nacl_io/event_listener.cc
-src/nacl_io/inet_ntoa.cc
+src/nacl_io/h_errno.cc
+src/nacl_io/host_resolver.cc
 src/nacl_io/kernel_handle.cc
 src/nacl_io/kernel_intercept.cc
 src/nacl_io/kernel_object.cc
@@ -867,6 +873,8 @@
 src/nacl_io/syscalls/getcwd.c
 src/nacl_io/syscalls/getdents.c
 src/nacl_io/syscalls/getwd.c
+src/nacl_io/syscalls/inet_ntoa.cc
+src/nacl_io/syscalls/inet_ntop.cc
 src/nacl_io/syscalls/ioctl.c
 src/nacl_io/syscalls/isatty.c
 src/nacl_io/syscalls/lchown.c
@@ -877,6 +885,9 @@
 src/nacl_io/syscalls/remove.c
 src/nacl_io/syscalls/rmdir.c
 src/nacl_io/syscalls/select.c
+src/nacl_io/syscalls/tcflush.c
+src/nacl_io/syscalls/tcgetattr.c
+src/nacl_io/syscalls/tcsetattr.c
 src/nacl_io/syscalls/umount.c
 src/nacl_io/syscalls/uname.c
 src/nacl_io/syscalls/unlink.c
diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.dsc b/native_client_sdk/src/examples/demo/nacl_io/example.dsc
index 104c1dd..4d1cf02 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/example.dsc
+++ b/native_client_sdk/src/examples/demo/nacl_io/example.dsc
@@ -25,5 +25,8 @@
   'GROUP': 'Demo',
   'PERMISSIONS': [
     'unlimitedStorage'
+  ],
+  'SOCKET_PERMISSIONS': [
+    'resolve-host'
   ]
 }
diff --git a/native_client_sdk/src/examples/demo/nacl_io/example.js b/native_client_sdk/src/examples/demo/nacl_io/example.js
index ef69aa6..87eedd5 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/example.js
+++ b/native_client_sdk/src/examples/demo/nacl_io/example.js
@@ -194,6 +194,22 @@
   common.logMessage('Directory ' + dirname + ' created successfully.');
 }
 
+function gethostbyname(e) {
+  var name = document.getElementById('gethostbynameName').value;
+  nacl_module.postMessage(makeCall('gethostbyname', name));
+}
+
+
+function gethostbynameResult(name, addr_type) {
+  common.logMessage('gethostbyname returned successfully\n');
+  common.logMessage('h_name = ' + name + '.\n');
+  common.logMessage('h_addr_type = ' + addr_type + '.\n');
+  for (var i = 2; i < arguments.length; i++) {
+    common.logMessage('Address number ' + (i-1) + ' = ' + arguments[i] + '.\n');
+  }
+  common.logMessage('\n');
+}
+
 /**
  * Return true when |s| starts with the string |prefix|.
  *
diff --git a/native_client_sdk/src/examples/demo/nacl_io/handlers.c b/native_client_sdk/src/examples/demo/nacl_io/handlers.c
index 9182676..2ec6559 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/handlers.c
+++ b/native_client_sdk/src/examples/demo/nacl_io/handlers.c
@@ -5,13 +5,17 @@
 
 #include "handlers.h"
 
+#include <arpa/inet.h>
 #include <assert.h>
 #include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 
 #include "nacl_io/osdirent.h"
@@ -641,3 +645,82 @@
   *output = PrintfToNewString("mkdir\1%s", dirname);
   return 0;
 }
+
+/**
+ * Handle a call to gethostbyname() made by JavaScript.
+ *
+ * gethostbyname expects 1 parameter:
+ *   0: The name of the host to look up.
+ * on success, gethostbyname returns a result in |output| separated by \1:
+ *   0: "gethostbyname"
+ *   1: Host name
+ *   2: Address type (either "AF_INET" or "AF_INET6")
+ *   3. The first address.
+ *   4+ The second, third, etc. addresses.
+ * on failure, gethostbyname returns an error string in |output|.
+ *
+ * @param[in] num_params The number of params in |params|.
+ * @param[in] params An array of strings, parameters to this function.
+ * @param[out] output A string to write informational function output to.
+ * @return An errorcode; 0 means success, anything else is a failure. */
+int HandleGethostbyname(int num_params, char** params, char** output) {
+  struct hostent* info;
+  struct in_addr **addr_list;
+  const char* addr_type;
+  const char* name;
+  char inet6_addr_str[INET6_ADDRSTRLEN];
+  int non_variable_len, output_len;
+  int current_pos;
+  int i;
+
+  if (num_params != 1) {
+    *output = PrintfToNewString("Error: gethostbyname takes 1 parameter.");
+    return 1;
+  }
+
+  name = params[0];
+
+  info = gethostbyname(name);
+  if (!info) {
+    *output = PrintfToNewString("Error: gethostbyname failed, error is \"%s\"",
+                                hstrerror(h_errno));
+    return 2;
+  }
+
+  addr_type = info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6";
+
+  non_variable_len = strlen("gethostbyname") + 1
+    + strlen(info->h_name) + 1 + strlen(addr_type);
+  output_len = non_variable_len;
+
+  addr_list = (struct in_addr **)info->h_addr_list;
+  for (i = 0; addr_list[i] != NULL; i++) {
+    output_len += 1; // for the divider
+    if (info->h_addrtype == AF_INET) {
+      output_len += strlen(inet_ntoa(*addr_list[i]));
+    } else { // IPv6
+      inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
+      output_len += strlen(inet6_addr_str);
+    }
+  }
+
+  *output = (char*) calloc(output_len + 1, 1);
+  if (!*output) {
+    *output = PrintfToNewString("Error: out of memory.");
+    return 3;
+  }
+  snprintf(*output, non_variable_len + 1, "gethostbyname\1%s\1%s",
+           info->h_name, addr_type);
+
+  current_pos = non_variable_len;
+  for (i = 0; addr_list[i] != NULL; i++) {
+    if (info->h_addrtype == AF_INET) {
+      current_pos += sprintf(*output + current_pos,
+                             "\1%s", inet_ntoa(*addr_list[i]));
+    } else { // IPv6
+      inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
+      sprintf(*output + current_pos, "\1%s", inet6_addr_str);
+    }
+  }
+  return 0;
+}
diff --git a/native_client_sdk/src/examples/demo/nacl_io/handlers.h b/native_client_sdk/src/examples/demo/nacl_io/handlers.h
index 0698707..595f96a 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/handlers.h
+++ b/native_client_sdk/src/examples/demo/nacl_io/handlers.h
@@ -20,5 +20,6 @@
 int HandleReaddir(int num_params, char** params, char** output);
 int HandleClosedir(int num_params, char** params, char** output);
 int HandleMkdir(int num_params, char** params, char** output);
+int HandleGethostbyname(int num_params, char** params, char** output);
 
 #endif /* HANDLERS_H_ */
diff --git a/native_client_sdk/src/examples/demo/nacl_io/index.html b/native_client_sdk/src/examples/demo/nacl_io/index.html
index 42bc1e7..1b132c1 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/index.html
+++ b/native_client_sdk/src/examples/demo/nacl_io/index.html
@@ -16,8 +16,8 @@
   <h1>{{title}}</h1>
   <h2>Status: <code id="statusField">NO-STATUS</code></h2>
   <p>
-    This example shows how you can use standard C library file operation
-    functions in Native Client using a library called nacl_io.
+    This example shows how you can use standard C library file and socket
+    operation functions in Native Client using a library called nacl_io.
   </p>
   <p>
     nacl_io provides a virtual filesystem. The filesystem can be "mounted"
@@ -37,18 +37,25 @@
           /dev/zero, etc.</li>
     </ol>
   </p>
+  <p>
+    nacl_io also provides a (currently incomplete) posix socket api. Like the
+    virtual filesystem, it is an abstraction layer on top of ppapi. To use this
+    API, an app must be a packaged app with the appropriate socket permissions
+    specified in the manifest file.
+  <hr>
+  <p><b>File Operations:</b></p>
   <div>
     <span>
-      <input type="radio" id="radiofopen" name="group" checked="checked">fopen
-      <input type="radio" id="radiofclose" name="group">fclose
-      <input type="radio" id="radiofread" name="group">fread
-      <input type="radio" id="radiofwrite" name="group">fwrite
-      <input type="radio" id="radiofseek" name="group">fseek
-      <input type="radio" id="radiostat" name="group">stat
-      <input type="radio" id="radioopendir" name="group">opendir
-      <input type="radio" id="radioreaddir" name="group">readdir
-      <input type="radio" id="radioclosedir" name="group">closedir
-      <input type="radio" id="radiomkdir" name="group">mkdir
+      <input type="radio" id="radiofopen" name="filegroup" checked="checked">fopen
+      <input type="radio" id="radiofclose" name="filegroup">fclose
+      <input type="radio" id="radiofread" name="filegroup">fread
+      <input type="radio" id="radiofwrite" name="filegroup">fwrite
+      <input type="radio" id="radiofseek" name="filegroup">fseek
+      <input type="radio" id="radiostat" name="filegroup">stat
+      <input type="radio" id="radioopendir" name="filegroup">opendir
+      <input type="radio" id="radioreaddir" name="filegroup">readdir
+      <input type="radio" id="radioclosedir" name="filegroup">closedir
+      <input type="radio" id="radiomkdir" name="filegroup">mkdir
     </span>
   </div>
   <div class="function" id="fopen">
@@ -137,6 +144,23 @@
       <button>mkdir</button>
     </span>
   </div>
+  <hr>
+  <p><b>Socket Operations:</b></p>
+  <div>
+    <span>
+      <input type="radio" id="radiogethostbyname" name="socketgroup" checked="checked">gethostbyname
+    </span>
+  </div>
+  <div class="function" id="gethostbyname">
+    <span>
+      Name:
+      <input type="text" id="gethostbynameName">
+      <button>gethostbyname</button>
+    </span>
+  </div>
+
+  <hr>
+  <p><b>Log:</b></p>
   <pre id="log" style="font-weight: bold"></pre>
   <!-- The NaCl plugin will be embedded inside the element with id "listener".
       See common.js.-->
diff --git a/native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c b/native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c
index e809e7a..9a1babd 100644
--- a/native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c
+++ b/native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c
@@ -52,6 +52,7 @@
   {"readdir", HandleReaddir},
   {"closedir", HandleClosedir},
   {"mkdir", HandleMkdir},
+  {"gethostbyname", HandleGethostbyname},
   {NULL, NULL},
 };
 
diff --git a/native_client_sdk/src/libraries/nacl_io/h_errno.cc b/native_client_sdk/src/libraries/nacl_io/h_errno.cc
new file mode 100644
index 0000000..5f328ed
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/h_errno.cc
@@ -0,0 +1,15 @@
+// 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 "nacl_io/ossocket.h"
+
+#if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
+
+static __thread int __h_errno__;
+
+extern "C" int *__h_errno_location() {
+  return &__h_errno__;
+}
+
+#endif  // defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
diff --git a/native_client_sdk/src/libraries/nacl_io/host_resolver.cc b/native_client_sdk/src/libraries/nacl_io/host_resolver.cc
new file mode 100644
index 0000000..f059f9a
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/host_resolver.cc
@@ -0,0 +1,226 @@
+// 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 "nacl_io/host_resolver.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sstream>
+#include <string>
+
+#include "nacl_io/kernel_proxy.h"
+#include "nacl_io/ossocket.h"
+#include "nacl_io/pepper_interface.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+namespace nacl_io {
+
+HostResolver::HostResolver() : hostent_(), ppapi_(NULL) {
+}
+
+HostResolver::~HostResolver() {
+  hostent_cleanup();
+}
+
+void HostResolver::Init(PepperInterface* ppapi) {
+  ppapi_ = ppapi;
+}
+
+struct hostent* HostResolver::gethostbyname(const char* name) {
+  h_errno = NETDB_INTERNAL;
+
+  if (NULL == ppapi_)
+    return NULL;
+
+  HostResolverInterface* resolver_interface =
+    ppapi_->GetHostResolverInterface();
+  ScopedResource resolver(ppapi_,
+                          resolver_interface->Create(ppapi_->GetInstance()));
+
+  struct PP_CompletionCallback callback;
+  callback.func = NULL;
+  struct PP_HostResolver_Hint hint;
+  hint.family = PP_NETADDRESS_FAMILY_IPV4;
+  hint.flags = PP_HOSTRESOLVER_FLAG_CANONNAME;
+
+  int err = resolver_interface->Resolve(resolver.pp_resource(),
+                                        name, 0, &hint, callback);
+  if (err) {
+    switch (err) {
+    case PP_ERROR_NOACCESS:
+      h_errno = NO_RECOVERY;
+      break;
+    case PP_ERROR_NAME_NOT_RESOLVED:
+      h_errno = HOST_NOT_FOUND;
+      break;
+    default:
+      h_errno = NETDB_INTERNAL;
+      break;
+    }
+    return NULL;
+  }
+
+  // We use a single hostent struct for all calls to to gethostbyname
+  // (as explicitly permitted by the spec - gethostbyname is NOT supposed to
+  // be threadsafe!), so the first thing we do is free all the malloced data
+  // left over from the last call.
+  hostent_cleanup();
+
+  PP_Var name_var =
+    resolver_interface->GetCanonicalName(resolver.pp_resource());
+  if (PP_VARTYPE_STRING != name_var.type)
+    return NULL;
+
+  uint32_t len;
+  const char* name_ptr = ppapi_->GetVarInterface()->VarToUtf8(name_var, &len);
+  if (NULL == name_ptr)
+    return NULL;
+  if (0 == len) {
+    // Sometimes GetCanonicalName gives up more easily than gethostbyname should
+    // (for example, it returns "" when asked to resolve "localhost"), so if we
+    // get an empty string we copy over the input string instead.
+    len = strlen(name);
+    name_ptr = name;
+  }
+  hostent_.h_name = static_cast<char*>(malloc(len + 1));
+  if (NULL == hostent_.h_name)
+    return NULL;
+  memcpy(hostent_.h_name, name_ptr, len);
+  hostent_.h_name[len] = '\0';
+
+  // Aliases aren't supported at the moment, so we just make an empty list.
+  hostent_.h_aliases = static_cast<char**>(malloc(sizeof(char*)));
+  if (NULL == hostent_.h_aliases)
+    return NULL;
+  hostent_.h_aliases[0] = NULL;
+
+  NetAddressInterface* netaddr_interface = ppapi_->GetNetAddressInterface();
+  PP_Resource addr =
+      resolver_interface->GetNetAddress(resolver.pp_resource(), 0);
+  if (!PP_ToBool(netaddr_interface->IsNetAddress(addr)))
+    return NULL;
+
+  switch (netaddr_interface->GetFamily(addr)) {
+    case PP_NETADDRESS_FAMILY_IPV4:
+      hostent_.h_addrtype = AF_INET;
+      hostent_.h_length = 4;
+      break;
+    case PP_NETADDRESS_FAMILY_IPV6:
+      hostent_.h_addrtype = AF_INET6;
+      hostent_.h_length = 16;
+      break;
+    default:
+      return NULL;
+  }
+
+  const uint32_t num_addresses =
+    resolver_interface->GetNetAddressCount(resolver.pp_resource());
+  if (0 == num_addresses)
+    return NULL;
+  hostent_.h_addr_list =
+    static_cast<char**>(calloc(num_addresses + 1, sizeof(char*)));
+  if (NULL == hostent_.h_addr_list)
+    return NULL;
+
+  for (uint32_t i = 0; i < num_addresses; i++) {
+    PP_Resource addr =
+      resolver_interface->GetNetAddress(resolver.pp_resource(), i);
+    if (!PP_ToBool(netaddr_interface->IsNetAddress(addr)))
+      return NULL;
+    if (AF_INET == hostent_.h_addrtype) {
+      struct PP_NetAddress_IPv4 addr_struct;
+      if (!netaddr_interface->DescribeAsIPv4Address(addr, &addr_struct)) {
+        return NULL;
+      }
+      hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length));
+      if (NULL == hostent_.h_addr_list[i])
+        return NULL;
+      memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length);
+    } else { // IPv6
+      struct PP_NetAddress_IPv6 addr_struct;
+      if (!netaddr_interface->DescribeAsIPv6Address(addr, &addr_struct))
+        return NULL;
+      hostent_.h_addr_list[i] = static_cast<char*>(malloc(hostent_.h_length));
+      if (NULL == hostent_.h_addr_list[i])
+        return NULL;
+      memcpy(hostent_.h_addr_list[i], addr_struct.addr, hostent_.h_length);
+    }
+  }
+  return &hostent_;
+}
+
+// Frees all of the deep pointers in a hostent struct. Called between uses of
+// gethostbyname, and when the kernel_proxy object is destroyed.
+void HostResolver::hostent_cleanup() {
+  if (NULL != hostent_.h_name) {
+    free(hostent_.h_name);
+  }
+  if (NULL != hostent_.h_aliases) {
+    for (int i = 0;  NULL != hostent_.h_aliases[i]; i++) {
+      free(hostent_.h_aliases[i]);
+    }
+    free(hostent_.h_aliases);
+  }
+  if (NULL != hostent_.h_addr_list) {
+    for (int i = 0;  NULL != hostent_.h_addr_list[i]; i++) {
+      free(hostent_.h_addr_list[i]);
+    }
+    free(hostent_.h_addr_list);
+  }
+  hostent_.h_name = NULL;
+  hostent_.h_aliases = NULL;
+  hostent_.h_addr_list = NULL;
+}
+
+void HostResolver::herror(const char* s) {
+  if (s) {
+    fprintf(stderr, "%s: ", s);
+  }
+
+  fprintf(stderr, "%s\n", hstrerror(h_errno));
+}
+
+const char* HostResolver::hstrerror(int err) {
+  // These error message texts are taken straight from the man page
+  const char* host_not_found_msg =
+    "The specified host is unknown.";
+  const char* no_address_msg =
+    "The requested name is valid but does not have an IP address.";
+  const char* no_recovery_msg =
+    "A nonrecoverable name server error occurred.";
+  const char* try_again_msg =
+    "A temporary error occurred on an authoritative name server. "
+    "Try again later.";
+  const char* internal_msg =
+    "Internal error in gethostbyname.";
+  const char* unknown_msg_base =
+    "Unknown error in gethostbyname: ";
+
+  switch (err) {
+    case HOST_NOT_FOUND:
+      return host_not_found_msg;
+    case NO_ADDRESS:
+      return no_address_msg;
+    case NO_RECOVERY:
+      return no_recovery_msg;
+    case TRY_AGAIN:
+      return try_again_msg;
+    case NETDB_INTERNAL:
+      return internal_msg;
+    default:
+      std::stringstream msg;
+      msg << unknown_msg_base << err << ".";
+
+      static std::string unknown_msg;
+      unknown_msg.assign(msg.str());
+      return unknown_msg.c_str();
+  }
+}
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io/host_resolver.h b/native_client_sdk/src/libraries/nacl_io/host_resolver.h
new file mode 100644
index 0000000..0a942bd
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/host_resolver.h
@@ -0,0 +1,37 @@
+// 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 LIBRARIES_NACL_IO_HOST_RESOLVER_H_
+#define LIBRARIES_NACL_IO_HOST_RESOLVER_H_
+
+#include "nacl_io/ossocket.h"
+#include "nacl_io/pepper_interface.h"
+
+#ifdef PROVIDES_SOCKET_API
+
+namespace nacl_io {
+
+class HostResolver {
+ public:
+  HostResolver();
+  ~HostResolver();
+
+  void Init(PepperInterface* ppapi);
+
+  struct hostent* gethostbyname(const char* name);
+  static void herror(const char* s);
+  static const char* hstrerror(int err);
+
+ private:
+  void hostent_initialize();
+  void hostent_cleanup();
+
+  struct hostent hostent_;
+  PepperInterface *ppapi_;
+};
+
+}  // namespace nacl_io
+
+#endif  // PROVIDES_SOCKET_API
+#endif  // LIBRARIES_NACL_IO_HOST_RESOLVER_H_
diff --git a/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
new file mode 100644
index 0000000..8eabbd9
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/include/sys/termios.h
@@ -0,0 +1,129 @@
+/* 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. */
+
+#ifndef SYS_TERMIOS_H_
+#define SYS_TERMIOS_H_
+
+#define IGNBRK  0000001
+#define BRKINT  0000002
+#define IGNPAR  0000004
+#define PARMRK  0000010
+#define INPCK   0000020
+#define ISTRIP  0000040
+#define INLCR   0000100
+#define IGNCR   0000200
+#define ICRNL   0000400
+#define IUCLC   0001000
+#define IXON    0002000
+#define IXANY   0004000
+#define IXOFF   0010000
+#define IMAXBEL 0020000
+#define IUTF8   0040000
+
+#define OPOST   000001
+#define OCRNL   000004
+#define ONLCR   000010
+#define ONOCR   000020
+#define ONLRET  000040
+#define TAB3    014000
+
+#define CLOCAL  004000
+#define CREAD   000200
+#define PARODD  001000
+#define CSIZE   000060
+#define CS5     0
+#define CS6     020
+#define CS7     040
+#define CS8     060
+#define CSTOPB  000100
+#define HUPCL   002000
+#define PARENB  000400
+#define PAODD   001000
+
+#define ECHO    0000010
+#define ECHOE   0000020
+#define ECHOK   0000040
+#define ECHONL  0000100
+#define ICANON  0000002
+#define IEXTEN  0100000
+#define ISIG    0000001
+#define NOFLSH  0000200
+#define TOSTOP  0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE  0004000
+#define FLUSHO  0010000
+#define PENDIN  0040000
+
+#define VINTR     0
+#define VQUIT     1
+#define VERASE    2
+#define VKILL     3
+#define VEOF      4
+#define VTIME     5
+#define VMIN      6
+#define VSWTC     7
+#define VSTART    8
+#define VSTOP     9
+#define VSUSP    10
+#define VEOL     11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE  14
+#define VLNEXT   15
+#define VEOL2    16
+
+#define B0      000000
+#define B50     000001
+#define B75     000002
+#define B110    000003
+#define B134    000004
+#define B150    000005
+#define B200    000006
+#define B300    000007
+#define B600    000010
+#define B1200   000011
+#define B1800   000012
+#define B2400   000013
+#define B4800   000014
+#define B9600   000015
+#define B19200  000016
+#define B38400  000017
+
+#define TCIFLUSH  0
+#define TCOFLUSH  1
+#define TCIOFLUSH 2
+
+#define TCSANOW   0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+typedef unsigned char cc_t;
+typedef unsigned short tcflag_t;
+typedef char speed_t;
+
+#define NCCS 32
+struct termios {
+  tcflag_t c_iflag;
+  tcflag_t c_oflag;
+  tcflag_t c_cflag;
+  tcflag_t c_lflag;
+  char c_line;
+  cc_t c_cc[NCCS];
+  speed_t c_ispeed;
+  speed_t c_ospeed;
+};
+
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+int tcflush(int fd, int queue_selector);
+int tcgetattr(int fd, struct termios *termios_p);
+int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
+
+__END_DECLS
+
+#endif  /* SYS_TERMIOS_H_ */
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
index a479f9c..912fd18 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.cc
@@ -242,6 +242,22 @@
   return s_kp->select(nfds, readfds, writefds, exceptfds, timeout);
 }
 
+int ki_tcflush(int fd, int queue_selector) {
+  ON_NOSYS_RETURN(-1);
+  return s_kp->tcflush(fd, queue_selector);
+}
+
+int ki_tcgetattr(int fd, struct termios* termios_p) {
+  ON_NOSYS_RETURN(-1);
+  return s_kp->tcgetattr(fd, termios_p);
+}
+
+int ki_tcsetattr(int fd, int optional_actions,
+                 const struct termios *termios_p) {
+  ON_NOSYS_RETURN(-1);
+  return s_kp->tcsetattr(fd, optional_actions, termios_p);
+}
+
 #ifdef PROVIDES_SOCKET_API
 // Socket Functions
 int ki_accept(int fd, struct sockaddr* addr, socklen_t* len) {
@@ -256,6 +272,10 @@
   return s_kp->connect(fd, addr, len);
 }
 
+struct hostent* ki_gethostbyname(const char* name) {
+  return s_kp->gethostbyname(name);
+}
+
 int ki_getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
   return s_kp->getpeername(fd, addr, len);
 }
@@ -267,6 +287,14 @@
   return s_kp->getsockopt(fd, lvl, optname, optval, len);
 }
 
+void ki_herror(const char *s) {
+  return s_kp->herror(s);
+}
+
+const char *ki_hstrerror(int err) {
+  return s_kp->hstrerror(err);
+}
+
 int ki_listen(int fd, int backlog) {
   return s_kp->listen(fd, backlog);
 }
@@ -313,4 +341,4 @@
 int ki_socketpair(int domain, int type, int protocol, int* sv) {
   return s_kp->socketpair(domain, type, protocol, sv);
 }
-#endif // PROVIDES_SOCKET_API
+#endif  // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
index 90fecf9..b570c8f 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_intercept.h
@@ -10,6 +10,7 @@
 
 #include "nacl_io/ossocket.h"
 #include "nacl_io/osstat.h"
+#include "nacl_io/ostermios.h"
 #include "nacl_io/ostypes.h"
 #include "nacl_io/osutime.h"
 #include "sdk_util/macros.h"
@@ -70,14 +71,22 @@
 int ki_select(int nfds, fd_set* readfds, fd_set* writefds,
               fd_set* exceptfds, struct timeval* timeout);
 
+int ki_tcflush(int fd, int queue_selector);
+int ki_tcgetattr(int fd, struct termios* termios_p);
+int ki_tcsetattr(int fd, int optional_actions,
+                 const struct termios *termios_p);
+
 #ifdef PROVIDES_SOCKET_API
 // Socket Functions
 int ki_accept(int fd, struct sockaddr* addr, socklen_t* len);
 int ki_bind(int fd, const struct sockaddr* addr, socklen_t len);
 int ki_connect(int fd, const struct sockaddr* addr, socklen_t len);
+struct hostent* ki_gethostbyname(const char* name);
 int ki_getpeername(int fd, struct sockaddr* addr, socklen_t* len);
 int ki_getsockname(int fd, struct sockaddr* addr, socklen_t* len);
 int ki_getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len);
+void ki_herror(const char *s);
+const char *ki_hstrerror(int err);
 int ki_listen(int fd, int backlog);
 ssize_t ki_recv(int fd, void* buf, size_t len, int flags);
 ssize_t ki_recvfrom(int fd, void* buf, size_t len, int flags,
@@ -92,7 +101,7 @@
 int ki_shutdown(int fd, int how);
 int ki_socket(int domain, int type, int protocol);
 int ki_socketpair(int domain, int type, int protocl, int* sv);
-#endif // PROVIDES_SOCKET_API
+#endif  // PROVIDES_SOCKET_API
 
 EXTERN_C_END
 
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
index 1e6ae64..a64a800 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.cc
@@ -18,6 +18,7 @@
 #include <iterator>
 #include <string>
 
+#include "nacl_io/host_resolver.h"
 #include "nacl_io/kernel_handle.h"
 #include "nacl_io/kernel_wrap_real.h"
 #include "nacl_io/mount.h"
@@ -77,6 +78,10 @@
   open("/dev/stdin", O_RDONLY);
   open("/dev/stdout", O_WRONLY);
   open("/dev/stderr", O_WRONLY);
+
+#ifdef PROVIDES_SOCKET_API
+  host_resolver_.Init(ppapi_);
+#endif
 }
 
 int KernelProxy::open_resource(const char* path) {
@@ -471,9 +476,9 @@
   return 0;
 }
 
-int KernelProxy::ioctl(int d, int request, char* argp) {
+int KernelProxy::ioctl(int fd, int request, char* argp) {
   ScopedKernelHandle handle;
-  Error error = AcquireHandle(d, &handle);
+  Error error = AcquireHandle(fd, &handle);
   if (error) {
     errno = error;
     return -1;
@@ -647,6 +652,58 @@
   return 0;
 }
 
+int KernelProxy::tcflush(int fd, int queue_selector) {
+  ScopedKernelHandle handle;
+  Error error = AcquireHandle(fd, &handle);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  error = handle->node()->Tcflush(queue_selector);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  return 0;
+}
+
+int KernelProxy::tcgetattr(int fd, struct termios* termios_p) {
+  ScopedKernelHandle handle;
+  Error error = AcquireHandle(fd, &handle);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  error = handle->node()->Tcgetattr(termios_p);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  return 0;
+}
+
+int KernelProxy::tcsetattr(int fd, int optional_actions,
+                           const struct termios *termios_p) {
+  ScopedKernelHandle handle;
+  Error error = AcquireHandle(fd, &handle);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  error = handle->node()->Tcsetattr(optional_actions, termios_p);
+  if (error) {
+    errno = error;
+    return -1;
+  }
+
+  return 0;
+}
+
 #ifdef PROVIDES_SOCKET_API
 
 int KernelProxy::select(int nfds, fd_set* readfds, fd_set* writefds,
@@ -868,6 +925,10 @@
   return -1;
 }
 
+struct hostent* KernelProxy::gethostbyname(const char* name) {
+  return host_resolver_.gethostbyname(name);
+}
+
 int KernelProxy::getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
   if (NULL == addr || NULL == len) {
     errno = EFAULT;
@@ -914,6 +975,14 @@
   return -1;
 }
 
+void KernelProxy::herror(const char* s) {
+  return host_resolver_.herror(s);
+}
+
+const char* KernelProxy::hstrerror(int err) {
+  return host_resolver_.hstrerror(err);
+}
+
 int KernelProxy::listen(int fd, int backlog) {
   ScopedKernelHandle handle;
   if (AcquireSocketHandle(fd, &handle) == -1)
@@ -1111,6 +1180,6 @@
   return 0;
 }
 
-#endif // PROVIDES_SOCKET_API
+#endif  // PROVIDES_SOCKET_API
 
-} // namespace_nacl_io
+}  // namespace_nacl_io
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
index e0dff69..47b6f77 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_proxy.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <string>
 
+#include "nacl_io/host_resolver.h"
 #include "nacl_io/kernel_object.h"
 #include "nacl_io/mount_factory.h"
 #include "nacl_io/ossocket.h"
@@ -118,6 +119,10 @@
                      int fd,
                      size_t offset);
   virtual int munmap(void* addr, size_t length);
+  virtual int tcflush(int fd, int queue_selector);
+  virtual int tcgetattr(int fd, struct termios* termios_p);
+  virtual int tcsetattr(int fd, int optional_actions,
+                           const struct termios *termios_p);
 
 #ifdef PROVIDES_SOCKET_API
   virtual int select(int nfds, fd_set* readfds, fd_set* writefds,
@@ -129,6 +134,7 @@
   virtual int accept(int fd, struct sockaddr* addr, socklen_t* len);
   virtual int bind(int fd, const struct sockaddr* addr, socklen_t len);
   virtual int connect(int fd, const struct sockaddr* addr, socklen_t len);
+  virtual struct hostent* gethostbyname(const char* name);
   virtual int getpeername(int fd, struct sockaddr* addr, socklen_t* len);
   virtual int getsockname(int fd, struct sockaddr* addr, socklen_t* len);
   virtual int getsockopt(int fd,
@@ -136,6 +142,8 @@
                          int optname,
                          void* optval,
                          socklen_t* len);
+  virtual void herror(const char* s);
+  virtual const char* hstrerror(int err);
   virtual int listen(int fd, int backlog);
   virtual ssize_t recv(int fd,
                        void* buf,
@@ -164,13 +172,16 @@
   virtual int shutdown(int fd, int how);
   virtual int socket(int domain, int type, int protocol);
   virtual int socketpair(int domain, int type, int protocol, int* sv);
-#endif // PROVIDES_SOCKET_API
+#endif  // PROVIDES_SOCKET_API
 
  protected:
   MountFactoryMap_t factories_;
   int dev_;
   PepperInterface* ppapi_;
   static KernelProxy *s_instance_;
+#ifdef PROVIDES_SOCKET_API
+  HostResolver host_resolver_;
+#endif
 
 #ifdef PROVIDES_SOCKET_API
   virtual int AcquireSocketHandle(int fd, ScopedKernelHandle* handle);
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
index 1a0886c..6b79d4f 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap.h
@@ -102,9 +102,12 @@
 int accept(int fd, struct sockaddr* addr, socklen_t* len);
 int bind(int fd, const struct sockaddr* addr, socklen_t len);
 int connect(int fd, const struct sockaddr* addr, socklen_t len);
+struct hostent* gethostbyname(const char* name);
 int getpeername(int fd, struct sockaddr* addr, socklen_t* len);
 int getsockname(int fd, struct sockaddr* addr, socklen_t* len);
 int getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len);
+void herror(const char *s);
+const char *hstrerror(int err);
 int listen(int fd, int backlog);
 ssize_t recv(int fd, void* buf, size_t len, int flags);
 ssize_t recvfrom(int fd, void* buf, size_t len, int flags,
@@ -119,7 +122,7 @@
 int shutdown(int fd, int how);
 int socket(int domain, int type, int protocol);
 int socketpair(int domain, int type, int protocl, int* sv);
-#endif // PROVIDES_SOCKET_API
+#endif  // PROVIDES_SOCKET_API
 
 EXTERN_C_END
 
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
index b4e80e9..7c52f4d 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_glibc.cc
@@ -292,6 +292,10 @@
   return ki_connect(fd, addr, len);
 }
 
+struct hostent* gethostbyname(const char* name) {
+  return ki_gethostbyname(name);
+}
+
 int getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
   return ki_getpeername(fd, addr, len);
 }
@@ -299,10 +303,19 @@
 int getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
   return ki_getsockname(fd, addr, len);
 }
+
 int getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len) {
   return ki_getsockopt(fd, lvl, optname, optval, len);
 }
 
+void herror(const char *s) {
+  return ki_herror(s);
+}
+
+const char *hstrerror(int err) {
+  return ki_hstrerror(err);
+}
+
 int listen(int fd, int backlog) {
   return ki_listen(fd, backlog);
 }
diff --git a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
index c2f91a1..e218301 100644
--- a/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
+++ b/native_client_sdk/src/libraries/nacl_io/kernel_wrap_newlib.cc
@@ -144,6 +144,10 @@
   return ki_connect(fd, addr, len);
 }
 
+struct hostent* gethostbyname(const char* name) {
+  return ki_gethostbyname(name);
+}
+
 int getpeername(int fd, struct sockaddr* addr, socklen_t* len) {
   return ki_getpeername(fd, addr, len);
 }
@@ -151,10 +155,19 @@
 int getsockname(int fd, struct sockaddr* addr, socklen_t* len) {
   return ki_getsockname(fd, addr, len);
 }
+
 int getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len) {
   return ki_getsockopt(fd, lvl, optname, optval, len);
 }
 
+void herror(const char* s) {
+  return ki_herror(s);
+}
+
+const char* hstrerror(int err) {
+  return ki_hstrerror(err);
+}
+
 int listen(int fd, int backlog) {
   return ki_listen(fd, backlog);
 }
diff --git a/native_client_sdk/src/libraries/nacl_io/library.dsc b/native_client_sdk/src/libraries/nacl_io/library.dsc
index 8b4ed00..011a9c6 100644
--- a/native_client_sdk/src/libraries/nacl_io/library.dsc
+++ b/native_client_sdk/src/libraries/nacl_io/library.dsc
@@ -13,7 +13,8 @@
       'SOURCES' : [
         "event_emitter.cc",
         "event_listener.cc",
-        "inet_ntoa.cc",
+        "h_errno.cc",
+        "host_resolver.cc",
         "kernel_handle.cc",
         "kernel_intercept.cc",
         "kernel_object.cc",
@@ -46,6 +47,8 @@
         "syscalls/getdents.c",
         "syscalls/getwd.c",
         "syscalls/getcwd.c",
+        "syscalls/inet_ntoa.cc",
+        "syscalls/inet_ntop.cc",
         "syscalls/ioctl.c",
         "syscalls/isatty.c",
         "syscalls/link.c",
@@ -56,6 +59,9 @@
         "syscalls/remove.c",
         "syscalls/rmdir.c",
         "syscalls/select.c",
+        "syscalls/tcflush.c",
+        "syscalls/tcgetattr.c",
+        "syscalls/tcsetattr.c",
         "syscalls/unlink.c",
         "syscalls/umount.c",
         "syscalls/uname.c",
@@ -69,6 +75,7 @@
         "event_emitter.h",
         "event_listener.h",
         "error.h",
+        "host_resolver.h",
         "inode_pool.h",
         "ioctl.h",
         "kernel_handle.h",
@@ -99,6 +106,7 @@
         "ostypes.h",
         "osunistd.h",
         "osutime.h",
+        "ostermios.h",
         "path.h",
         "pepper_interface.h",
         "real_pepper_interface.h",
@@ -115,6 +123,7 @@
         "poll.h",
         "sys/select.h",
         "sys/socket.h",
+        "sys/termios.h",
         "sys/utsname.h",
       ],
       'DEST': 'include/newlib',
@@ -128,6 +137,7 @@
         "poll.h",
         "sys/select.h",
         "sys/socket.h",
+        "sys/termios.h",
         "sys/utsname.h",
       ],
       'DEST': 'include/pnacl',
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.cc b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
index 3e423da..0116745 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.cc
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.cc
@@ -125,6 +125,19 @@
   return 0;
 }
 
+Error MountNode::Tcflush(int queue_selector) {
+  return EINVAL;
+}
+
+Error MountNode::Tcgetattr(struct termios* termios_p) {
+  return EINVAL;
+}
+
+Error MountNode::Tcsetattr(int optional_actions,
+                           const struct termios *termios_p) {
+  return EINVAL;
+}
+
 int MountNode::GetLinks() { return stat_.st_nlink; }
 
 int MountNode::GetMode() { return stat_.st_mode & ~S_IFMT; }
diff --git a/native_client_sdk/src/libraries/nacl_io/mount_node.h b/native_client_sdk/src/libraries/nacl_io/mount_node.h
index bf9534e..2afc88b 100644
--- a/native_client_sdk/src/libraries/nacl_io/mount_node.h
+++ b/native_client_sdk/src/libraries/nacl_io/mount_node.h
@@ -11,6 +11,7 @@
 #include "nacl_io/event_listener.h"
 #include "nacl_io/osdirent.h"
 #include "nacl_io/osstat.h"
+#include "nacl_io/ostermios.h"
 
 #include "sdk_util/ref_object.h"
 #include "sdk_util/scoped_ref.h"
@@ -69,6 +70,10 @@
                      int flags,
                      size_t offset,
                      void** out_addr);
+  virtual Error Tcflush(int queue_selector);
+  virtual Error Tcgetattr(struct termios* termios_p);
+  virtual Error Tcsetattr(int optional_actions,
+                          const struct termios *termios_p);
 
   virtual int GetLinks();
   virtual int GetMode();
@@ -79,6 +84,7 @@
   virtual bool IsaFile();
   virtual bool IsaTTY();
 
+
   // Number of children for this node (directory)
   virtual int ChildCount();
 
diff --git a/native_client_sdk/src/libraries/nacl_io/ossocket.h b/native_client_sdk/src/libraries/nacl_io/ossocket.h
index 784086a..936509b 100644
--- a/native_client_sdk/src/libraries/nacl_io/ossocket.h
+++ b/native_client_sdk/src/libraries/nacl_io/ossocket.h
@@ -5,6 +5,8 @@
 #ifndef LIBRARIES_NACL_IO_OSSOCKET_H_
 #define LIBRARIES_NACL_IO_OSSOCKET_H_
 
+#include <sys/types.h>
+
 #if defined(__native_client__)
 #include <arpa/inet.h>
 #include <netdb.h>
diff --git a/native_client_sdk/src/libraries/nacl_io/ostermios.h b/native_client_sdk/src/libraries/nacl_io/ostermios.h
new file mode 100644
index 0000000..03c4b6c
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/ostermios.h
@@ -0,0 +1,42 @@
+/* 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. */
+
+#ifndef LIBRARIES_NACL_IO_OSTERMIOS_H
+#define LIBRARIES_NACL_IO_OSTERMIOS_H
+
+#if defined(__native_client__)
+
+#include <termios.h>
+
+#else
+
+#include "sdk_util/macros.h"
+
+typedef unsigned char cc_t;
+typedef unsigned short tcflag_t;
+typedef char speed_t;
+
+#define NCCS 32
+struct termios {
+  tcflag_t c_iflag;
+  tcflag_t c_oflag;
+  tcflag_t c_cflag;
+  tcflag_t c_lflag;
+  char c_line;
+  cc_t c_cc[NCCS];
+  speed_t c_ispeed;
+  speed_t c_ospeed;
+};
+
+
+EXTERN_C_BEGIN
+
+int tcgetattr(int fd,struct termios *termios_p);
+int tcsetattr(int fd,int optional_actions,const struct termios *termios_p);
+
+EXTERN_C_END
+
+#endif
+
+#endif  /* LIBRARIES_NACL_IO_OSTERMIOS_H */
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
index dbf1daf..cb75d73 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper/all_interfaces.h
@@ -68,6 +68,28 @@
   METHOD2(VarInterface, const char*, VarToUtf8, PP_Var, uint32_t*)
 END_INTERFACE(VarInterface, PPB_Var)
 
+BEGIN_INTERFACE(HostResolverInterface, PPB_HostResolver,
+                PPB_HOSTRESOLVER_INTERFACE_1_0)
+  METHOD1(HostResolverInterface, PP_Resource, Create, PP_Instance)
+  METHOD5(HostResolverInterface, int32_t, Resolve, PP_Resource, const char*,
+          uint16_t, const struct PP_HostResolver_Hint*,
+          struct PP_CompletionCallback)
+  METHOD1(HostResolverInterface, PP_Var, GetCanonicalName, PP_Resource)
+  METHOD1(HostResolverInterface, uint32_t, GetNetAddressCount, PP_Resource)
+  METHOD2(HostResolverInterface, PP_Resource, GetNetAddress,
+          PP_Resource, uint32_t)
+END_INTERFACE(HostResolverInterface, PPB_HostResolver)
+
+BEGIN_INTERFACE(NetAddressInterface, PPB_NetAddress,
+                PPB_NETADDRESS_INTERFACE_1_0)
+  METHOD1(NetAddressInterface, PP_Bool, IsNetAddress, PP_Resource)
+  METHOD1(NetAddressInterface, PP_NetAddress_Family, GetFamily, PP_Resource)
+  METHOD2(NetAddressInterface, PP_Bool, DescribeAsIPv4Address, PP_Resource,
+          struct PP_NetAddress_IPv4*)
+  METHOD2(NetAddressInterface, PP_Bool, DescribeAsIPv6Address, PP_Resource,
+          struct PP_NetAddress_IPv6*)
+END_INTERFACE(NetAddressInterface, PPB_NetAddress)
+
 BEGIN_INTERFACE(URLLoaderInterface, PPB_URLLoader, PPB_URLLOADER_INTERFACE_1_0)
   METHOD1(URLLoaderInterface, PP_Resource, Create, PP_Instance)
   METHOD3(URLLoaderInterface, int32_t, Open, PP_Resource, PP_Resource,
diff --git a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
index 9eaec00..6ffe1e6 100644
--- a/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
+++ b/native_client_sdk/src/libraries/nacl_io/pepper_interface.h
@@ -5,7 +5,9 @@
 #ifndef LIBRARIES_NACL_IO_PEPPER_INTERFACE_H_
 #define LIBRARIES_NACL_IO_PEPPER_INTERFACE_H_
 
+#include <ppapi/c/pp_bool.h>
 #include <ppapi/c/pp_completion_callback.h>
+#include <ppapi/c/pp_errors.h>
 #include <ppapi/c/pp_file_info.h>
 #include <ppapi/c/pp_instance.h>
 #include <ppapi/c/pp_resource.h>
@@ -14,8 +16,10 @@
 #include <ppapi/c/ppb_file_io.h>
 #include <ppapi/c/ppb_file_ref.h>
 #include <ppapi/c/ppb_file_system.h>
+#include <ppapi/c/ppb_host_resolver.h>
 #include <ppapi/c/ppb_messaging.h>
 #include <ppapi/c/ppb_messaging.h>
+#include <ppapi/c/ppb_net_address.h>
 #include <ppapi/c/ppb_url_loader.h>
 #include <ppapi/c/ppb_url_request_info.h>
 #include <ppapi/c/ppb_url_response_info.h>
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntoa.cc b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntoa.cc
new file mode 100644
index 0000000..93825e7
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntoa.cc
@@ -0,0 +1,28 @@
+/* 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 "nacl_io/ossocket.h"
+#if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
+
+#include <string.h>
+#include "sdk_util/macros.h"
+
+static uint8_t GetByte(const void* addr, int byte) {
+  const char* buf = static_cast<const char*>(addr);
+  return static_cast<uint8_t>(buf[byte]);
+}
+
+EXTERN_C_BEGIN
+
+char* inet_ntoa(struct in_addr in) {
+  static char addr[INET_ADDRSTRLEN];
+  snprintf(addr, INET_ADDRSTRLEN, "%u.%u.%u.%u",
+           GetByte(&in, 0), GetByte(&in, 1),
+           GetByte(&in, 2), GetByte(&in, 3));
+  return addr;
+}
+
+EXTERN_C_END
+
+#endif  // defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
diff --git a/native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntop.cc
similarity index 61%
rename from native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc
rename to native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntop.cc
index fdeae08..807bdfe 100644
--- a/native_client_sdk/src/libraries/nacl_io/inet_ntoa.cc
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/inet_ntop.cc
@@ -1,31 +1,21 @@
-// 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.
+/* 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 "nacl_io/ossocket.h"
-
-#ifdef PROVIDES_SOCKET_API
+#if defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
 
 #include <errno.h>
-#include <stdio.h>
 #include <string.h>
 
 #include <iostream>
 #include <sstream>
 #include <string>
 
-static inline uint8_t get_byte(const void* addr, int byte) {
-  const char* buf = static_cast<const char*>(addr);
-  return static_cast<uint8_t>(buf[byte]);
-}
+#include "sdk_util/macros.h"
 
-char* inet_ntoa(struct in_addr in) {
-  static char addr[INET_ADDRSTRLEN];
-  snprintf(addr, INET_ADDRSTRLEN, "%u.%u.%u.%u",
-           get_byte(&in, 0), get_byte(&in, 1),
-           get_byte(&in, 2), get_byte(&in, 3));
-  return addr;
-}
+
+EXTERN_C_BEGIN
 
 const char* inet_ntop(int af, const void* src, char* dst, socklen_t size) {
   if (AF_INET == af) {
@@ -62,4 +52,7 @@
   return NULL;
 }
 
-#endif // PROVIDES_SOCKET_API
+EXTERN_C_END
+
+#endif  // defined(PROVIDES_SOCKET_API) && !defined(__GLIBC__)
+
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcflush.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflush.c
new file mode 100644
index 0000000..5a59b8b
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcflush.c
@@ -0,0 +1,11 @@
+// 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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/ostermios.h"
+
+int tcflush(int fd, int queue_selector) {
+  return ki_tcflush(fd, queue_selector);
+}
+
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcgetattr.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcgetattr.c
new file mode 100644
index 0000000..0715f45
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcgetattr.c
@@ -0,0 +1,10 @@
+// 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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/ostermios.h"
+
+int tcgetattr(int fd, struct termios* termios_p) {
+  return ki_tcgetattr(fd, termios_p);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io/syscalls/tcsetattr.c b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsetattr.c
new file mode 100644
index 0000000..bb44397
--- /dev/null
+++ b/native_client_sdk/src/libraries/nacl_io/syscalls/tcsetattr.c
@@ -0,0 +1,10 @@
+// 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 "nacl_io/kernel_intercept.h"
+#include "nacl_io/ostermios.h"
+
+int tcsetattr(int fd, int optional_actions, const struct termios* termios_p) {
+  return ki_tcsetattr(fd, optional_actions, termios_p);
+}
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
index eeaf104..c082856 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_mock.h
@@ -11,6 +11,7 @@
 
 #include "nacl_io/kernel_proxy.h"
 #include "nacl_io/ossocket.h"
+#include "nacl_io/ostermios.h"
 
 class KernelProxyMock : public nacl_io::KernelProxy {
  public:
@@ -43,6 +44,8 @@
   MOCK_METHOD1(remove, int(const char*));
   MOCK_METHOD1(rmdir, int(const char*));
   MOCK_METHOD2(stat, int(const char*, struct stat*));
+  MOCK_METHOD2(tcgetattr, int(int, struct termios*));
+  MOCK_METHOD3(tcsetattr, int(int, int, const struct termios*));
   MOCK_METHOD1(umount, int(const char*));
   MOCK_METHOD1(unlink, int(const char*));
   MOCK_METHOD2(utime, int(const char*, const struct utimbuf*));
@@ -60,9 +63,12 @@
   MOCK_METHOD3(accept, int(int, struct sockaddr*, socklen_t*));
   MOCK_METHOD3(bind, int(int, const struct sockaddr*, socklen_t));
   MOCK_METHOD3(connect, int(int, const struct sockaddr*, socklen_t));
+  MOCK_METHOD1(gethostbyname, struct hostent*(const char*));
   MOCK_METHOD3(getpeername, int(int, struct sockaddr*, socklen_t*));
   MOCK_METHOD3(getsockname, int(int, struct sockaddr*, socklen_t*));
   MOCK_METHOD5(getsockopt, int(int, int, int, void*, socklen_t*));
+  MOCK_METHOD1(herror, void(const char*));
+  MOCK_METHOD1(hstrerror, const char*(int));
   MOCK_METHOD2(listen, int(int, int));
   MOCK_METHOD4(recv, ssize_t(int, void*, size_t, int));
   MOCK_METHOD6(recvfrom, ssize_t(int, void*, size_t, int,
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
index 7b19f4a..1eabdd0 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_proxy_test.cc
@@ -5,6 +5,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <pthread.h>
+#include <stdio.h>
 #include <sys/stat.h>
 
 #include <map>
@@ -520,3 +521,4 @@
   // propagate through.
   EXPECT_EQ(1234, errno);
 }
+
diff --git a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
index 92577e0..6b48c88 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/kernel_wrap_test.cc
@@ -7,10 +7,10 @@
 
 #include "gtest/gtest.h"
 #include "kernel_proxy_mock.h"
-#include "nacl_io/kernel_proxy.h"
 #include "nacl_io/kernel_intercept.h"
 #include "nacl_io/kernel_wrap.h"
 #include "nacl_io/ossocket.h"
+#include "nacl_io/ostermios.h"
 
 using namespace nacl_io;
 
@@ -20,6 +20,8 @@
 
 namespace {
 
+static const int DUMMY_FD = 5678;
+
 #define COMPARE_FIELD(f) \
   if (arg->f != statbuf->f) { \
     *result_listener << "mismatch of field \""#f"\". " \
@@ -133,30 +135,30 @@
 }
 
 TEST_F(KernelWrapTest, dup) {
-  EXPECT_CALL(mock, dup(123)).Times(1);
-  dup(123);
+  EXPECT_CALL(mock, dup(DUMMY_FD)).Times(1);
+  dup(DUMMY_FD);
 }
 
 TEST_F(KernelWrapTest, dup2) {
-  EXPECT_CALL(mock, dup2(123, 234)).Times(1);
-  dup2(123, 234);
+  EXPECT_CALL(mock, dup2(DUMMY_FD, 234)).Times(1);
+  dup2(DUMMY_FD, 234);
 }
 
 TEST_F(KernelWrapTest, fchown) {
   uid_t uid = kDummyUid;
   gid_t gid = kDummyGid;
-  EXPECT_CALL(mock, fchown(123, uid, gid)).Times(1);
-  fchown(123, uid, gid);
+  EXPECT_CALL(mock, fchown(DUMMY_FD, uid, gid)).Times(1);
+  fchown(DUMMY_FD, uid, gid);
 }
 
 TEST_F(KernelWrapTest, fstat) {
   struct stat in_statbuf;
   MakeDummyStatbuf(&in_statbuf);
-  EXPECT_CALL(mock, fstat(234, _))
+  EXPECT_CALL(mock, fstat(DUMMY_FD, _))
       .Times(1)
       .WillOnce(SetStat(&in_statbuf));
   struct stat out_statbuf;
-  fstat(234, &out_statbuf);
+  fstat(DUMMY_FD, &out_statbuf);
   EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
 }
 
@@ -265,6 +267,18 @@
   EXPECT_THAT(&in_statbuf, IsEqualToStatbuf(&out_statbuf));
 }
 
+TEST_F(KernelWrapTest, tcgetattr) {
+  struct termios term;
+  EXPECT_CALL(mock, tcgetattr(DUMMY_FD, &term)).Times(1);
+  tcgetattr(DUMMY_FD, &term);
+}
+
+TEST_F(KernelWrapTest, tcsetattr) {
+  struct termios term;
+  EXPECT_CALL(mock, tcsetattr(DUMMY_FD, 0, &term)).Times(1);
+  tcsetattr(DUMMY_FD, 0, &term);
+}
+
 TEST_F(KernelWrapTest, umount) {
   EXPECT_CALL(mock, umount(StrEq("umount"))).Times(1);
   umount("umount");
@@ -299,88 +313,103 @@
 
 // Socket Functions
 TEST_F(KernelWrapTest, accept) {
-  EXPECT_CALL(mock, accept(123, NULL, NULL)).Times(1);
-  accept(123, NULL, NULL);
+  EXPECT_CALL(mock, accept(DUMMY_FD, NULL, NULL)).Times(1);
+  accept(DUMMY_FD, NULL, NULL);
 }
 
 TEST_F(KernelWrapTest, bind) {
-  EXPECT_CALL(mock, bind(123, NULL, 456)).Times(1);
-  bind(123, NULL, 456);
+  EXPECT_CALL(mock, bind(DUMMY_FD, NULL, 456)).Times(1);
+  bind(DUMMY_FD, NULL, 456);
 }
 
 TEST_F(KernelWrapTest, connect) {
-  EXPECT_CALL(mock, connect(123, NULL, 456)).Times(1);
-  connect(123, NULL, 456);
+  EXPECT_CALL(mock, connect(DUMMY_FD, NULL, 456)).Times(1);
+  connect(DUMMY_FD, NULL, 456);
+}
+
+TEST_F(KernelWrapTest, gethostbyname) {
+  EXPECT_CALL(mock, gethostbyname(NULL)).Times(1);
+  gethostbyname(NULL);
 }
 
 TEST_F(KernelWrapTest, getpeername) {
-  EXPECT_CALL(mock, getpeername(123, NULL, NULL)).Times(1);
-  getpeername(123, NULL, NULL);
+  EXPECT_CALL(mock, getpeername(DUMMY_FD, NULL, NULL)).Times(1);
+  getpeername(DUMMY_FD, NULL, NULL);
 }
 
 TEST_F(KernelWrapTest, getsockname) {
-  EXPECT_CALL(mock, getsockname(123, NULL, NULL)).Times(1);
-  getsockname(123, NULL, NULL);
+  EXPECT_CALL(mock, getsockname(DUMMY_FD, NULL, NULL)).Times(1);
+  getsockname(DUMMY_FD, NULL, NULL);
 }
 
 TEST_F(KernelWrapTest, getsockopt) {
-  EXPECT_CALL(mock, getsockopt(123, 456, 789, NULL, NULL)).Times(1);
-  getsockopt(123, 456, 789, NULL, NULL);
+  EXPECT_CALL(mock, getsockopt(DUMMY_FD, 456, 789, NULL, NULL)).Times(1);
+  getsockopt(DUMMY_FD, 456, 789, NULL, NULL);
+}
+
+TEST_F(KernelWrapTest, herror) {
+  EXPECT_CALL(mock, herror(NULL)).Times(1);
+  herror(NULL);
+}
+
+TEST_F(KernelWrapTest, hstrerror) {
+  EXPECT_CALL(mock, hstrerror(123)).Times(1);
+  hstrerror(123);
 }
 
 TEST_F(KernelWrapTest, listen) {
-  EXPECT_CALL(mock, listen(123, 456)).Times(1);
-  listen(123, 456);
+  EXPECT_CALL(mock, listen(DUMMY_FD, 456)).Times(1);
+  listen(DUMMY_FD, 456);
 }
 
 TEST_F(KernelWrapTest, recv) {
-  EXPECT_CALL(mock, recv(123, NULL, 456, 789)).Times(1);
-  recv(123, NULL, 456, 789);
+  EXPECT_CALL(mock, recv(DUMMY_FD, NULL, 456, 789)).Times(1);
+  recv(DUMMY_FD, NULL, 456, 789);
 }
 
 TEST_F(KernelWrapTest, recvfrom) {
-  EXPECT_CALL(mock, recvfrom(123, NULL, 456, 789, NULL, NULL)).Times(1);
-  recvfrom(123, NULL, 456, 789, NULL, NULL);
+  EXPECT_CALL(mock, recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL)).Times(1);
+  recvfrom(DUMMY_FD, NULL, 456, 789, NULL, NULL);
 }
 
 TEST_F(KernelWrapTest, recvmsg) {
-  EXPECT_CALL(mock, recvmsg(123, NULL, 456)).Times(1);
-  recvmsg(123, NULL, 456);
+  EXPECT_CALL(mock, recvmsg(DUMMY_FD, NULL, 456)).Times(1);
+  recvmsg(DUMMY_FD, NULL, 456);
 }
 
 TEST_F(KernelWrapTest, send) {
-  EXPECT_CALL(mock, send(123, NULL, 456, 789)).Times(1);
-  send(123, NULL, 456, 789);
+  EXPECT_CALL(mock, send(DUMMY_FD, NULL, 456, 789)).Times(1);
+  send(DUMMY_FD, NULL, 456, 789);
 }
 
 TEST_F(KernelWrapTest, sendto) {
-  EXPECT_CALL(mock, sendto(123, NULL, 456, 789, NULL, 314)).Times(1);
-  sendto(123, NULL, 456, 789, NULL, 314);
+  EXPECT_CALL(mock, sendto(DUMMY_FD, NULL, 456, 789, NULL, 314)).Times(1);
+  sendto(DUMMY_FD, NULL, 456, 789, NULL, 314);
 }
 
 TEST_F(KernelWrapTest, sendmsg) {
-  EXPECT_CALL(mock, sendmsg(123, NULL, 456)).Times(1);
-  sendmsg(123, NULL, 456);
+  EXPECT_CALL(mock, sendmsg(DUMMY_FD, NULL, 456)).Times(1);
+  sendmsg(DUMMY_FD, NULL, 456);
 }
 
 TEST_F(KernelWrapTest, setsockopt) {
-  EXPECT_CALL(mock, setsockopt(123, 456, 789, NULL, 314)).Times(1);
-  setsockopt(123, 456, 789, NULL, 314);
+  EXPECT_CALL(mock, setsockopt(DUMMY_FD, 456, 789, NULL, 314)).Times(1);
+  setsockopt(DUMMY_FD, 456, 789, NULL, 314);
 }
 
 TEST_F(KernelWrapTest, shutdown) {
-  EXPECT_CALL(mock, shutdown(123, 456)).Times(1);
-  shutdown(123, 456);
+  EXPECT_CALL(mock, shutdown(DUMMY_FD, 456)).Times(1);
+  shutdown(DUMMY_FD, 456);
 }
 
 TEST_F(KernelWrapTest, socket) {
-  EXPECT_CALL(mock, socket(123, 456, 789)).Times(1);
-  socket(123, 456, 789);
+  EXPECT_CALL(mock, socket(DUMMY_FD, 456, 789)).Times(1);
+  socket(DUMMY_FD, 456, 789);
 }
 
 TEST_F(KernelWrapTest, socketpair) {
-  EXPECT_CALL(mock, socketpair(123,456, 789, NULL)).Times(1);
-  socketpair(123,456, 789, NULL);
+  EXPECT_CALL(mock, socketpair(DUMMY_FD, 456, 789, NULL)).Times(1);
+  socketpair(DUMMY_FD, 456, 789, NULL);
 }
 
 #endif // PROVIDES_SOCKET_API
diff --git a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc b/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
index 9768c13..ec45185 100644
--- a/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
+++ b/native_client_sdk/src/libraries/nacl_io_test/socket_test.cc
@@ -38,7 +38,7 @@
   KernelProxy* kp_;
 };
 
-} // namespace
+}  // namespace
 
 TEST_F(SocketTest, Accept) {
   struct sockaddr addr = {};
@@ -128,6 +128,11 @@
   EXPECT_EQ(errno, ENOTSOCK);
 }
 
+TEST_F(SocketTest, Hstrerror) {
+  EXPECT_STREQ(ki_hstrerror(2718),
+               "Unknown error in gethostbyname: 2718.");
+}
+
 TEST_F(SocketTest, Listen) {
   EXPECT_LT(ki_listen(-1, 123), 0);
   EXPECT_EQ(errno, EBADF);
@@ -259,8 +264,9 @@
   EXPECT_EQ(errno, EPROTONOSUPPORT);
 }
 
-// These functions don't go through KernelProxy, so they don't require a test
-// fixture
+// These utility functions are only used for newlib (glibc provides its own
+// implementations of these functions).
+#if !defined(__GLIBC__)
 
 static struct in_addr generate_ipv4_addr(int tuple1, int tuple2,
                                          int tuple3, int tuple4) {
@@ -366,4 +372,5 @@
   EXPECT_EQ(errno, ENOSPC);
 }
 
-#endif // PROVIDES_SOCKETPAIR_API
+#endif  // !defined(__GLIBC__)
+#endif  // PROVIDES_SOCKETPAIR_API
diff --git a/native_client_sdk/src/web/manifest.html b/native_client_sdk/src/web/manifest.html
index 49574b4..7da5a3f 100644
--- a/native_client_sdk/src/web/manifest.html
+++ b/native_client_sdk/src/web/manifest.html
@@ -54,14 +54,17 @@
       <tbody id="rows">
       </tbody>
     </table>
+    <h2>Most recent upload log:</h2>
+    <pre id="log">
+    </pre>
     <script type="application/javascript">
-      function loadJson(url, callback) {
+      function loadText(url, callback) {
         var xhr = new XMLHttpRequest();
         xhr.open('GET', url, true);
         xhr.onreadystatechange = function (e) {
           if (xhr.readyState == 4) {
             if (xhr.status == 200) {
-              callback(JSON.parse(xhr.responseText));
+              callback(xhr.responseText);
             } else {
               alert("Failed to load: error " + xhr.status);
             }
@@ -70,6 +73,12 @@
         xhr.send(null);
       }
 
+      function loadJson(url, callback) {
+        loadText(url, function (text) {
+          callback(JSON.parse(text));
+        });
+      }
+
       function removeAllChildren(elm) {
         while (elm.childNodes.length) {
           elm.removeChild(elm.firstChild);
@@ -128,7 +137,12 @@
         }
       }
 
+      function displayLog(text) {
+        document.getElementById('log').textContent = text;
+      }
+
       loadJson('naclsdk_manifest2.json', display);
+      loadText('naclsdk_manifest2.json.log', displayLog);
     </script>
   </body>
 </html>
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index 120f091..f63297e 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -162,10 +162,6 @@
 void GetCertChainInfo(CERTCertList* cert_list,
                       CERTCertificate* root_cert,
                       CertVerifyResult* verify_result) {
-  // NOTE: Using a NSS library before 3.12.3.1 will crash below.  To see the
-  // NSS version currently in use:
-  // 1. use ldd on the chrome executable for NSS's location (ie. libnss3.so*)
-  // 2. use ident libnss3.so* for the library's version
   DCHECK(cert_list);
 
   CERTCertificate* verified_cert = NULL;
@@ -367,31 +363,6 @@
   bool use_crl = check_revocation;
   bool use_ocsp = check_revocation;
 
-  // These CAs have multiple keys, which trigger two bugs in NSS's CRL code.
-  // 1. NSS may use one key to verify a CRL signed with another key,
-  //    incorrectly concluding that the CRL's signature is invalid.
-  //    Hopefully this bug will be fixed in NSS 3.12.9.
-  // 2. NSS considers all certificates issued by the CA as revoked when it
-  //    receives a CRL with an invalid signature.  This overly strict policy
-  //    has been relaxed in NSS 3.12.7.  See
-  //    https://bugzilla.mozilla.org/show_bug.cgi?id=562542.
-  // So we have to turn off CRL checking for these CAs.  See
-  // http://crbug.com/55695.
-  static const char* const kMultipleKeyCA[] = {
-    "CN=Microsoft Secure Server Authority,"
-    "DC=redmond,DC=corp,DC=microsoft,DC=com",
-    "CN=Microsoft Secure Server Authority",
-  };
-
-  if (!NSS_VersionCheck("3.12.7")) {
-    for (size_t i = 0; i < arraysize(kMultipleKeyCA); ++i) {
-      if (strcmp(cert_handle->issuerName, kMultipleKeyCA[i]) == 0) {
-        use_crl = false;
-        break;
-      }
-    }
-  }
-
   PRUint64 revocation_method_flags =
       CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD |
       CERT_REV_M_ALLOW_NETWORK_FETCHING |
diff --git a/net/cert/jwk_serializer.h b/net/cert/jwk_serializer.h
new file mode 100644
index 0000000..7a12a36
--- /dev/null
+++ b/net/cert/jwk_serializer.h
@@ -0,0 +1,30 @@
+// 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 NET_CERT_JWK_SERIALIZER_H_
+#define NET_CERT_JWK_SERIALIZER_H_
+
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace net {
+
+namespace JwkSerializer {
+
+// Converts a subject public key info from DER to JWK.
+// See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-13 for
+// the output format.
+NET_EXPORT_PRIVATE bool ConvertSpkiFromDerToJwk(
+    const base::StringPiece& spki_der,
+    base::DictionaryValue* public_key_jwk);
+
+} // namespace JwkSerializer
+
+} // namespace net
+
+#endif  // NET_CERT_JWK_SERIALIZER_H_
diff --git a/net/cert/jwk_serializer_nss.cc b/net/cert/jwk_serializer_nss.cc
new file mode 100644
index 0000000..0259c5c
--- /dev/null
+++ b/net/cert/jwk_serializer_nss.cc
@@ -0,0 +1,118 @@
+// 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 "net/cert/jwk_serializer.h"
+
+#include <cert.h>
+#include <keyhi.h>
+#include <nss.h>
+
+#include "base/base64.h"
+#include "base/values.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace net {
+
+namespace JwkSerializer {
+
+namespace {
+
+bool ConvertEcPrime256v1PublicKeyInfoToJwk(
+    CERTSubjectPublicKeyInfo* spki,
+    base::DictionaryValue* public_key_jwk) {
+  static const int kPrime256v1EncodingType = 4;
+  static const int kPrime256v1PublicKeyLength = 64;
+  // The public key value is encoded as 0x04 + 64 bytes of public key.
+  // NSS gives the length as the bit length.
+  if (spki->subjectPublicKey.len != (kPrime256v1PublicKeyLength + 1) * 8 ||
+      spki->subjectPublicKey.data[0] != kPrime256v1EncodingType)
+    return false;
+
+  public_key_jwk->SetString("alg", "EC");
+  public_key_jwk->SetString("crv", "P-256");
+
+  base::StringPiece x(
+      reinterpret_cast<char*>(spki->subjectPublicKey.data + 1),
+      kPrime256v1PublicKeyLength / 2);
+  std::string x_b64;
+  base::Base64Encode(x, &x_b64);
+  public_key_jwk->SetString("x", x_b64);
+
+  base::StringPiece y(
+      reinterpret_cast<char*>(spki->subjectPublicKey.data + 1 +
+                              kPrime256v1PublicKeyLength / 2),
+      kPrime256v1PublicKeyLength / 2);
+  std::string y_b64;
+  base::Base64Encode(y, &y_b64);
+  public_key_jwk->SetString("y", y_b64);
+  return true;
+}
+
+bool ConvertEcPublicKeyInfoToJwk(
+    CERTSubjectPublicKeyInfo* spki,
+    base::DictionaryValue* public_key_jwk) {
+  // 1.2.840.10045.3.1.7
+  // (iso.member-body.us.ansi-x9-62.ellipticCurve.primeCurve.prime256v1)
+  // (This includes the DER-encoded type (OID) and length: parameters can be
+  // anything, so the DER type isn't implied, and NSS includes it.)
+  static const unsigned char kPrime256v1[] = {
+    0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
+  };
+  if (spki->algorithm.parameters.len == sizeof(kPrime256v1) &&
+      !memcmp(spki->algorithm.parameters.data, kPrime256v1,
+              sizeof(kPrime256v1))) {
+    return ConvertEcPrime256v1PublicKeyInfoToJwk(spki, public_key_jwk);
+  }
+  // TODO(juanlang): other curves
+  return false;
+}
+
+typedef scoped_ptr_malloc<
+    CERTSubjectPublicKeyInfo,
+    crypto::NSSDestroyer<CERTSubjectPublicKeyInfo,
+                         SECKEY_DestroySubjectPublicKeyInfo> >
+    ScopedCERTSubjectPublicKeyInfo;
+
+}  // namespace
+
+bool ConvertSpkiFromDerToJwk(
+    const base::StringPiece& spki_der,
+    base::DictionaryValue* public_key_jwk) {
+  public_key_jwk->Clear();
+
+  crypto::EnsureNSSInit();
+
+  if (!NSS_IsInitialized())
+    return false;
+
+  SECItem sec_item;
+  sec_item.data = const_cast<unsigned char*>(
+      reinterpret_cast<const unsigned char*>(spki_der.data()));
+  sec_item.len = spki_der.size();
+  ScopedCERTSubjectPublicKeyInfo spki(
+      SECKEY_DecodeDERSubjectPublicKeyInfo(&sec_item));
+  if (!spki)
+    return false;
+
+  // 1.2.840.10045.2
+  // (iso.member-body.us.ansi-x9-62.id-ecPublicKey)
+  // (This omits the ASN.1 encoding of the type (OID) and length: the fact that
+  // this is an OID is already clear, and NSS omits it here.)
+  static const unsigned char kIdEcPublicKey[] = {
+    0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01
+  };
+  bool rv = false;
+  if (spki->algorithm.algorithm.len == sizeof(kIdEcPublicKey) &&
+      !memcmp(spki->algorithm.algorithm.data, kIdEcPublicKey,
+              sizeof(kIdEcPublicKey))) {
+    rv = ConvertEcPublicKeyInfoToJwk(spki.get(), public_key_jwk);
+  }
+  // TODO(juanlang): other algorithms
+  return rv;
+}
+
+}  // namespace JwkSerializer
+
+}  // namespace net
diff --git a/net/cert/jwk_serializer_openssl.cc b/net/cert/jwk_serializer_openssl.cc
new file mode 100644
index 0000000..ef15b4b
--- /dev/null
+++ b/net/cert/jwk_serializer_openssl.cc
@@ -0,0 +1,22 @@
+// 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 "base/logging.h"
+#include "net/cert/jwk_serializer.h"
+
+namespace net {
+
+namespace JwkSerializer {
+
+bool ConvertSpkiFromDerToJwk(
+    const base::StringPiece& spki_der,
+    base::DictionaryValue* public_key_jwk) {
+  // TODO(juanlang): implement
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace JwkSerializer
+
+}  // namespace net
diff --git a/net/cert/jwk_serializer_unittest.cc b/net/cert/jwk_serializer_unittest.cc
new file mode 100644
index 0000000..37b8002
--- /dev/null
+++ b/net/cert/jwk_serializer_unittest.cc
@@ -0,0 +1,148 @@
+// 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 "net/cert/jwk_serializer.h"
+
+#include "base/base64.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+// This is the ASN.1 prefix for a P-256 public key. Specifically it's:
+// SEQUENCE
+//   SEQUENCE
+//     OID id-ecPublicKey
+//     OID prime256v1
+//   BIT STRING, length 66, 0 trailing bits: 0x04
+//
+// The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62
+// public key. Following that are the two field elements as 32-byte,
+// big-endian numbers, as required by the Channel ID.
+static const unsigned char kP256SpkiPrefix[] = {
+    0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+    0x42, 0x00, 0x04
+};
+static const unsigned int kEcPointSize = 32U;
+
+// This is a valid P-256 public key.
+static const unsigned char kSpkiEc[] = {
+    0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+    0x42, 0x00, 0x04,
+    0x29, 0x5d, 0x6e, 0xfe, 0x33, 0x77, 0x26, 0xea,
+    0x5b, 0xa4, 0xe6, 0x1b, 0x34, 0x6e, 0x7b, 0xa0,
+    0xa3, 0x8f, 0x33, 0x49, 0xa0, 0x9c, 0xae, 0x98,
+    0xbd, 0x46, 0x0d, 0xf6, 0xd4, 0x5a, 0xdc, 0x8a,
+    0x1f, 0x8a, 0xb2, 0x20, 0x51, 0xb7, 0xd2, 0x87,
+    0x0d, 0x53, 0x7e, 0x5d, 0x94, 0xa3, 0xe0, 0x34,
+    0x16, 0xa1, 0xcc, 0x10, 0x48, 0xcd, 0x70, 0x9c,
+    0x05, 0xd3, 0xd2, 0xca, 0xdf, 0x44, 0x2f, 0xf4
+};
+
+// This is a P-256 public key with 0 X and Y values.
+static const unsigned char kSpkiEcWithZeroXY[] = {
+    0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+    0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
+    0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+    0x42, 0x00, 0x04,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+#if !defined(USE_OPENSSL)
+
+TEST(JwkSerializerNSSTest, ConvertSpkiFromDerToJwkEc) {
+  base::StringPiece spki;
+  base::DictionaryValue public_key_jwk;
+
+  EXPECT_FALSE(JwkSerializer::ConvertSpkiFromDerToJwk(spki, &public_key_jwk));
+  EXPECT_TRUE(public_key_jwk.empty());
+
+  // Test the result of a "normal" point on this curve.
+  spki.set(reinterpret_cast<const char*>(kSpkiEc), sizeof(kSpkiEc));
+  EXPECT_TRUE(JwkSerializer::ConvertSpkiFromDerToJwk(spki, &public_key_jwk));
+
+  std::string string_value;
+  EXPECT_TRUE(public_key_jwk.GetString("alg", &string_value));
+  EXPECT_STREQ("EC", string_value.c_str());
+  EXPECT_TRUE(public_key_jwk.GetString("crv", &string_value));
+  EXPECT_STREQ("P-256", string_value.c_str());
+
+  EXPECT_TRUE(public_key_jwk.GetString("x", &string_value));
+  std::string decoded_coordinate;
+  EXPECT_TRUE(base::Base64Decode(string_value, &decoded_coordinate));
+  EXPECT_EQ(kEcPointSize, decoded_coordinate.size());
+  EXPECT_EQ(0,
+            memcmp(decoded_coordinate.data(),
+                   kSpkiEc + sizeof(kP256SpkiPrefix),
+                   kEcPointSize));
+
+  EXPECT_TRUE(public_key_jwk.GetString("y", &string_value));
+  EXPECT_TRUE(base::Base64Decode(string_value, &decoded_coordinate));
+  EXPECT_EQ(kEcPointSize, decoded_coordinate.size());
+  EXPECT_EQ(0,
+            memcmp(decoded_coordinate.data(),
+                  kSpkiEc + sizeof(kP256SpkiPrefix) + kEcPointSize,
+                  kEcPointSize));
+
+  // Test the result of a corner case: leading 0s in the x, y coordinates are
+  // not trimmed, but the point is fixed-length encoded.
+  spki.set(reinterpret_cast<const char*>(kSpkiEcWithZeroXY),
+           sizeof(kSpkiEcWithZeroXY));
+  EXPECT_TRUE(JwkSerializer::ConvertSpkiFromDerToJwk(spki, &public_key_jwk));
+
+  EXPECT_TRUE(public_key_jwk.GetString("alg", &string_value));
+  EXPECT_STREQ("EC", string_value.c_str());
+  EXPECT_TRUE(public_key_jwk.GetString("crv", &string_value));
+  EXPECT_STREQ("P-256", string_value.c_str());
+
+  EXPECT_TRUE(public_key_jwk.GetString("x", &string_value));
+  EXPECT_TRUE(base::Base64Decode(string_value, &decoded_coordinate));
+  EXPECT_EQ(kEcPointSize, decoded_coordinate.size());
+  EXPECT_EQ(0,
+            memcmp(decoded_coordinate.data(),
+                   kSpkiEcWithZeroXY + sizeof(kP256SpkiPrefix),
+                   kEcPointSize));
+
+  EXPECT_TRUE(public_key_jwk.GetString("y", &string_value));
+  EXPECT_TRUE(base::Base64Decode(string_value, &decoded_coordinate));
+  EXPECT_EQ(kEcPointSize, decoded_coordinate.size());
+  EXPECT_EQ(0,
+            memcmp(decoded_coordinate.data(),
+                   kSpkiEcWithZeroXY + sizeof(kP256SpkiPrefix) + kEcPointSize,
+                   kEcPointSize));
+}
+
+#else
+
+// For OpenSSL, JwkSerializer::ConvertSpkiFromDerToJwk() is not yet implemented
+// and should return false.  This unit test ensures that a stub implementation
+// is present.
+TEST(JwkSerializerOpenSSLTest, ConvertSpkiFromDerToJwkNotImplemented) {
+  base::StringPiece spki;
+  base::DictionaryValue public_key_jwk;
+
+  // The empty SPKI is trivially non-convertible...
+  EXPECT_FALSE(JwkSerializer::ConvertSpkiFromDerToJwk(spki, &public_key_jwk));
+  EXPECT_TRUE(public_key_jwk.empty());
+  // but even a valid SPKI is non-convertible via the stub OpenSSL
+  // implementation.
+  spki.set(reinterpret_cast<const char*>(kSpkiEc), sizeof(kSpkiEc));
+  EXPECT_FALSE(JwkSerializer::ConvertSpkiFromDerToJwk(spki, &public_key_jwk));
+  EXPECT_TRUE(public_key_jwk.empty());
+}
+
+#endif  // !defined(USE_OPENSSL)
+
+}  // namespace net
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc
index 7bef5f0..3c3ec7d 100644
--- a/net/disk_cache/simple/simple_entry_impl.cc
+++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -125,14 +125,6 @@
                              g_open_entry_count);
 }
 
-bool OperationsConflict(int index1, int offset1, int length1, bool truncate1,
-                        int index2, int offset2, int length2, bool truncate2) {
-  int end1 = truncate1 ? INT_MAX : offset1 + length1;
-  int end2 = truncate2 ? INT_MAX : offset2 + length2;
-  bool ranges_intersect = (offset1 < end2 && offset2 < end1);
-  return (index1 == index2 && ranges_intersect);
-}
-
 }  // namespace
 
 namespace disk_cache {
@@ -220,11 +212,8 @@
     return net::ERR_FAILED;
   }
 
-  EnqueueOperation(base::Bind(&SimpleEntryImpl::OpenEntryInternal,
-                              this,
-                              have_index,
-                              callback,
-                              out_entry));
+  pending_operations_.push(SimpleEntryOperation::OpenOperation(
+      this, have_index, callback, out_entry));
   RunNextOperationIfNeeded();
   return net::ERR_IO_PENDING;
 }
@@ -243,18 +232,12 @@
     net_log_.AddEvent(net::NetLog::TYPE_SIMPLE_CACHE_ENTRY_CREATE_OPTIMISTIC);
 
     ReturnEntryToCaller(out_entry);
-    EnqueueOperation(base::Bind(&SimpleEntryImpl::CreateEntryInternal,
-                                this,
-                                have_index,
-                                CompletionCallback(),
-                                static_cast<Entry**>(NULL)));
+    pending_operations_.push(SimpleEntryOperation::CreateOperation(
+        this, have_index, CompletionCallback(), static_cast<Entry**>(NULL)));
     ret_value = net::OK;
   } else {
-    EnqueueOperation(base::Bind(&SimpleEntryImpl::CreateEntryInternal,
-                                this,
-                                have_index,
-                                callback,
-                                out_entry));
+    pending_operations_.push(SimpleEntryOperation::CreateOperation(
+        this, have_index, callback, out_entry));
     ret_value = net::ERR_IO_PENDING;
   }
 
@@ -305,7 +288,7 @@
     return;
   }
 
-  EnqueueOperation(base::Bind(&SimpleEntryImpl::CloseInternal, this));
+  pending_operations_.push(SimpleEntryOperation::CloseOperation(this));
   DCHECK(!HasOneRef());
   Release();  // Balanced in ReturnEntryToCaller().
   RunNextOperationIfNeeded();
@@ -368,16 +351,10 @@
 
   // TODO(felipeg): Optimization: Add support for truly parallel read
   // operations.
-  EnqueueReadOperation(base::Bind(&SimpleEntryImpl::ReadDataInternal,
-                                  this,
-                                  stream_index,
-                                  offset,
-                                  make_scoped_refptr(buf),
-                                  buf_len,
-                                  callback),
-                       stream_index,
-                       offset,
-                       buf_len);
+  bool alone_in_queue =
+      pending_operations_.size() == 0 && state_ == STATE_READY;
+  pending_operations_.push(SimpleEntryOperation::ReadOperation(
+      this, stream_index, offset, buf_len, buf, callback, alone_in_queue));
   RunNextOperationIfNeeded();
   return net::ERR_IO_PENDING;
 }
@@ -462,13 +439,14 @@
     }
   }
 
-  EnqueueWriteOperation(optimistic,
-                        stream_index,
-                        offset,
-                        op_buf.get(),
-                        buf_len,
-                        truncate,
-                        op_callback);
+  pending_operations_.push(SimpleEntryOperation::WriteOperation(this,
+                                                                stream_index,
+                                                                offset,
+                                                                buf_len,
+                                                                op_buf.get(),
+                                                                truncate,
+                                                                optimistic,
+                                                                op_callback));
   return ret_value;
 }
 
@@ -521,9 +499,6 @@
   return net::ERR_FAILED;
 }
 
-SimpleEntryImpl::LastQueuedOpInfo::LastQueuedOpInfo()
-    : is_optimistic_write(false), is_write(false), is_read(false) {}
-
 SimpleEntryImpl::~SimpleEntryImpl() {
   DCHECK(io_thread_checker_.CalledOnValidThread());
   DCHECK_EQ(0U, pending_operations_.size());
@@ -570,98 +545,51 @@
   UMA_HISTOGRAM_CUSTOM_COUNTS("SimpleCache.EntryOperationsPending",
                               pending_operations_.size(), 0, 100, 20);
   if (!pending_operations_.empty() && state_ != STATE_IO_PENDING) {
-    base::Closure operation = pending_operations_.front();
+    scoped_ptr<SimpleEntryOperation> operation(
+        new SimpleEntryOperation(pending_operations_.front()));
     pending_operations_.pop();
-    operation.Run();
+    switch (operation->type()) {
+      case SimpleEntryOperation::TYPE_OPEN:
+        OpenEntryInternal(operation->have_index(),
+                          operation->callback(),
+                          operation->out_entry());
+        break;
+      case SimpleEntryOperation::TYPE_CREATE:
+        CreateEntryInternal(operation->have_index(),
+                            operation->callback(),
+                            operation->out_entry());
+        break;
+      case SimpleEntryOperation::TYPE_CLOSE:
+        CloseInternal();
+        break;
+      case SimpleEntryOperation::TYPE_READ:
+        RecordReadIsParallelizable(*operation);
+        ReadDataInternal(operation->index(),
+                         operation->offset(),
+                         operation->buf(),
+                         operation->length(),
+                         operation->callback());
+        break;
+      case SimpleEntryOperation::TYPE_WRITE:
+        RecordWriteDependencyType(*operation);
+        WriteDataInternal(operation->index(),
+                          operation->offset(),
+                          operation->buf(),
+                          operation->length(),
+                          operation->callback(),
+                          operation->truncate());
+        break;
+      default:
+        NOTREACHED();
+    }
+    // The operation is kept for histograms. Makes sure it does not leak
+    // resources.
+    executing_operation_.swap(operation);
+    executing_operation_->ReleaseReferences();
     // |this| may have been deleted.
   }
 }
 
-void SimpleEntryImpl::EnqueueOperation(const base::Closure& operation) {
-  last_op_info_.is_read = false;
-  last_op_info_.is_write = false;
-  last_op_info_.is_optimistic_write = false;
-  pending_operations_.push(operation);
-}
-
-void SimpleEntryImpl::EnqueueReadOperation(const base::Closure& operation,
-                                           int index,
-                                           int offset,
-                                           int length) {
-  bool parallelizable_read = last_op_info_.is_read &&
-      (!pending_operations_.empty() || state_ == STATE_IO_PENDING);
-  UMA_HISTOGRAM_BOOLEAN("SimpleCache.ReadIsParallelizable",
-                        parallelizable_read);
-  last_op_info_.is_read = true;
-  last_op_info_.is_write = false;
-  last_op_info_.is_optimistic_write = false;
-  last_op_info_.io_index = index;
-  last_op_info_.io_offset = offset;
-  last_op_info_.io_length = length;
-  pending_operations_.push(operation);
-}
-
-void SimpleEntryImpl::EnqueueWriteOperation(
-    bool optimistic,
-    int index,
-    int offset,
-    net::IOBuffer* buf,
-    int length,
-    bool truncate,
-    const CompletionCallback& callback) {
-  // Used in histograms, please only add entries at the end.
-  enum WriteDependencyType {
-    WRITE_OPTIMISTIC = 0,
-    WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC = 1,
-    WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC = 2,
-    WRITE_FOLLOWS_CONFLICTING_WRITE = 3,
-    WRITE_FOLLOWS_NON_CONFLICTING_WRITE = 4,
-    WRITE_FOLLOWS_CONFLICTING_READ = 5,
-    WRITE_FOLLOWS_NON_CONFLICTING_READ = 6,
-    WRITE_FOLLOWS_OTHER = 7,
-    WRITE_DEPENDENCY_TYPE_MAX = 8,
-  };
-
-  WriteDependencyType type = WRITE_FOLLOWS_OTHER;
-  if (optimistic) {
-    type = WRITE_OPTIMISTIC;
-  } else if (last_op_info_.is_read || last_op_info_.is_write) {
-    bool conflicting = OperationsConflict(
-        index, offset, length, truncate,
-        last_op_info_.io_index,
-        last_op_info_.io_offset, last_op_info_.io_length,
-        last_op_info_.truncate && last_op_info_.is_write);
-
-    if (last_op_info_.is_optimistic_write) {
-      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC
-                         : WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC;
-    } else if (last_op_info_.is_read) {
-      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_READ
-                         : WRITE_FOLLOWS_NON_CONFLICTING_READ;
-    } else {
-      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_WRITE
-                         : WRITE_FOLLOWS_NON_CONFLICTING_WRITE;
-    }
-  }
-  UMA_HISTOGRAM_ENUMERATION(
-      "SimpleCache.WriteDependencyType", type, WRITE_DEPENDENCY_TYPE_MAX);
-  last_op_info_.is_read = false;
-  last_op_info_.is_write = true;
-  last_op_info_.is_optimistic_write = optimistic;
-  last_op_info_.io_index = index;
-  last_op_info_.io_offset = offset;
-  last_op_info_.io_length = length;
-  last_op_info_.truncate = truncate;
-  pending_operations_.push(base::Bind(&SimpleEntryImpl::WriteDataInternal,
-                                      this,
-                                      index,
-                                      offset,
-                                      make_scoped_refptr(buf),
-                                      length,
-                                      callback,
-                                      truncate));
-}
-
 void SimpleEntryImpl::OpenEntryInternal(bool have_index,
                                         const CompletionCallback& callback,
                                         Entry** out_entry) {
@@ -1204,4 +1132,56 @@
   return file_size;
 }
 
+void SimpleEntryImpl::RecordReadIsParallelizable(
+    const SimpleEntryOperation& operation) const {
+  if (!executing_operation_)
+    return;
+  // TODO(clamy): The values of this histogram should be changed to something
+  // more useful.
+  bool parallelizable_read =
+      !operation.alone_in_queue() &&
+      executing_operation_->type() == SimpleEntryOperation::TYPE_READ;
+  UMA_HISTOGRAM_BOOLEAN("SimpleCache.ReadIsParallelizable",
+                        parallelizable_read);
+}
+
+void SimpleEntryImpl::RecordWriteDependencyType(
+    const SimpleEntryOperation& operation) const {
+  if (!executing_operation_)
+    return;
+  // Used in histograms, please only add entries at the end.
+  enum WriteDependencyType {
+    WRITE_OPTIMISTIC = 0,
+    WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC = 1,
+    WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC = 2,
+    WRITE_FOLLOWS_CONFLICTING_WRITE = 3,
+    WRITE_FOLLOWS_NON_CONFLICTING_WRITE = 4,
+    WRITE_FOLLOWS_CONFLICTING_READ = 5,
+    WRITE_FOLLOWS_NON_CONFLICTING_READ = 6,
+    WRITE_FOLLOWS_OTHER = 7,
+    WRITE_DEPENDENCY_TYPE_MAX = 8,
+  };
+
+  WriteDependencyType type = WRITE_FOLLOWS_OTHER;
+  if (operation.optimistic()) {
+    type = WRITE_OPTIMISTIC;
+  } else if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ ||
+             executing_operation_->type() == SimpleEntryOperation::TYPE_WRITE) {
+    bool conflicting = executing_operation_->ConflictsWith(operation);
+
+    if (executing_operation_->type() == SimpleEntryOperation::TYPE_READ) {
+      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_READ
+                         : WRITE_FOLLOWS_NON_CONFLICTING_READ;
+    } else if (executing_operation_->optimistic()) {
+      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_OPTIMISTIC
+                         : WRITE_FOLLOWS_NON_CONFLICTING_OPTIMISTIC;
+    } else {
+      type = conflicting ? WRITE_FOLLOWS_CONFLICTING_WRITE
+                         : WRITE_FOLLOWS_NON_CONFLICTING_WRITE;
+    }
+  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "SimpleCache.WriteDependencyType", type, WRITE_DEPENDENCY_TYPE_MAX);
+}
+
 }  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_entry_impl.h b/net/disk_cache/simple/simple_entry_impl.h
index be28fb8..7eb8914 100644
--- a/net/disk_cache/simple/simple_entry_impl.h
+++ b/net/disk_cache/simple/simple_entry_impl.h
@@ -16,6 +16,7 @@
 #include "net/base/net_log.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/disk_cache/simple/simple_entry_format.h"
+#include "net/disk_cache/simple/simple_entry_operation.h"
 
 namespace base {
 class TaskRunner;
@@ -129,22 +130,6 @@
     CRC_CHECK_MAX = 4,
   };
 
-  // Used in histograms.
-  struct LastQueuedOpInfo {
-    LastQueuedOpInfo();
-
-    // Used for SimpleCache.WriteDependencyType.
-    int io_index;
-    int io_offset;
-    int io_length;
-    bool is_optimistic_write;
-    bool is_write;
-    bool truncate;
-
-    // Used for SimpleCache.ReadIsParallelizable histogram.
-    bool is_read;
-  };
-
   virtual ~SimpleEntryImpl();
 
   // Sets entry to STATE_UNINITIALIZED.
@@ -169,24 +154,6 @@
   // the last reference.
   void RunNextOperationIfNeeded();
 
-  // Adds a non read operation to the queue of operations.
-  void EnqueueOperation(const base::Closure& operation);
-
-  // Adds a read operation to the queue of operations.
-  void EnqueueReadOperation(const base::Closure& operation,
-                            int index,
-                            int offset,
-                            int length);
-
-  // Adds a write operation to the queue of operations.
-  void EnqueueWriteOperation(bool optimistic,
-                             int index,
-                             int offset,
-                             net::IOBuffer* buf,
-                             int length,
-                             bool truncate,
-                             const CompletionCallback& callback);
-
   void OpenEntryInternal(bool have_index,
                          const CompletionCallback& callback,
                          Entry** out_entry);
@@ -263,6 +230,10 @@
 
   int64 GetDiskUsage() const;
 
+  // Used to report histograms.
+  void RecordReadIsParallelizable(const SimpleEntryOperation& operation) const;
+  void RecordWriteDependencyType(const SimpleEntryOperation& operation) const;
+
   // All nonstatic SimpleEntryImpl methods should always be called on the IO
   // thread, in all cases. |io_thread_checker_| documents and enforces this.
   base::ThreadChecker io_thread_checker_;
@@ -307,11 +278,11 @@
   // is false (i.e. when an operation is not pending on the worker pool).
   SimpleSynchronousEntry* synchronous_entry_;
 
-  std::queue<base::Closure> pending_operations_;
+  std::queue<SimpleEntryOperation> pending_operations_;
 
   net::BoundNetLog net_log_;
 
-  LastQueuedOpInfo last_op_info_;
+  scoped_ptr<SimpleEntryOperation> executing_operation_;
 };
 
 }  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_entry_operation.cc b/net/disk_cache/simple/simple_entry_operation.cc
new file mode 100644
index 0000000..81d5f7c
--- /dev/null
+++ b/net/disk_cache/simple/simple_entry_operation.cc
@@ -0,0 +1,184 @@
+// 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 "net/disk_cache/simple/simple_entry_operation.h"
+
+#include "base/logging.h"
+#include "net/base/io_buffer.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/disk_cache/simple/simple_entry_impl.h"
+
+namespace disk_cache {
+
+SimpleEntryOperation::SimpleEntryOperation(const SimpleEntryOperation& other)
+    : entry_(other.entry_.get()),
+      buf_(other.buf_),
+      callback_(other.callback_),
+      out_entry_(other.out_entry_),
+      offset_(other.offset_),
+      length_(other.length_),
+      type_(other.type_),
+      have_index_(other.have_index_),
+      index_(other.index_),
+      truncate_(other.truncate_),
+      optimistic_(other.optimistic_),
+      alone_in_queue_(other.alone_in_queue_) {
+}
+
+SimpleEntryOperation::~SimpleEntryOperation() {}
+
+// Static.
+SimpleEntryOperation SimpleEntryOperation::OpenOperation(
+    SimpleEntryImpl* entry,
+    bool have_index,
+    const CompletionCallback& callback,
+    Entry** out_entry) {
+  return SimpleEntryOperation(entry,
+                              NULL,
+                              callback,
+                              out_entry,
+                              0,
+                              0,
+                              TYPE_OPEN,
+                              have_index,
+                              0,
+                              false,
+                              false,
+                              false);
+}
+
+// Static.
+SimpleEntryOperation SimpleEntryOperation::CreateOperation(
+    SimpleEntryImpl* entry,
+    bool have_index,
+    const CompletionCallback& callback,
+    Entry** out_entry) {
+  return SimpleEntryOperation(entry,
+                              NULL,
+                              callback,
+                              out_entry,
+                              0,
+                              0,
+                              TYPE_CREATE,
+                              have_index,
+                              0,
+                              false,
+                              false,
+                              false);
+}
+
+// Static.
+SimpleEntryOperation SimpleEntryOperation::CloseOperation(
+    SimpleEntryImpl* entry) {
+  return SimpleEntryOperation(entry,
+                              NULL,
+                              CompletionCallback(),
+                              NULL,
+                              0,
+                              0,
+                              TYPE_CLOSE,
+                              false,
+                              0,
+                              false,
+                              false,
+                              false);
+}
+
+// Static.
+SimpleEntryOperation SimpleEntryOperation::ReadOperation(
+    SimpleEntryImpl* entry,
+    int index,
+    int offset,
+    int length,
+    net::IOBuffer* buf,
+    const CompletionCallback& callback,
+    bool alone_in_queue) {
+  return SimpleEntryOperation(entry,
+                              buf,
+                              callback,
+                              NULL,
+                              offset,
+                              length,
+                              TYPE_READ,
+                              false,
+                              index,
+                              false,
+                              false,
+                              alone_in_queue);
+}
+
+// Static.
+SimpleEntryOperation SimpleEntryOperation::WriteOperation(
+    SimpleEntryImpl* entry,
+    int index,
+    int offset,
+    int length,
+    net::IOBuffer* buf,
+    bool truncate,
+    bool optimistic,
+    const CompletionCallback& callback) {
+  return SimpleEntryOperation(entry,
+                              buf,
+                              callback,
+                              NULL,
+                              offset,
+                              length,
+                              TYPE_WRITE,
+                              false,
+                              index,
+                              truncate,
+                              optimistic,
+                              false);
+}
+
+bool SimpleEntryOperation::ConflictsWith(
+    const SimpleEntryOperation& other_op) const {
+  if (type_ != TYPE_READ && type_ != TYPE_WRITE)
+    return true;
+  if (other_op.type() != TYPE_READ && other_op.type() != TYPE_WRITE)
+    return true;
+  if (type() == TYPE_READ && other_op.type() == TYPE_READ)
+    return false;
+  if (index_ != other_op.index_)
+    return false;
+  int end = (type_ == TYPE_WRITE && truncate_) ? INT_MAX : offset_ + length_;
+  int other_op_end = (other_op.type() == TYPE_WRITE && other_op.truncate())
+                         ? INT_MAX
+                         : other_op.offset() + other_op.length();
+  return (offset_ < other_op_end && other_op.offset() < end);
+}
+
+void SimpleEntryOperation::ReleaseReferences() {
+  callback_ = CompletionCallback();
+  buf_ = NULL;
+  entry_ = NULL;
+}
+
+SimpleEntryOperation::SimpleEntryOperation(SimpleEntryImpl* entry,
+                                           net::IOBuffer* buf,
+                                           const CompletionCallback& callback,
+                                           Entry** out_entry,
+                                           int offset,
+                                           int length,
+                                           EntryOperationType type,
+                                           bool have_index,
+                                           int index,
+                                           bool truncate,
+                                           bool optimistic,
+                                           bool alone_in_queue)
+    : entry_(entry),
+      buf_(buf),
+      callback_(callback),
+      out_entry_(out_entry),
+      offset_(offset),
+      length_(length),
+      type_(type),
+      have_index_(have_index),
+      index_(index),
+      truncate_(truncate),
+      optimistic_(optimistic),
+      alone_in_queue_(alone_in_queue) {
+}
+
+}  // namespace disk_cache
diff --git a/net/disk_cache/simple/simple_entry_operation.h b/net/disk_cache/simple/simple_entry_operation.h
new file mode 100644
index 0000000..acdd60a
--- /dev/null
+++ b/net/disk_cache/simple/simple_entry_operation.h
@@ -0,0 +1,125 @@
+// 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 NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_OPERATION_H_
+#define NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_OPERATION_H_
+
+#include "base/memory/ref_counted.h"
+#include "net/base/completion_callback.h"
+#include "net/base/net_log.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace disk_cache {
+
+class Entry;
+class SimpleEntryImpl;
+
+// SimpleEntryOperation stores the information regarding operations in
+// SimpleEntryImpl, between the moment they are issued by users of the backend,
+// and the moment when they are executed.
+class SimpleEntryOperation {
+ public:
+  typedef net::CompletionCallback CompletionCallback;
+
+  enum EntryOperationType {
+    TYPE_OPEN = 0,
+    TYPE_CREATE = 1,
+    TYPE_CLOSE = 2,
+    TYPE_READ = 3,
+    TYPE_WRITE = 4,
+  };
+
+  SimpleEntryOperation(const SimpleEntryOperation& other);
+  ~SimpleEntryOperation();
+
+  static SimpleEntryOperation OpenOperation(SimpleEntryImpl* entry,
+                                            bool have_index,
+                                            const CompletionCallback& callback,
+                                            Entry** out_entry);
+  static SimpleEntryOperation CreateOperation(
+      SimpleEntryImpl* entry,
+      bool have_index,
+      const CompletionCallback& callback,
+      Entry** out_entry);
+  static SimpleEntryOperation CloseOperation(SimpleEntryImpl* entry);
+  static SimpleEntryOperation ReadOperation(SimpleEntryImpl* entry,
+                                            int index,
+                                            int offset,
+                                            int length,
+                                            net::IOBuffer* buf,
+                                            const CompletionCallback& callback,
+                                            bool alone_in_queue);
+  static SimpleEntryOperation WriteOperation(
+      SimpleEntryImpl* entry,
+      int index,
+      int offset,
+      int length,
+      net::IOBuffer* buf,
+      bool truncate,
+      bool optimistic,
+      const CompletionCallback& callback);
+
+  bool ConflictsWith(const SimpleEntryOperation& other_op) const;
+  // Releases all references. After calling this operation, SimpleEntryOperation
+  // will only hold POD members.
+  void ReleaseReferences();
+
+  EntryOperationType type() const {
+    return static_cast<EntryOperationType>(type_);
+  }
+  const CompletionCallback& callback() const { return callback_; }
+  Entry** out_entry() { return out_entry_; }
+  bool have_index() const { return have_index_; }
+  int index() const { return index_; }
+  int offset() const { return offset_; }
+  int length() const { return length_; }
+  net::IOBuffer* buf() { return buf_.get(); }
+  bool truncate() const { return truncate_; }
+  bool optimistic() const { return optimistic_; }
+  bool alone_in_queue() const { return alone_in_queue_; }
+
+ private:
+  SimpleEntryOperation(SimpleEntryImpl* entry,
+                       net::IOBuffer* buf,
+                       const CompletionCallback& callback,
+                       Entry** out_entry,
+                       int offset,
+                       int length,
+                       EntryOperationType type,
+                       bool have_index,
+                       int index,
+                       bool truncate,
+                       bool optimistic,
+                       bool alone_in_queue);
+
+  // This ensures entry will not be deleted until the operation has ran.
+  scoped_refptr<SimpleEntryImpl> entry_;
+  scoped_refptr<net::IOBuffer> buf_;
+  CompletionCallback callback_;
+
+  // Used in open and create operations.
+  Entry** out_entry_;
+
+  // Used in write and read operations.
+  const int offset_;
+  const int length_;
+
+  const unsigned int type_ : 3;           /* 3 */
+  // Used in open and create operations.
+  const unsigned int have_index_ : 1;     /* 4 */
+  // Used in write and read operations.
+  const unsigned int index_ : 2;          /* 6 */
+  // Used only in write operations.
+  const unsigned int truncate_ : 1;       /* 7 */
+  const unsigned int optimistic_ : 1;     /* 8 */
+  // Used only in SimpleCache.ReadIsParallelizable histogram.
+  const unsigned int alone_in_queue_ : 1; /* 9 */
+};
+
+}  // namespace disk_cache
+
+#endif  // NET_DISK_CACHE_SIMPLE_SIMPLE_ENTRY_OPERATION_H_
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index 089a51a..8f79edf 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -622,8 +622,7 @@
     client_->core()->QueryCache(rrtype_, name_, &records);
     for (std::vector<const RecordParsed*>::iterator i = records.begin();
          i != records.end() && weak_this; ++i) {
-      weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD,
-                                 records.front());
+      weak_this->TriggerCallback(MDnsTransaction::RESULT_RECORD, *i);
     }
 
 #if defined(ENABLE_NSEC)
diff --git a/net/net.gyp b/net/net.gyp
index 8942367..0165031 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -271,6 +271,9 @@
         'cert/crl_set.h',
         'cert/ev_root_ca_metadata.cc',
         'cert/ev_root_ca_metadata.h',
+        'cert/jwk_serializer_nss.cc',
+        'cert/jwk_serializer_openssl.cc',
+        'cert/jwk_serializer.h',
         'cert/multi_threaded_cert_verifier.cc',
         'cert/multi_threaded_cert_verifier.h',
         'cert/nss_cert_database.cc',
@@ -390,6 +393,8 @@
         'disk_cache/simple/simple_entry_format.h',
         'disk_cache/simple/simple_entry_impl.cc',
         'disk_cache/simple/simple_entry_impl.h',
+        'disk_cache/simple/simple_entry_operation.cc',
+        'disk_cache/simple/simple_entry_operation.h',
         'disk_cache/simple/simple_index.cc',
         'disk_cache/simple/simple_index.h',
         'disk_cache/simple/simple_index_file.cc',
@@ -1199,6 +1204,7 @@
               'cert/cert_database_nss.cc',
               'cert/cert_verify_proc_nss.cc',
               'cert/cert_verify_proc_nss.h',
+              'cert/jwk_serializer_nss.cc',
               'cert/nss_cert_database.cc',
               'cert/nss_cert_database.h',
               'cert/test_root_certs_nss.cc',
@@ -1236,6 +1242,7 @@
               'cert/cert_database_openssl.cc',
               'cert/cert_verify_proc_openssl.cc',
               'cert/cert_verify_proc_openssl.h',
+              'cert/jwk_serializer_openssl.cc',
               'cert/test_root_certs_openssl.cc',
               'cert/x509_certificate_openssl.cc',
               'cert/x509_util_openssl.cc',
@@ -1524,6 +1531,7 @@
         'cert/cert_verify_proc_unittest.cc',
         'cert/crl_set_unittest.cc',
         'cert/ev_root_ca_metadata_unittest.cc',
+        'cert/jwk_serializer_unittest.cc',
         'cert/multi_threaded_cert_verifier_unittest.cc',
         'cert/nss_cert_database_unittest.cc',
         'cert/pem_tokenizer_unittest.cc',
@@ -1869,11 +1877,14 @@
             'tools/quic/quic_in_memory_cache_test.cc',
             'tools/quic/quic_reliable_client_stream_test.cc',
             'tools/quic/quic_reliable_server_stream_test.cc',
+            'tools/quic/quic_server_test.cc',
             'tools/quic/quic_spdy_server_stream_test.cc',
             'tools/quic/test_tools/http_message_test_utils.cc',
             'tools/quic/test_tools/http_message_test_utils.h',
             'tools/quic/test_tools/mock_epoll_server.cc',
             'tools/quic/test_tools/mock_epoll_server.h',
+            'tools/quic/test_tools/mock_quic_dispatcher.cc',
+            'tools/quic/test_tools/mock_quic_dispatcher.h',
             'tools/quic/test_tools/quic_client_peer.cc',
             'tools/quic/test_tools/quic_client_peer.h',
             'tools/quic/test_tools/quic_epoll_connection_helper_peer.cc',
diff --git a/net/net.target.darwin-arm.mk b/net/net.target.darwin-arm.mk
index 32a09e6..88d78fc 100644
--- a/net/net.target.darwin-arm.mk
+++ b/net/net.target.darwin-arm.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/net.target.darwin-mips.mk b/net/net.target.darwin-mips.mk
index 47c7546..6fedabc 100644
--- a/net/net.target.darwin-mips.mk
+++ b/net/net.target.darwin-mips.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/net.target.darwin-x86.mk b/net/net.target.darwin-x86.mk
index 24f1ffd..4479a95 100644
--- a/net/net.target.darwin-x86.mk
+++ b/net/net.target.darwin-x86.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/net.target.linux-arm.mk b/net/net.target.linux-arm.mk
index 32a09e6..88d78fc 100644
--- a/net/net.target.linux-arm.mk
+++ b/net/net.target.linux-arm.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/net.target.linux-mips.mk b/net/net.target.linux-mips.mk
index 47c7546..6fedabc 100644
--- a/net/net.target.linux-mips.mk
+++ b/net/net.target.linux-mips.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/net.target.linux-x86.mk b/net/net.target.linux-x86.mk
index 24f1ffd..4479a95 100644
--- a/net/net.target.linux-x86.mk
+++ b/net/net.target.linux-x86.mk
@@ -103,6 +103,7 @@
 	net/cert/cert_verify_result.cc \
 	net/cert/crl_set.cc \
 	net/cert/ev_root_ca_metadata.cc \
+	net/cert/jwk_serializer_openssl.cc \
 	net/cert/multi_threaded_cert_verifier.cc \
 	net/cert/pem_tokenizer.cc \
 	net/cert/single_request_cert_verifier.cc \
@@ -149,6 +150,7 @@
 	net/disk_cache/simple/simple_backend_impl.cc \
 	net/disk_cache/simple/simple_entry_format.cc \
 	net/disk_cache/simple/simple_entry_impl.cc \
+	net/disk_cache/simple/simple_entry_operation.cc \
 	net/disk_cache/simple/simple_index.cc \
 	net/disk_cache/simple/simple_index_file.cc \
 	net/disk_cache/simple/simple_net_log_parameters.cc \
diff --git a/net/quic/crypto/crypto_server_config.h b/net/quic/crypto/crypto_server_config.h
index 651e928..1a99136 100644
--- a/net/quic/crypto/crypto_server_config.h
+++ b/net/quic/crypto/crypto_server_config.h
@@ -198,8 +198,10 @@
    public:
     Config();
 
-    // serialized contains the bytes of this server config, suitable for sending
-    // on the wire.
+    // TODO(rtenneti): since this is a class, we should probably do
+    // getters/setters here.
+    // |serialized| contains the bytes of this server config, suitable for
+    // sending on the wire.
     std::string serialized;
     // id contains the SCID of this server config.
     std::string id;
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index ea738af..30f822c 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -877,8 +877,6 @@
   RetransmissionInfo retransmission_info(serialized_packet.sequence_number);
   retransmission_info.number_retransmissions =
       retransmission_it->second.number_retransmissions + 1;
-  retransmission_map_.insert(make_pair(serialized_packet.sequence_number,
-                                       retransmission_info));
   // Remove info with old sequence number.
   unacked_packets_.erase(unacked_it);
   retransmission_map_.erase(retransmission_it);
@@ -888,6 +886,8 @@
          unacked_packets_.rbegin()->first < serialized_packet.sequence_number);
   unacked_packets_.insert(make_pair(serialized_packet.sequence_number,
                                     unacked));
+  retransmission_map_.insert(make_pair(serialized_packet.sequence_number,
+                                       retransmission_info));
   SendOrQueuePacket(unacked->encryption_level(),
                     serialized_packet.sequence_number,
                     serialized_packet.packet,
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc
index 19e58c3..6d69676 100644
--- a/net/quic/quic_packet_creator.cc
+++ b/net/quic/quic_packet_creator.cc
@@ -111,16 +111,23 @@
   size_t bytes_consumed = 0;
 
   if (data.size() != 0) {
-    size_t min_last_stream_frame_size =
-        QuicFramer::GetMinStreamFrameSize(framer_->version(), id, offset, true);
-    // Comparing against the last stream frame size including the frame length
-    // guarantees that all the bytes will fit.  Otherwise there is a
-    // discontinuity where the packet goes one byte over due to the length data.
-    if (data.size() + min_last_stream_frame_size + kQuicStreamPayloadLengthSize
-        >= free_bytes) {
-      // Its the last frame, put as much data as possible in.
+    // When a STREAM frame is the last frame in a packet, it consumes two fewer
+    // bytes of framing overhead.
+    // Anytime more data is available than fits in with the extra two bytes,
+    // the frame will be the last, and up to two extra bytes are consumed.
+    // TODO(ianswett): If QUIC pads, the 1 byte PADDING frame does not fit when
+    // 1 byte is available, because then the STREAM frame isn't the last.
+
+    // The minimum frame size(0 bytes of data) if it's not the last frame.
+    size_t min_frame_size = QuicFramer::GetMinStreamFrameSize(
+        framer_->version(), id, offset, false);
+    // Check if it's the last frame in the packet.
+    if (data.size() + min_frame_size > free_bytes) {
+      // The minimum frame size(0 bytes of data) if it is the last frame.
+      size_t min_last_frame_size = QuicFramer::GetMinStreamFrameSize(
+          framer_->version(), id, offset, true);
       bytes_consumed =
-          min<size_t>(free_bytes - min_last_stream_frame_size, data.size());
+          min<size_t>(free_bytes - min_last_frame_size, data.size());
     } else {
       DCHECK_LT(data.size(), BytesFree());
       bytes_consumed = data.size();
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc
index f6f94cc..3ade8fb 100644
--- a/net/quic/quic_received_packet_manager.cc
+++ b/net/quic/quic_received_packet_manager.cc
@@ -99,6 +99,8 @@
       packets_entropy_.upper_bound(sequence_number);
   // When this map is empty we should only query entropy for
   // |largest_received_sequence_number_|.
+  // TODO(rtenneti): add support for LOG_IF_EVERY_N_SEC to chromium.
+  // LOG_IF_EVERY_N_SEC(WARNING, it != packets_entropy_.end(), 10)
   LOG_IF(WARNING, it != packets_entropy_.end())
       << "largest_received: " << received_info_.largest_observed
       << " sequence_number: " << sequence_number;
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index fca3904..6650dbf 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -70,6 +70,10 @@
   // "0x0010:  001c fb98 4000 4001 7e18 d8ef 2301 455d  ....@.@.~...#.E]\n"
   // "0x0020:  7fe2 0800 6bcb 0bc6 806e                 ....k....n\n"
   static std::string StringToHexASCIIDump(base::StringPiece in_buffer);
+
+  static char* AsChars(unsigned char* data) {
+    return reinterpret_cast<char*>(data);
+  }
 };
 
 }  // namespace net
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index a5645b9..d1f2832 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -771,8 +771,7 @@
   ////////////////////////////////////////////////////////////////////////////
   int DoBufferRecv(IOBuffer* buffer, int len);
   int DoBufferSend(IOBuffer* buffer, int len);
-  int DoGetDomainBoundCert(const std::string& host,
-                           const std::vector<uint8>& requested_cert_types);
+  int DoGetDomainBoundCert(const std::string& host);
 
   void OnGetDomainBoundCertComplete(int result);
   void OnHandshakeStateUpdated(const HandshakeState& state);
@@ -903,7 +902,6 @@
   // prior to invoking OnHandshakeIOComplete.
   // Read on the NSS task runner when once OnHandshakeIOComplete is invoked
   // on the NSS task runner.
-  SSLClientCertType domain_bound_cert_type_;
   std::string domain_bound_private_key_;
   std::string domain_bound_cert_;
 
@@ -944,8 +942,7 @@
       user_write_buf_len_(0),
       network_task_runner_(network_task_runner),
       nss_task_runner_(nss_task_runner),
-      weak_net_log_(weak_net_log_factory_.GetWeakPtr()),
-      domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE) {
+      weak_net_log_(weak_net_log_factory_.GetWeakPtr()) {
 }
 
 SSLClientSocketNSS::Core::~Core() {
@@ -1274,7 +1271,6 @@
     PRFileDesc* socket,
     PRBool checksig,
     PRBool is_server) {
-#ifdef SSL_ENABLE_FALSE_START
   Core* core = reinterpret_cast<Core*>(arg);
   if (!core->handshake_callback_called_) {
     // Only need to turn off False Start in the initial handshake. Also, it is
@@ -1296,7 +1292,6 @@
       SSL_OptionSet(socket, SSL_ENABLE_FALSE_START, PR_FALSE);
     }
   }
-#endif
 
   // Tell NSS to not verify the certificate.
   return SECSuccess;
@@ -2318,17 +2313,15 @@
   // We have negotiated the TLS channel ID extension.
   core->channel_id_xtn_negotiated_ = true;
   std::string host = core->host_and_port_.host();
-  std::vector<uint8> requested_cert_types;
-  requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
   int error = ERR_UNEXPECTED;
   if (core->OnNetworkTaskRunner()) {
-    error = core->DoGetDomainBoundCert(host, requested_cert_types);
+    error = core->DoGetDomainBoundCert(host);
   } else {
     bool posted = core->network_task_runner_->PostTask(
         FROM_HERE,
         base::Bind(
             IgnoreResult(&Core::DoGetDomainBoundCert),
-            core, host, requested_cert_types));
+            core, host));
     error = posted ? ERR_IO_PENDING : ERR_ABORTED;
   }
 
@@ -2372,9 +2365,7 @@
     return MapNSSError(PORT_GetError());
 
   // Set the private key.
-  switch (domain_bound_cert_type_) {
-    case CLIENT_CERT_ECDSA_SIGN: {
-      if (!crypto::ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
+  if (!crypto::ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
           ServerBoundCertService::kEPKIPassword,
           reinterpret_cast<const unsigned char*>(
               domain_bound_private_key_.data()),
@@ -2384,15 +2375,8 @@
           false,
           key,
           public_key)) {
-        int error = MapNSSError(PORT_GetError());
-        return error;
-      }
-      break;
-    }
-
-    default:
-      NOTREACHED();
-      return ERR_INVALID_ARGUMENT;
+    int error = MapNSSError(PORT_GetError());
+    return error;
   }
 
   return OK;
@@ -2433,8 +2417,8 @@
          SSL_CONNECTION_COMPRESSION_MASK) <<
         SSL_CONNECTION_COMPRESSION_SHIFT;
 
-    // NSS 3.12.x doesn't have version macros for TLS 1.1 and 1.2 (because NSS
-    // doesn't support them yet), so we use 0x0302 and 0x0303 directly.
+    // NSS 3.14.x doesn't have a version macro for TLS 1.2 (because NSS didn't
+    // support it yet), so use 0x0303 directly.
     int version = SSL_CONNECTION_VERSION_UNKNOWN;
     if (channel_info.protocolVersion < SSL_LIBRARY_VERSION_3_0) {
       // All versions less than SSL_LIBRARY_VERSION_3_0 are treated as SSL
@@ -2444,7 +2428,7 @@
       version = SSL_CONNECTION_VERSION_SSL3;
     } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_3_1_TLS) {
       version = SSL_CONNECTION_VERSION_TLS1;
-    } else if (channel_info.protocolVersion == 0x0302) {
+    } else if (channel_info.protocolVersion == SSL_LIBRARY_VERSION_TLS_1_1) {
       version = SSL_CONNECTION_VERSION_TLS1_1;
     } else if (channel_info.protocolVersion == 0x0303) {
       version = SSL_CONNECTION_VERSION_TLS1_2;
@@ -2454,10 +2438,6 @@
         SSL_CONNECTION_VERSION_SHIFT;
   }
 
-  // SSL_HandshakeNegotiatedExtension was added in NSS 3.12.6.
-  // Since SSL_MAX_EXTENSIONS was added at the same time, we can test
-  // SSL_MAX_EXTENSIONS for the presence of SSL_HandshakeNegotiatedExtension.
-#if defined(SSL_MAX_EXTENSIONS)
   PRBool peer_supports_renego_ext;
   ok = SSL_HandshakeNegotiatedExtension(nss_fd_, ssl_renegotiation_info_xtn,
                                         &peer_supports_renego_ext);
@@ -2491,7 +2471,6 @@
                             peer_supports_renego_ext == PR_TRUE);
     }
   }
-#endif
 
   if (ssl_config_.version_fallback) {
     nss_handshake_state_.ssl_connection_status |=
@@ -2620,9 +2599,7 @@
   return rv;
 }
 
-int SSLClientSocketNSS::Core::DoGetDomainBoundCert(
-    const std::string& host,
-    const std::vector<uint8>& requested_cert_types) {
+int SSLClientSocketNSS::Core::DoGetDomainBoundCert(const std::string& host) {
   DCHECK(OnNetworkTaskRunner());
 
   if (detached_)
@@ -2632,8 +2609,6 @@
 
   int rv = server_bound_cert_service_->GetDomainBoundCert(
       host,
-      requested_cert_types,
-      &domain_bound_cert_type_,
       &domain_bound_private_key_,
       &domain_bound_cert_,
       base::Bind(&Core::OnGetDomainBoundCertComplete, base::Unretained(this)),
@@ -3168,25 +3143,18 @@
     SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE);
   }
 
-#ifdef SSL_ENABLE_SESSION_TICKETS
   // Support RFC 5077
   rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
   if (rv != SECSuccess) {
     LogFailedNSSFunction(
         net_log_, "SSL_OptionSet", "SSL_ENABLE_SESSION_TICKETS");
   }
-#else
-  #error "You need to install NSS-3.12 or later to build chromium"
-#endif
 
-#ifdef SSL_ENABLE_FALSE_START
   rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_FALSE_START,
                      ssl_config_.false_start_enabled);
   if (rv != SECSuccess)
     LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_ENABLE_FALSE_START");
-#endif
 
-#ifdef SSL_ENABLE_RENEGOTIATION
   // We allow servers to request renegotiation. Since we're a client,
   // prohibiting this is rather a waste of time. Only servers are in a
   // position to prevent renegotiation attacks.
@@ -3198,14 +3166,12 @@
     LogFailedNSSFunction(
         net_log_, "SSL_OptionSet", "SSL_ENABLE_RENEGOTIATION");
   }
-#endif  // SSL_ENABLE_RENEGOTIATION
 
-#ifdef SSL_CBC_RANDOM_IV
   rv = SSL_OptionSet(nss_fd_, SSL_CBC_RANDOM_IV, PR_TRUE);
   if (rv != SECSuccess)
     LogFailedNSSFunction(net_log_, "SSL_OptionSet", "SSL_CBC_RANDOM_IV");
-#endif
 
+// Added in NSS 3.15
 #ifdef SSL_ENABLE_OCSP_STAPLING
   if (IsOCSPStaplingSupported()) {
     rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_OCSP_STAPLING, PR_TRUE);
@@ -3216,6 +3182,7 @@
   }
 #endif
 
+// Chromium patch to libssl
 #ifdef SSL_ENABLE_CACHED_INFO
   rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_CACHED_INFO,
                      ssl_config_.cached_info_enabled);
diff --git a/net/spdy/spdy_credential_builder.cc b/net/spdy/spdy_credential_builder.cc
index 1742aff..79567b6 100644
--- a/net/spdy/spdy_credential_builder.cc
+++ b/net/spdy/spdy_credential_builder.cc
@@ -26,14 +26,10 @@
 
 // static
 int SpdyCredentialBuilder::Build(const std::string& tls_unique,
-                                 SSLClientCertType type,
                                  const std::string& key,
                                  const std::string& cert,
                                  size_t slot,
                                  SpdyCredential* credential) {
-  if (type != CLIENT_CERT_ECDSA_SIGN)
-    return ERR_BAD_SSL_CLIENT_AUTH_CERT;
-
   std::string secret = SpdyCredentialBuilder::GetCredentialSecret(tls_unique);
 
   // Extract the SubjectPublicKeyInfo from the certificate.
diff --git a/net/spdy/spdy_credential_builder.h b/net/spdy/spdy_credential_builder.h
index d74b600..3bdc0a1 100644
--- a/net/spdy/spdy_credential_builder.h
+++ b/net/spdy/spdy_credential_builder.h
@@ -8,7 +8,6 @@
 #include <string>
 
 #include "net/base/net_export.h"
-#include "net/ssl/ssl_client_cert_type.h"
 
 namespace net {
 
@@ -20,7 +19,6 @@
 class NET_EXPORT_PRIVATE SpdyCredentialBuilder {
  public:
   static int Build(const std::string& tls_unique,
-                   SSLClientCertType type,
                    const std::string& key,
                    const std::string& cert,
                    size_t slot,
diff --git a/net/spdy/spdy_credential_builder_unittest.cc b/net/spdy/spdy_credential_builder_unittest.cc
index 89332d5..bc67cc5 100644
--- a/net/spdy/spdy_credential_builder_unittest.cc
+++ b/net/spdy/spdy_credential_builder_unittest.cc
@@ -30,16 +30,12 @@
                                  sequenced_worker_pool));
 
   TestCompletionCallback callback;
-  std::vector<uint8> requested_cert_types;
-  requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
-  SSLClientCertType cert_type;
   ServerBoundCertService::RequestHandle request_handle;
   int rv = server_bound_cert_service->GetDomainBoundCert(
-      "www.google.com", requested_cert_types, &cert_type, key, cert,
+      "www.google.com", key, cert,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
 
   sequenced_worker_pool->Shutdown();
 }
@@ -53,13 +49,9 @@
   }
 
  protected:
-  int BuildWithType(SSLClientCertType type) {
-    return SpdyCredentialBuilder::Build(
-        MockClientSocket::kTlsUnique, type, key_, cert_, kSlot, &credential_);
-  }
-
   int Build() {
-    return BuildWithType(CLIENT_CERT_ECDSA_SIGN);
+    return SpdyCredentialBuilder::Build(
+        MockClientSocket::kTlsUnique, key_, cert_, kSlot, &credential_);
   }
 
   std::string GetCredentialSecret() {
@@ -89,35 +81,13 @@
 }
 
 #if defined(USE_OPENSSL)
-#define MAYBE_SucceedsWithECDSACert DISABLED_SucceedsWithECDSACert
+#define MAYBE_Succeeds DISABLED_Succeeds
 #else
-#define MAYBE_SucceedsWithECDSACert SucceedsWithECDSACert
+#define MAYBE_Succeeds Succeeds
 #endif
 
-TEST_F(SpdyCredentialBuilderTest, MAYBE_SucceedsWithECDSACert) {
-  EXPECT_EQ(OK, BuildWithType(CLIENT_CERT_ECDSA_SIGN));
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_FailsWithRSACert DISABLED_FailsWithRSACert
-#else
-#define MAYBE_FailsWithRSACert FailsWithRSACert
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_FailsWithRSACert) {
-  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
-            BuildWithType(CLIENT_CERT_RSA_SIGN));
-}
-
-#if defined(USE_OPENSSL)
-#define MAYBE_FailsWithDSACert DISABLED_FailsWithDSACert
-#else
-#define MAYBE_FailsWithDSACert FailsWithDSACert
-#endif
-
-TEST_F(SpdyCredentialBuilderTest, MAYBE_FailsWithDSACert) {
-  EXPECT_EQ(ERR_BAD_SSL_CLIENT_AUTH_CERT,
-            BuildWithType(CLIENT_CERT_DSS_SIGN));
+TEST_F(SpdyCredentialBuilderTest, MAYBE_Succeeds) {
+  EXPECT_EQ(OK, Build());
 }
 
 #if defined(USE_OPENSSL)
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 04a8eca..55387cf 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -540,23 +540,18 @@
     std::string* cert,
     std::string* proof) {
   TestCompletionCallback callback;
-  std::vector<uint8> requested_cert_types;
-  requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
-  SSLClientCertType cert_type;
   std::string key;
   ServerBoundCertService::RequestHandle request_handle;
   int rv = server_bound_cert_service->GetDomainBoundCert(
-      host, requested_cert_types, &cert_type, &key, cert, callback.callback(),
+      host, &key, cert, callback.callback(),
       &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, rv);
   EXPECT_EQ(OK, callback.WaitForResult());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, cert_type);
 
   SpdyCredential credential;
   EXPECT_EQ(OK,
             SpdyCredentialBuilder::Build(
-                MockClientSocket::kTlsUnique, cert_type, key,
-                *cert, 2, &credential));
+                MockClientSocket::kTlsUnique, key, *cert, 2, &credential));
 
   ASSERT_FALSE(credential.certs.empty());
   cert->assign(credential.certs[0]);
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 8a730ce..db47549 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -793,7 +793,6 @@
 
 int SpdySession::CreateCredentialFrame(
     const std::string& origin,
-    SSLClientCertType type,
     const std::string& key,
     const std::string& cert,
     RequestPriority priority,
@@ -807,7 +806,7 @@
   std::string tls_unique;
   ssl_socket->GetTLSUniqueChannelBinding(&tls_unique);
   size_t slot = credential_state_.SetHasCredential(GURL(origin));
-  int rv = SpdyCredentialBuilder::Build(tls_unique, type, key, cert, slot,
+  int rv = SpdyCredentialBuilder::Build(tls_unique, key, cert, slot,
                                         &credential);
   DCHECK_NE(rv, ERR_IO_PENDING);
   if (rv != OK)
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index c6a22e6..819db11 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -35,7 +35,6 @@
 #include "net/spdy/spdy_session_pool.h"
 #include "net/spdy/spdy_stream.h"
 #include "net/spdy/spdy_write_queue.h"
-#include "net/ssl/ssl_client_cert_type.h"
 #include "net/ssl/ssl_config_service.h"
 #include "url/gurl.h"
 
@@ -299,7 +298,6 @@
   // |credential_frame| and returns OK. Returns the error (guaranteed
   // to not be ERR_IO_PENDING) otherwise.
   int CreateCredentialFrame(const std::string& origin,
-                            SSLClientCertType type,
                             const std::string& key,
                             const std::string& cert,
                             RequestPriority priority,
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index db085cf..18d20e8 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -108,7 +108,6 @@
       net_log_(net_log),
       send_bytes_(0),
       recv_bytes_(0),
-      domain_bound_cert_type_(CLIENT_CERT_INVALID_TYPE),
       just_completed_frame_type_(DATA),
       just_completed_frame_size_(0) {
   CHECK(type_ == SPDY_BIDIRECTIONAL_STREAM ||
@@ -741,11 +740,10 @@
   io_state_ = STATE_GET_DOMAIN_BOUND_CERT_COMPLETE;
   ServerBoundCertService* sbc_service = session_->GetServerBoundCertService();
   DCHECK(sbc_service != NULL);
-  std::vector<uint8> requested_cert_types;
-  requested_cert_types.push_back(CLIENT_CERT_ECDSA_SIGN);
   int rv = sbc_service->GetDomainBoundCert(
-      url.GetOrigin().host(), requested_cert_types,
-      &domain_bound_cert_type_, &domain_bound_private_key_, &domain_bound_cert_,
+      url.GetOrigin().host(),
+      &domain_bound_private_key_,
+      &domain_bound_cert_,
       base::Bind(&SpdyStream::OnGetDomainBoundCertComplete, GetWeakPtr()),
       &domain_bound_cert_request_handle_);
   return rv;
@@ -771,8 +769,11 @@
   origin.erase(origin.length() - 1);  // Trim trailing slash.
   scoped_ptr<SpdyFrame> frame;
   int rv = session_->CreateCredentialFrame(
-      origin, domain_bound_cert_type_, domain_bound_private_key_,
-      domain_bound_cert_, priority_, &frame);
+      origin,
+      domain_bound_private_key_,
+      domain_bound_cert_,
+      priority_,
+      &frame);
   if (rv != OK) {
     DCHECK_NE(rv, ERR_IO_PENDING);
     return rv;
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index 06209a1..4d18e3e 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -541,7 +541,6 @@
   // Data received before delegate is attached.
   ScopedVector<SpdyBuffer> pending_buffers_;
 
-  SSLClientCertType domain_bound_cert_type_;
   std::string domain_bound_private_key_;
   std::string domain_bound_cert_;
   ServerBoundCertService::RequestHandle domain_bound_cert_request_handle_;
diff --git a/net/ssl/default_server_bound_cert_store.cc b/net/ssl/default_server_bound_cert_store.cc
index b189661..6fb9180 100644
--- a/net/ssl/default_server_bound_cert_store.cc
+++ b/net/ssl/default_server_bound_cert_store.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "net/base/net_errors.h"
 
 namespace net {
 
@@ -60,16 +61,15 @@
 
 void DefaultServerBoundCertStore::GetServerBoundCertTask::Run(
     DefaultServerBoundCertStore* store) {
-  SSLClientCertType type = CLIENT_CERT_INVALID_TYPE;
   base::Time expiration_time;
   std::string private_key_result;
   std::string cert_result;
-  bool was_sync = store->GetServerBoundCert(
-      server_identifier_, &type, &expiration_time, &private_key_result,
+  int err = store->GetServerBoundCert(
+      server_identifier_, &expiration_time, &private_key_result,
       &cert_result, GetCertCallback());
-  DCHECK(was_sync);
+  DCHECK(err != ERR_IO_PENDING);
 
-  InvokeCallback(base::Bind(callback_, server_identifier_, type,
+  InvokeCallback(base::Bind(callback_, err, server_identifier_,
                             expiration_time, private_key_result, cert_result));
 }
 
@@ -79,7 +79,6 @@
     : public DefaultServerBoundCertStore::Task {
  public:
   SetServerBoundCertTask(const std::string& server_identifier,
-                         SSLClientCertType type,
                          base::Time creation_time,
                          base::Time expiration_time,
                          const std::string& private_key,
@@ -89,7 +88,6 @@
 
  private:
   std::string server_identifier_;
-  SSLClientCertType type_;
   base::Time creation_time_;
   base::Time expiration_time_;
   std::string private_key_;
@@ -98,13 +96,11 @@
 
 DefaultServerBoundCertStore::SetServerBoundCertTask::SetServerBoundCertTask(
     const std::string& server_identifier,
-    SSLClientCertType type,
     base::Time creation_time,
     base::Time expiration_time,
     const std::string& private_key,
     const std::string& cert)
     : server_identifier_(server_identifier),
-      type_(type),
       creation_time_(creation_time),
       expiration_time_(expiration_time),
       private_key_(private_key),
@@ -116,7 +112,7 @@
 
 void DefaultServerBoundCertStore::SetServerBoundCertTask::Run(
     DefaultServerBoundCertStore* store) {
-  store->SyncSetServerBoundCert(server_identifier_, type_, creation_time_,
+  store->SyncSetServerBoundCert(server_identifier_, creation_time_,
                                 expiration_time_, private_key_, cert_);
 }
 
@@ -236,9 +232,8 @@
       store_(store),
       weak_ptr_factory_(this) {}
 
-bool DefaultServerBoundCertStore::GetServerBoundCert(
+int DefaultServerBoundCertStore::GetServerBoundCert(
     const std::string& server_identifier,
-    SSLClientCertType* type,
     base::Time* expiration_time,
     std::string* private_key_result,
     std::string* cert_result,
@@ -249,34 +244,30 @@
   if (!loaded_) {
     EnqueueTask(scoped_ptr<Task>(
         new GetServerBoundCertTask(server_identifier, callback)));
-    return false;
+    return ERR_IO_PENDING;
   }
 
   ServerBoundCertMap::iterator it = server_bound_certs_.find(server_identifier);
 
-  if (it == server_bound_certs_.end()) {
-    *type = CLIENT_CERT_INVALID_TYPE;
-    return true;
-  }
+  if (it == server_bound_certs_.end())
+    return ERR_FILE_NOT_FOUND;
 
   ServerBoundCert* cert = it->second;
-  *type = cert->type();
   *expiration_time = cert->expiration_time();
   *private_key_result = cert->private_key();
   *cert_result = cert->cert();
 
-  return true;
+  return OK;
 }
 
 void DefaultServerBoundCertStore::SetServerBoundCert(
     const std::string& server_identifier,
-    SSLClientCertType type,
     base::Time creation_time,
     base::Time expiration_time,
     const std::string& private_key,
     const std::string& cert) {
   RunOrEnqueueTask(scoped_ptr<Task>(new SetServerBoundCertTask(
-      server_identifier, type, creation_time, expiration_time, private_key,
+      server_identifier, creation_time, expiration_time, private_key,
       cert)));
 }
 
@@ -377,7 +368,6 @@
 
 void DefaultServerBoundCertStore::SyncSetServerBoundCert(
     const std::string& server_identifier,
-    SSLClientCertType type,
     base::Time creation_time,
     base::Time expiration_time,
     const std::string& private_key,
@@ -389,7 +379,7 @@
   InternalInsertServerBoundCert(
       server_identifier,
       new ServerBoundCert(
-          server_identifier, type, creation_time, expiration_time, private_key,
+          server_identifier, creation_time, expiration_time, private_key,
           cert));
 }
 
diff --git a/net/ssl/default_server_bound_cert_store.h b/net/ssl/default_server_bound_cert_store.h
index 8ec6805..6128218 100644
--- a/net/ssl/default_server_bound_cert_store.h
+++ b/net/ssl/default_server_bound_cert_store.h
@@ -43,16 +43,14 @@
   virtual ~DefaultServerBoundCertStore();
 
   // ServerBoundCertStore implementation.
-  virtual bool GetServerBoundCert(
+  virtual int GetServerBoundCert(
       const std::string& server_identifier,
-      SSLClientCertType* type,
       base::Time* expiration_time,
       std::string* private_key_result,
       std::string* cert_result,
       const GetCertCallback& callback) OVERRIDE;
   virtual void SetServerBoundCert(
       const std::string& server_identifier,
-      SSLClientCertType type,
       base::Time creation_time,
       base::Time expiration_time,
       const std::string& private_key,
@@ -110,7 +108,6 @@
   // initialization is complete.
   void SyncSetServerBoundCert(
       const std::string& server_identifier,
-      SSLClientCertType type,
       base::Time creation_time,
       base::Time expiration_time,
       const std::string& private_key,
diff --git a/net/ssl/default_server_bound_cert_store_unittest.cc b/net/ssl/default_server_bound_cert_store_unittest.cc
index 8673916..c3f8452 100644
--- a/net/ssl/default_server_bound_cert_store_unittest.cc
+++ b/net/ssl/default_server_bound_cert_store_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "net/base/net_errors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
@@ -27,8 +28,8 @@
   ADD_FAILURE() << "Unexpected callback execution.";
 }
 
-void GetCertCallbackNotCalled(const std::string& server_identifier,
-                              SSLClientCertType type,
+void GetCertCallbackNotCalled(int err,
+                              const std::string& server_identifier,
                               base::Time expiration_time,
                               const std::string& private_key_result,
                               const std::string& cert_result) {
@@ -39,21 +40,21 @@
  public:
   AsyncGetCertHelper() : called_(false) {}
 
-  void Callback(const std::string& server_identifier,
-                SSLClientCertType type,
+  void Callback(int err,
+                const std::string& server_identifier,
                 base::Time expiration_time,
                 const std::string& private_key_result,
                 const std::string& cert_result) {
+    err_ = err;
     server_identifier_ = server_identifier;
-    type_ = type;
     expiration_time_ = expiration_time;
     private_key_ = private_key_result;
     cert_ = cert_result;
     called_ = true;
   }
 
+  int err_;
   std::string server_identifier_;
-  SSLClientCertType type_;
   base::Time expiration_time_;
   std::string private_key_;
   std::string cert_;
@@ -127,14 +128,12 @@
   persistent_store->AddServerBoundCert(
       DefaultServerBoundCertStore::ServerBoundCert(
           "google.com",
-          CLIENT_CERT_RSA_SIGN,
           base::Time(),
           base::Time(),
           "a", "b"));
   persistent_store->AddServerBoundCert(
       DefaultServerBoundCertStore::ServerBoundCert(
           "verisign.com",
-          CLIENT_CERT_ECDSA_SIGN,
           base::Time(),
           base::Time(),
           "c", "d"));
@@ -145,7 +144,6 @@
   EXPECT_EQ(0, store.GetCertCount());
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "e", "f");
@@ -154,7 +152,6 @@
   EXPECT_EQ(2, store.GetCertCount());
   store.SetServerBoundCert(
       "twitter.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "g", "h");
@@ -166,32 +163,28 @@
 TEST(DefaultServerBoundCertStoreTest, TestSettingAndGetting) {
   // No persistent store, all calls will be synchronous.
   DefaultServerBoundCertStore store(NULL);
-  SSLClientCertType type;
   base::Time expiration_time;
   std::string private_key, cert;
   EXPECT_EQ(0, store.GetCertCount());
-  EXPECT_TRUE(store.GetServerBoundCert("verisign.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_INVALID_TYPE, type);
+  EXPECT_EQ(ERR_FILE_NOT_FOUND,
+            store.GetServerBoundCert("verisign.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
   EXPECT_TRUE(private_key.empty());
   EXPECT_TRUE(cert.empty());
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time::FromInternalValue(123),
       base::Time::FromInternalValue(456),
       "i", "j");
-  EXPECT_TRUE(store.GetServerBoundCert("verisign.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_RSA_SIGN, type);
+  EXPECT_EQ(OK,
+            store.GetServerBoundCert("verisign.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
   EXPECT_EQ(456, expiration_time.ToInternalValue());
   EXPECT_EQ("i", private_key);
   EXPECT_EQ("j", cert);
@@ -201,19 +194,16 @@
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   DefaultServerBoundCertStore store(persistent_store.get());
 
-  SSLClientCertType type;
   base::Time expiration_time;
   std::string private_key, cert;
   EXPECT_EQ(0, store.GetCertCount());
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time::FromInternalValue(123),
       base::Time::FromInternalValue(1234),
       "a", "b");
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_ECDSA_SIGN,
       base::Time::FromInternalValue(456),
       base::Time::FromInternalValue(4567),
       "c", "d");
@@ -221,13 +211,12 @@
   // Wait for load & queued set tasks.
   base::MessageLoop::current()->RunUntilIdle();
   EXPECT_EQ(1, store.GetCertCount());
-  EXPECT_TRUE(store.GetServerBoundCert("verisign.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type);
+  EXPECT_EQ(OK,
+            store.GetServerBoundCert("verisign.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
   EXPECT_EQ(4567, expiration_time.ToInternalValue());
   EXPECT_EQ("c", private_key);
   EXPECT_EQ("d", cert);
@@ -237,29 +226,31 @@
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time::FromInternalValue(123),
       base::Time::FromInternalValue(1234),
       "a", "b"));
 
   DefaultServerBoundCertStore store(persistent_store.get());
   AsyncGetCertHelper helper;
-  SSLClientCertType type;
   base::Time expiration_time;
   std::string private_key;
   std::string cert = "not set";
   EXPECT_EQ(0, store.GetCertCount());
-  EXPECT_FALSE(store.GetServerBoundCert(
-      "verisign.com", &type, &expiration_time, &private_key, &cert,
-      base::Bind(&AsyncGetCertHelper::Callback, base::Unretained(&helper))));
+  EXPECT_EQ(ERR_IO_PENDING,
+            store.GetServerBoundCert("verisign.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&AsyncGetCertHelper::Callback,
+                                                base::Unretained(&helper))));
 
   // Wait for load & queued get tasks.
   base::MessageLoop::current()->RunUntilIdle();
   EXPECT_EQ(1, store.GetCertCount());
   EXPECT_EQ("not set", cert);
   EXPECT_TRUE(helper.called_);
+  EXPECT_EQ(OK, helper.err_);
   EXPECT_EQ("verisign.com", helper.server_identifier_);
-  EXPECT_EQ(CLIENT_CERT_RSA_SIGN, helper.type_);
   EXPECT_EQ(1234, helper.expiration_time_.ToInternalValue());
   EXPECT_EQ("a", helper.private_key_);
   EXPECT_EQ("b", helper.cert_);
@@ -271,19 +262,16 @@
 
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b");
   store.SetServerBoundCert(
       "google.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d");
   store.SetServerBoundCert(
       "harvard.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "e", "f");
@@ -301,13 +289,11 @@
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b"));
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "google.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d"));
@@ -333,13 +319,11 @@
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   DefaultServerBoundCertStore store(persistent_store.get());
 
-  SSLClientCertType type;
   base::Time expiration_time;
   std::string private_key, cert;
   EXPECT_EQ(0, store.GetCertCount());
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b");
@@ -348,7 +332,6 @@
 
   store.SetServerBoundCert(
       "google.com",
-      CLIENT_CERT_ECDSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d");
@@ -359,45 +342,40 @@
                               base::Bind(&CallCounter, &delete_finished));
   ASSERT_EQ(1, delete_finished);
   EXPECT_EQ(1, store.GetCertCount());
-  EXPECT_TRUE(store.GetServerBoundCert("verisign.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_INVALID_TYPE, type);
-  EXPECT_TRUE(store.GetServerBoundCert("google.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type);
+  EXPECT_EQ(ERR_FILE_NOT_FOUND,
+            store.GetServerBoundCert("verisign.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
+  EXPECT_EQ(OK,
+            store.GetServerBoundCert("google.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
   int delete2_finished = 0;
   store.DeleteServerBoundCert("google.com",
                               base::Bind(&CallCounter, &delete2_finished));
   ASSERT_EQ(1, delete2_finished);
   EXPECT_EQ(0, store.GetCertCount());
-  EXPECT_TRUE(store.GetServerBoundCert("google.com",
-                                       &type,
-                                       &expiration_time,
-                                       &private_key,
-                                       &cert,
-                                       base::Bind(&GetCertCallbackNotCalled)));
-  EXPECT_EQ(CLIENT_CERT_INVALID_TYPE, type);
+  EXPECT_EQ(ERR_FILE_NOT_FOUND,
+            store.GetServerBoundCert("google.com",
+                                     &expiration_time,
+                                     &private_key,
+                                     &cert,
+                                     base::Bind(&GetCertCallbackNotCalled)));
 }
 
 TEST(DefaultServerBoundCertStoreTest, TestAsyncDelete) {
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "a.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time::FromInternalValue(1),
       base::Time::FromInternalValue(2),
       "a", "b"));
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "b.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time::FromInternalValue(3),
       base::Time::FromInternalValue(4),
       "c", "d"));
@@ -408,17 +386,20 @@
 
   AsyncGetCertHelper a_helper;
   AsyncGetCertHelper b_helper;
-  SSLClientCertType type;
   base::Time expiration_time;
   std::string private_key;
   std::string cert = "not set";
   EXPECT_EQ(0, store.GetCertCount());
-  EXPECT_FALSE(store.GetServerBoundCert(
-      "a.com", &type, &expiration_time, &private_key, &cert,
-      base::Bind(&AsyncGetCertHelper::Callback, base::Unretained(&a_helper))));
-  EXPECT_FALSE(store.GetServerBoundCert(
-      "b.com", &type, &expiration_time, &private_key, &cert,
-      base::Bind(&AsyncGetCertHelper::Callback, base::Unretained(&b_helper))));
+  EXPECT_EQ(ERR_IO_PENDING,
+      store.GetServerBoundCert(
+          "a.com", &expiration_time, &private_key, &cert,
+          base::Bind(&AsyncGetCertHelper::Callback,
+                     base::Unretained(&a_helper))));
+  EXPECT_EQ(ERR_IO_PENDING,
+      store.GetServerBoundCert(
+          "b.com", &expiration_time, &private_key, &cert,
+          base::Bind(&AsyncGetCertHelper::Callback,
+                     base::Unretained(&b_helper))));
 
   EXPECT_EQ(0, delete_finished);
   EXPECT_FALSE(a_helper.called_);
@@ -429,14 +410,14 @@
   EXPECT_EQ(1, store.GetCertCount());
   EXPECT_EQ("not set", cert);
   EXPECT_TRUE(a_helper.called_);
+  EXPECT_EQ(ERR_FILE_NOT_FOUND, a_helper.err_);
   EXPECT_EQ("a.com", a_helper.server_identifier_);
-  EXPECT_EQ(CLIENT_CERT_INVALID_TYPE, a_helper.type_);
   EXPECT_EQ(0, a_helper.expiration_time_.ToInternalValue());
   EXPECT_EQ("", a_helper.private_key_);
   EXPECT_EQ("", a_helper.cert_);
   EXPECT_TRUE(b_helper.called_);
+  EXPECT_EQ(OK, b_helper.err_);
   EXPECT_EQ("b.com", b_helper.server_identifier_);
-  EXPECT_EQ(CLIENT_CERT_RSA_SIGN, b_helper.type_);
   EXPECT_EQ(4, b_helper.expiration_time_.ToInternalValue());
   EXPECT_EQ("c", b_helper.private_key_);
   EXPECT_EQ("d", b_helper.cert_);
@@ -449,25 +430,21 @@
   EXPECT_EQ(0, store.GetCertCount());
   store.SetServerBoundCert(
       "verisign.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b");
   store.SetServerBoundCert(
       "google.com",
-      CLIENT_CERT_ECDSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d");
   store.SetServerBoundCert(
       "harvard.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "e", "f");
   store.SetServerBoundCert(
       "mit.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "g", "h");
@@ -486,13 +463,11 @@
 
   store.SetServerBoundCert(
       "preexisting.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b");
   store.SetServerBoundCert(
       "both.com",
-      CLIENT_CERT_ECDSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d");
@@ -503,14 +478,12 @@
   ServerBoundCertStore::ServerBoundCertList source_certs;
   source_certs.push_back(ServerBoundCertStore::ServerBoundCert(
       "both.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       // Key differs from above to test that existing entries are overwritten.
       "e", "f"));
   source_certs.push_back(ServerBoundCertStore::ServerBoundCert(
       "copied.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "g", "h"));
@@ -538,13 +511,11 @@
   scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore);
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "preexisting.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "a", "b"));
   persistent_store->AddServerBoundCert(ServerBoundCertStore::ServerBoundCert(
       "both.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "c", "d"));
@@ -553,14 +524,12 @@
   ServerBoundCertStore::ServerBoundCertList source_certs;
   source_certs.push_back(ServerBoundCertStore::ServerBoundCert(
       "both.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       // Key differs from above to test that existing entries are overwritten.
       "e", "f"));
   source_certs.push_back(ServerBoundCertStore::ServerBoundCert(
       "copied.com",
-      CLIENT_CERT_RSA_SIGN,
       base::Time(),
       base::Time(),
       "g", "h"));
diff --git a/net/ssl/server_bound_cert_service.cc b/net/ssl/server_bound_cert_service.cc
index 3740469..4bc82ed 100644
--- a/net/ssl/server_bound_cert_service.cc
+++ b/net/ssl/server_bound_cert_service.cc
@@ -42,15 +42,6 @@
 // while.
 const int kSystemTimeValidityBufferInDays = 90;
 
-bool IsSupportedCertType(uint8 type) {
-  switch(type) {
-    case CLIENT_CERT_ECDSA_SIGN:
-      return true;
-    default:
-      return false;
-  }
-}
-
 // Used by the GetDomainBoundCertResult histogram to record the final
 // outcome of each GetDomainBoundCert call.  Do not re-use values.
 enum GetCertResult {
@@ -96,7 +87,6 @@
 // unjoined thread, due to relying on a non-leaked LazyInstance
 scoped_ptr<ServerBoundCertStore::ServerBoundCert> GenerateCert(
     const std::string& server_identifier,
-    SSLClientCertType type,
     uint32 serial_number,
     int* error) {
   scoped_ptr<ServerBoundCertStore::ServerBoundCert> result;
@@ -107,34 +97,25 @@
       not_valid_before + base::TimeDelta::FromDays(kValidityPeriodInDays);
   std::string der_cert;
   std::vector<uint8> private_key_info;
-  switch (type) {
-    case CLIENT_CERT_ECDSA_SIGN: {
-      scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create());
-      if (!key.get()) {
-        DLOG(ERROR) << "Unable to create key pair for client";
-        *error = ERR_KEY_GENERATION_FAILED;
-        return result.Pass();
-      }
-      if (!x509_util::CreateDomainBoundCertEC(key.get(), server_identifier,
-                                              serial_number, not_valid_before,
-                                              not_valid_after, &der_cert)) {
-        DLOG(ERROR) << "Unable to create x509 cert for client";
-        *error = ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
-        return result.Pass();
-      }
+  scoped_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create());
+  if (!key.get()) {
+    DLOG(ERROR) << "Unable to create key pair for client";
+    *error = ERR_KEY_GENERATION_FAILED;
+    return result.Pass();
+  }
+  if (!x509_util::CreateDomainBoundCertEC(key.get(), server_identifier,
+                                          serial_number, not_valid_before,
+                                          not_valid_after, &der_cert)) {
+    DLOG(ERROR) << "Unable to create x509 cert for client";
+    *error = ERR_ORIGIN_BOUND_CERT_GENERATION_FAILED;
+    return result.Pass();
+  }
 
-      if (!key->ExportEncryptedPrivateKey(ServerBoundCertService::kEPKIPassword,
-                                          1, &private_key_info)) {
-        DLOG(ERROR) << "Unable to export private key";
-        *error = ERR_PRIVATE_KEY_EXPORT_FAILED;
-        return result.Pass();
-      }
-      break;
-    }
-    default:
-      NOTREACHED();
-      *error = ERR_INVALID_ARGUMENT;
-      return result.Pass();
+  if (!key->ExportEncryptedPrivateKey(ServerBoundCertService::kEPKIPassword,
+                                      1, &private_key_info)) {
+    DLOG(ERROR) << "Unable to export private key";
+    *error = ERR_PRIVATE_KEY_EXPORT_FAILED;
+    return result.Pass();
   }
 
   // TODO(rkn): Perhaps ExportPrivateKey should be changed to output a
@@ -142,7 +123,10 @@
   std::string key_out(private_key_info.begin(), private_key_info.end());
 
   result.reset(new ServerBoundCertStore::ServerBoundCert(
-      server_identifier, type, not_valid_before, not_valid_after, key_out,
+      server_identifier,
+      not_valid_before,
+      not_valid_after,
+      key_out,
       der_cert));
   UMA_HISTOGRAM_CUSTOM_TIMES("DomainBoundCerts.GenerateCertTime",
                              base::TimeTicks::Now() - start,
@@ -160,12 +144,10 @@
  public:
   ServerBoundCertServiceRequest(base::TimeTicks request_start,
                                 const CompletionCallback& callback,
-                                SSLClientCertType* type,
                                 std::string* private_key,
                                 std::string* cert)
       : request_start_(request_start),
         callback_(callback),
-        type_(type),
         private_key_(private_key),
         cert_(cert) {
   }
@@ -174,7 +156,6 @@
   void Cancel() {
     RecordGetDomainBoundCertResult(ASYNC_CANCELLED);
     callback_.Reset();
-    type_ = NULL;
     private_key_ = NULL;
     cert_ = NULL;
   }
@@ -182,7 +163,6 @@
   // Copies the contents of |private_key| and |cert| to the caller's output
   // arguments and calls the callback.
   void Post(int error,
-            SSLClientCertType type,
             const std::string& private_key,
             const std::string& cert) {
     switch (error) {
@@ -214,7 +194,6 @@
         break;
     }
     if (!callback_.is_null()) {
-      *type_ = type;
       *private_key_ = private_key;
       *cert_ = cert;
       callback_.Run(error);
@@ -227,7 +206,6 @@
  private:
   base::TimeTicks request_start_;
   CompletionCallback callback_;
-  SSLClientCertType* type_;
   std::string* private_key_;
   std::string* cert_;
 };
@@ -244,10 +222,8 @@
 
   ServerBoundCertServiceWorker(
       const std::string& server_identifier,
-      SSLClientCertType type,
       const WorkerDoneCallback& callback)
       : server_identifier_(server_identifier),
-        type_(type),
         serial_number_(base::RandInt(0, std::numeric_limits<int>::max())),
         origin_loop_(base::MessageLoopProxy::current()),
         callback_(callback) {
@@ -269,9 +245,8 @@
     // Runs on a worker thread.
     int error = ERR_FAILED;
     scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert =
-        GenerateCert(server_identifier_, type_, serial_number_, &error);
-    DVLOG(1) << "GenerateCert " << server_identifier_ << " " << type_
-             << " returned " << error;
+        GenerateCert(server_identifier_, serial_number_, &error);
+    DVLOG(1) << "GenerateCert " << server_identifier_ << " returned " << error;
 #if defined(USE_NSS)
     // Detach the thread from NSPR.
     // Calling NSS functions attaches the thread to NSPR, which stores
@@ -288,7 +263,6 @@
   }
 
   const std::string server_identifier_;
-  const SSLClientCertType type_;
   // Note that serial_number_ must be initialized on a non-worker thread
   // (see documentation for GenerateCert).
   uint32 serial_number_;
@@ -303,31 +277,25 @@
 // origin message loop.
 class ServerBoundCertServiceJob {
  public:
-  ServerBoundCertServiceJob(SSLClientCertType type)
-      : type_(type) {
-  }
+  ServerBoundCertServiceJob() { }
 
   ~ServerBoundCertServiceJob() {
     if (!requests_.empty())
       DeleteAllCanceled();
   }
 
-  SSLClientCertType type() const { return type_; }
-
   void AddRequest(ServerBoundCertServiceRequest* request) {
     requests_.push_back(request);
   }
 
   void HandleResult(int error,
-                    SSLClientCertType type,
                     const std::string& private_key,
                     const std::string& cert) {
-    PostAll(error, type, private_key, cert);
+    PostAll(error, private_key, cert);
   }
 
  private:
   void PostAll(int error,
-               SSLClientCertType type,
                const std::string& private_key,
                const std::string& cert) {
     std::vector<ServerBoundCertServiceRequest*> requests;
@@ -335,7 +303,7 @@
 
     for (std::vector<ServerBoundCertServiceRequest*>::iterator
          i = requests.begin(); i != requests.end(); i++) {
-      (*i)->Post(error, type, private_key, cert);
+      (*i)->Post(error, private_key, cert);
       // Post() causes the ServerBoundCertServiceRequest to delete itself.
     }
   }
@@ -352,7 +320,6 @@
   }
 
   std::vector<ServerBoundCertServiceRequest*> requests_;
-  SSLClientCertType type_;
 };
 
 // static
@@ -399,7 +366,8 @@
       weak_ptr_factory_(this),
       requests_(0),
       cert_store_hits_(0),
-      inflight_joins_(0) {
+      inflight_joins_(0),
+      workers_created_(0) {
   base::Time start = base::Time::Now();
   base::Time end = start + base::TimeDelta::FromDays(
       kValidityPeriodInDays + kSystemTimeValidityBufferInDays);
@@ -422,20 +390,15 @@
 
 int ServerBoundCertService::GetDomainBoundCert(
     const std::string& host,
-    const std::vector<uint8>& requested_types,
-    SSLClientCertType* type,
     std::string* private_key,
     std::string* cert,
     const CompletionCallback& callback,
     RequestHandle* out_req) {
-  DVLOG(1) << __FUNCTION__ << " " << host << " "
-           << (requested_types.empty() ? -1 : requested_types[0])
-           << (requested_types.size() > 1 ? "..." : "");
+  DVLOG(1) << __FUNCTION__ << " " << host;
   DCHECK(CalledOnValidThread());
   base::TimeTicks request_start = base::TimeTicks::Now();
 
-  if (callback.is_null() || !private_key || !cert || host.empty() ||
-      requested_types.empty()) {
+  if (callback.is_null() || !private_key || !cert || host.empty()) {
     RecordGetDomainBoundCertResult(INVALID_ARGUMENT);
     return ERR_INVALID_ARGUMENT;
   }
@@ -446,19 +409,6 @@
     return ERR_INVALID_ARGUMENT;
   }
 
-  SSLClientCertType preferred_type = CLIENT_CERT_INVALID_TYPE;
-  for (size_t i = 0; i < requested_types.size(); ++i) {
-    if (IsSupportedCertType(requested_types[i])) {
-      preferred_type = static_cast<SSLClientCertType>(requested_types[i]);
-      break;
-    }
-  }
-  if (preferred_type == CLIENT_CERT_INVALID_TYPE) {
-    RecordGetDomainBoundCertResult(UNSUPPORTED_TYPE);
-    // None of the requested types are supported.
-    return ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED;
-  }
-
   requests_++;
 
   // See if an identical request is currently in flight.
@@ -469,26 +419,13 @@
     // An identical request is in flight already. We'll just attach our
     // callback.
     job = j->second;
-    // Check that the job is for an acceptable type of cert.
-    if (std::find(requested_types.begin(), requested_types.end(), job->type())
-        == requested_types.end()) {
-      DVLOG(1) << "Found inflight job of wrong type " << job->type()
-               << " for " << domain;
-      // If we get here, the server is asking for different types of certs in
-      // short succession.  This probably means the server is broken or
-      // misconfigured.  Since we only store one type of cert per domain, we
-      // are unable to handle this well.  Just return an error and let the first
-      // job finish.
-      RecordGetDomainBoundCertResult(TYPE_MISMATCH);
-      return ERR_ORIGIN_BOUND_CERT_GENERATION_TYPE_MISMATCH;
-    }
     inflight_joins_++;
 
     ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
         request_start,
         base::Bind(&RequestHandle::OnRequestComplete,
                    base::Unretained(out_req)),
-        type, private_key, cert);
+        private_key, cert);
     job->AddRequest(request);
     out_req->RequestStarted(this, request, callback);
     return ERR_IO_PENDING;
@@ -498,30 +435,30 @@
   // domain. Note that |expiration_time| is ignored, and expired certs are
   // considered valid.
   base::Time expiration_time;
-  if (server_bound_cert_store_->GetServerBoundCert(
-          domain,
-          type,
-          &expiration_time /* ignored */,
-          private_key,
-          cert,
-          base::Bind(&ServerBoundCertService::GotServerBoundCert,
-                     weak_ptr_factory_.GetWeakPtr()))) {
-    if (IsSupportedCertType(*type)) {
-      // Sync lookup found a valid cert.
-      DVLOG(1) << "Cert store had valid cert for " << domain
-               << " of type " << *type;
-      cert_store_hits_++;
-      RecordGetDomainBoundCertResult(SYNC_SUCCESS);
-      base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
-      UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
-      RecordGetCertTime(request_time);
-      return OK;
-    }
+  int err = server_bound_cert_store_->GetServerBoundCert(
+      domain,
+      &expiration_time  /* ignored */,
+      private_key,
+      cert,
+      base::Bind(&ServerBoundCertService::GotServerBoundCert,
+                 weak_ptr_factory_.GetWeakPtr()));
 
+  if (err == OK) {
+    // Sync lookup found a valid cert.
+    DVLOG(1) << "Cert store had valid cert for " << domain;
+    cert_store_hits_++;
+    RecordGetDomainBoundCertResult(SYNC_SUCCESS);
+    base::TimeDelta request_time = base::TimeTicks::Now() - request_start;
+    UMA_HISTOGRAM_TIMES("DomainBoundCerts.GetCertTimeSync", request_time);
+    RecordGetCertTime(request_time);
+    return OK;
+  }
+
+  if (err == ERR_FILE_NOT_FOUND) {
     // Sync lookup did not find a valid cert.  Start generating a new one.
+    workers_created_++;
     ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
         domain,
-        preferred_type,
         base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
                    weak_ptr_factory_.GetWeakPtr()));
     if (!worker->Start(task_runner_)) {
@@ -532,23 +469,28 @@
     }
   }
 
-  // We are either waiting for async DB lookup, or waiting for cert generation.
-  // Create a job & request to track it.
-  job = new ServerBoundCertServiceJob(preferred_type);
-  inflight_[domain] = job;
+  if (err == ERR_IO_PENDING || err == ERR_FILE_NOT_FOUND) {
+    // We are either waiting for async DB lookup, or waiting for cert
+    // generation.  Create a job & request to track it.
+    job = new ServerBoundCertServiceJob();
+    inflight_[domain] = job;
 
-  ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
-      request_start,
-      base::Bind(&RequestHandle::OnRequestComplete, base::Unretained(out_req)),
-      type, private_key, cert);
-  job->AddRequest(request);
-  out_req->RequestStarted(this, request, callback);
-  return ERR_IO_PENDING;
+    ServerBoundCertServiceRequest* request = new ServerBoundCertServiceRequest(
+        request_start,
+        base::Bind(&RequestHandle::OnRequestComplete,
+                   base::Unretained(out_req)),
+        private_key, cert);
+    job->AddRequest(request);
+    out_req->RequestStarted(this, request, callback);
+    return ERR_IO_PENDING;
+  }
+
+  return err;
 }
 
 void ServerBoundCertService::GotServerBoundCert(
+    int err,
     const std::string& server_identifier,
-    SSLClientCertType type,
     base::Time expiration_time,
     const std::string& key,
     const std::string& cert) {
@@ -560,22 +502,19 @@
     NOTREACHED();
     return;
   }
-  ServerBoundCertServiceJob* job = j->second;
 
-  if (IsSupportedCertType(type)) {
+  if (err == OK) {
     // Async DB lookup found a valid cert.
-    DVLOG(1) << "Cert store had valid cert for " << server_identifier
-             << " of type " << type;
+    DVLOG(1) << "Cert store had valid cert for " << server_identifier;
     cert_store_hits_++;
     // ServerBoundCertServiceRequest::Post will do the histograms and stuff.
-    HandleResult(OK, server_identifier, type, key, cert);
+    HandleResult(OK, server_identifier, key, cert);
     return;
   }
-
   // Async lookup did not find a valid cert. Start generating a new one.
+  workers_created_++;
   ServerBoundCertServiceWorker* worker = new ServerBoundCertServiceWorker(
       server_identifier,
-      job->type(),
       base::Bind(&ServerBoundCertService::GeneratedServerBoundCert,
                  weak_ptr_factory_.GetWeakPtr()));
   if (!worker->Start(task_runner_)) {
@@ -583,7 +522,6 @@
     LOG(ERROR) << "ServerBoundCertServiceWorker couldn't be started.";
     HandleResult(ERR_INSUFFICIENT_RESOURCES,
                  server_identifier,
-                 CLIENT_CERT_INVALID_TYPE,
                  std::string(),
                  std::string());
     return;
@@ -609,24 +547,21 @@
     // TODO(mattm): we should just Pass() the cert object to
     // SetServerBoundCert().
     server_bound_cert_store_->SetServerBoundCert(
-        cert->server_identifier(), cert->type(), cert->creation_time(),
-        cert->expiration_time(), cert->private_key(), cert->cert());
+        cert->server_identifier(),
+        cert->creation_time(),
+        cert->expiration_time(),
+        cert->private_key(),
+        cert->cert());
 
-    HandleResult(error, server_identifier, cert->type(), cert->private_key(),
-                 cert->cert());
+    HandleResult(error, server_identifier, cert->private_key(), cert->cert());
   } else {
-    HandleResult(error,
-                 server_identifier,
-                 CLIENT_CERT_INVALID_TYPE,
-                 std::string(),
-                 std::string());
+    HandleResult(error, server_identifier, std::string(), std::string());
   }
 }
 
 void ServerBoundCertService::HandleResult(
     int error,
     const std::string& server_identifier,
-    SSLClientCertType type,
     const std::string& private_key,
     const std::string& cert) {
   DCHECK(CalledOnValidThread());
@@ -640,7 +575,7 @@
   ServerBoundCertServiceJob* job = j->second;
   inflight_.erase(j);
 
-  job->HandleResult(error, type, private_key, cert);
+  job->HandleResult(error, private_key, cert);
   delete job;
 }
 
diff --git a/net/ssl/server_bound_cert_service.h b/net/ssl/server_bound_cert_service.h
index dd50590..d931ec8 100644
--- a/net/ssl/server_bound_cert_service.h
+++ b/net/ssl/server_bound_cert_service.h
@@ -17,7 +17,6 @@
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
 #include "net/ssl/server_bound_cert_store.h"
-#include "net/ssl/ssl_client_cert_type.h"
 
 namespace base {
 class TaskRunner;
@@ -92,17 +91,13 @@
   // longer hold.
   bool IsSystemTimeValid() const { return is_system_time_valid_; }
 
-  // Fetches the domain bound cert for the specified host of the specified
-  // type if one exists and creates one otherwise. Returns OK if successful or
-  // an error code upon failure.
-  //
-  // |requested_types| is a list of the TLS ClientCertificateTypes the site will
-  // accept, ordered from most preferred to least preferred.  Types we don't
-  // support will be ignored. See ssl_client_cert_type.h.
+  // Fetches the domain bound cert for the specified host if one exists and
+  // creates one otherwise. Returns OK if successful or an error code upon
+  // failure.
   //
   // On successful completion, |private_key| stores a DER-encoded
-  // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate, and
-  // |type| specifies the type of certificate that was returned.
+  // PrivateKeyInfo struct, and |cert| stores a DER-encoded certificate.
+  // The PrivateKeyInfo is always an ECDSA private key.
   //
   // |callback| must not be null. ERR_IO_PENDING is returned if the operation
   // could not be completed immediately, in which case the result code will
@@ -113,8 +108,6 @@
   // ServerBoundCertService is destroyed.
   int GetDomainBoundCert(
       const std::string& host,
-      const std::vector<uint8>& requested_types,
-      SSLClientCertType* type,
       std::string* private_key,
       std::string* cert,
       const CompletionCallback& callback,
@@ -128,6 +121,7 @@
   uint64 requests() const { return requests_; }
   uint64 cert_store_hits() const { return cert_store_hits_; }
   uint64 inflight_joins() const { return inflight_joins_; }
+  uint64 workers_created() const { return workers_created_; }
 
  private:
   // Cancels the specified request. |req| is the handle stored by
@@ -135,8 +129,8 @@
   // callback will not be called.
   void CancelRequest(ServerBoundCertServiceRequest* req);
 
-  void GotServerBoundCert(const std::string& server_identifier,
-                          SSLClientCertType type,
+  void GotServerBoundCert(int err,
+                          const std::string& server_identifier,
                           base::Time expiration_time,
                           const std::string& key,
                           const std::string& cert);
@@ -146,7 +140,6 @@
       scoped_ptr<ServerBoundCertStore::ServerBoundCert> cert);
   void HandleResult(int error,
                     const std::string& server_identifier,
-                    SSLClientCertType type,
                     const std::string& private_key,
                     const std::string& cert);
 
@@ -161,6 +154,7 @@
   uint64 requests_;
   uint64 cert_store_hits_;
   uint64 inflight_joins_;
+  uint64 workers_created_;
 
   bool is_system_time_valid_;
 
diff --git a/net/ssl/server_bound_cert_service_unittest.cc b/net/ssl/server_bound_cert_service_unittest.cc
index 37a86a4..0063f49 100644
--- a/net/ssl/server_bound_cert_service_unittest.cc
+++ b/net/ssl/server_bound_cert_service_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
+#include "base/task_runner.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "crypto/ec_private_key.h"
 #include "net/base/net_errors.h"
@@ -47,6 +48,66 @@
   scoped_ptr<ServerBoundCertService> service_;
 };
 
+class MockServerBoundCertStoreWithAsyncGet
+    : public DefaultServerBoundCertStore {
+ public:
+  MockServerBoundCertStoreWithAsyncGet()
+      : DefaultServerBoundCertStore(NULL), cert_count_(0) {}
+
+  virtual int GetServerBoundCert(const std::string& server_identifier,
+                                 base::Time* expiration_time,
+                                 std::string* private_key_result,
+                                 std::string* cert_result,
+                                 const GetCertCallback& callback) OVERRIDE;
+
+  virtual void SetServerBoundCert(const std::string& server_identifier,
+                                  base::Time creation_time,
+                                  base::Time expiration_time,
+                                  const std::string& private_key,
+                                  const std::string& cert) OVERRIDE {
+    cert_count_ = 1;
+  }
+
+  virtual int GetCertCount() OVERRIDE { return cert_count_; }
+
+  void CallGetServerBoundCertCallbackWithResult(int err,
+                                                base::Time expiration_time,
+                                                const std::string& private_key,
+                                                const std::string& cert);
+
+ private:
+  GetCertCallback callback_;
+  std::string server_identifier_;
+  int cert_count_;
+};
+
+int MockServerBoundCertStoreWithAsyncGet::GetServerBoundCert(
+    const std::string& server_identifier,
+    base::Time* expiration_time,
+    std::string* private_key_result,
+    std::string* cert_result,
+    const GetCertCallback& callback) {
+  server_identifier_ = server_identifier;
+  callback_ = callback;
+  // Reset the cert count, it'll get incremented in either SetServerBoundCert or
+  // CallGetServerBoundCertCallbackWithResult.
+  cert_count_ = 0;
+  // Do nothing else: the results to be provided will be specified through
+  // CallGetServerBoundCertCallbackWithResult.
+  return ERR_IO_PENDING;
+}
+
+void
+MockServerBoundCertStoreWithAsyncGet::CallGetServerBoundCertCallbackWithResult(
+    int err,
+    base::Time expiration_time,
+    const std::string& private_key,
+    const std::string& cert) {
+  if (err == OK)
+    cert_count_ = 1;
+  callback_.Run(err, server_identifier_, expiration_time, private_key, cert);
+}
+
 TEST_F(ServerBoundCertServiceTest, GetDomainForHost) {
   EXPECT_EQ("google.com",
             ServerBoundCertService::GetDomainForHost("google.com"));
@@ -73,38 +134,32 @@
   std::string host("encrypted.google.com");
 
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
 
   // Asynchronous completion.
-  SSLClientCertType type1;
   std::string private_key_info1, der_cert1;
   EXPECT_EQ(0, service_->cert_count());
   error = service_->GetDomainBoundCert(
-      host, types, &type1, &private_key_info1, &der_cert1,
+      host, &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
   error = callback.WaitForResult();
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
   EXPECT_FALSE(private_key_info1.empty());
   EXPECT_FALSE(der_cert1.empty());
   EXPECT_FALSE(request_handle.is_active());
 
   // Synchronous completion.
-  SSLClientCertType type2;
   std::string private_key_info2, der_cert2;
   error = service_->GetDomainBoundCert(
-      host, types, &type2, &private_key_info2, &der_cert2,
+      host, &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_FALSE(request_handle.is_active());
   EXPECT_EQ(OK, error);
   EXPECT_EQ(1, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
   EXPECT_EQ(private_key_info1, private_key_info2);
   EXPECT_EQ(der_cert1, der_cert2);
 
@@ -113,97 +168,16 @@
   EXPECT_EQ(0u, service_->inflight_joins());
 }
 
-TEST_F(ServerBoundCertServiceTest, UnsupportedTypes) {
-  std::string host("encrypted.google.com");
-
-  int error;
-  std::vector<uint8> types;
-  TestCompletionCallback callback;
-  ServerBoundCertService::RequestHandle request_handle;
-
-  // Empty requested_types.
-  SSLClientCertType type1;
-  std::string private_key_info1, der_cert1;
-  error = service_->GetDomainBoundCert(
-      host, types, &type1, &private_key_info1, &der_cert1,
-      callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_INVALID_ARGUMENT, error);
-  EXPECT_FALSE(request_handle.is_active());
-
-  // No supported types in requested_types.
-  types.push_back(CLIENT_CERT_RSA_SIGN);
-  types.push_back(2);
-  types.push_back(3);
-  error = service_->GetDomainBoundCert(
-      host, types, &type1, &private_key_info1, &der_cert1,
-      callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED, error);
-  EXPECT_FALSE(request_handle.is_active());
-
-  // Supported types after unsupported ones in requested_types.
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
-  // Asynchronous completion.
-  EXPECT_EQ(0, service_->cert_count());
-  error = service_->GetDomainBoundCert(
-      host, types, &type1, &private_key_info1, &der_cert1,
-      callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_IO_PENDING, error);
-  EXPECT_TRUE(request_handle.is_active());
-  error = callback.WaitForResult();
-  EXPECT_EQ(OK, error);
-  EXPECT_EQ(1, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
-  EXPECT_FALSE(private_key_info1.empty());
-  EXPECT_FALSE(der_cert1.empty());
-
-  // Now that the cert is created, doing requests for unsupported types
-  // shouldn't affect the created cert.
-  // Empty requested_types.
-  types.clear();
-  SSLClientCertType type2;
-  std::string private_key_info2, der_cert2;
-  error = service_->GetDomainBoundCert(
-      host, types, &type2, &private_key_info2, &der_cert2,
-      callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_INVALID_ARGUMENT, error);
-  EXPECT_FALSE(request_handle.is_active());
-
-  // No supported types in requested_types.
-  types.push_back(CLIENT_CERT_RSA_SIGN);
-  types.push_back(2);
-  types.push_back(3);
-  error = service_->GetDomainBoundCert(
-      host, types, &type2, &private_key_info2, &der_cert2,
-      callback.callback(), &request_handle);
-  EXPECT_EQ(ERR_CLIENT_AUTH_CERT_TYPE_UNSUPPORTED, error);
-  EXPECT_FALSE(request_handle.is_active());
-
-  // If we request EC, the cert we created before should still be there.
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
-  error = service_->GetDomainBoundCert(
-      host, types, &type2, &private_key_info2, &der_cert2,
-      callback.callback(), &request_handle);
-  EXPECT_FALSE(request_handle.is_active());
-  EXPECT_EQ(OK, error);
-  EXPECT_EQ(1, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
-  EXPECT_EQ(private_key_info1, private_key_info2);
-  EXPECT_EQ(der_cert1, der_cert2);
-}
-
 TEST_F(ServerBoundCertServiceTest, StoreCerts) {
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
 
   std::string host1("encrypted.google.com");
-  SSLClientCertType type1;
   std::string private_key_info1, der_cert1;
   EXPECT_EQ(0, service_->cert_count());
   error = service_->GetDomainBoundCert(
-      host1, types, &type1, &private_key_info1, &der_cert1,
+      host1, &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -212,10 +186,9 @@
   EXPECT_EQ(1, service_->cert_count());
 
   std::string host2("www.verisign.com");
-  SSLClientCertType type2;
   std::string private_key_info2, der_cert2;
   error = service_->GetDomainBoundCert(
-      host2, types, &type2, &private_key_info2, &der_cert2,
+      host2, &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -224,10 +197,9 @@
   EXPECT_EQ(2, service_->cert_count());
 
   std::string host3("www.twitter.com");
-  SSLClientCertType type3;
   std::string private_key_info3, der_cert3;
   error = service_->GetDomainBoundCert(
-      host3, types, &type3, &private_key_info3, &der_cert3,
+      host3, &private_key_info3, &der_cert3,
       callback.callback(), &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -241,38 +213,29 @@
   EXPECT_NE(der_cert1, der_cert3);
   EXPECT_NE(private_key_info2, private_key_info3);
   EXPECT_NE(der_cert2, der_cert3);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type3);
 }
 
 // Tests an inflight join.
 TEST_F(ServerBoundCertServiceTest, InflightJoin) {
   std::string host("encrypted.google.com");
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
 
-  SSLClientCertType type1;
   std::string private_key_info1, der_cert1;
   TestCompletionCallback callback1;
   ServerBoundCertService::RequestHandle request_handle1;
 
-  SSLClientCertType type2;
   std::string private_key_info2, der_cert2;
   TestCompletionCallback callback2;
   ServerBoundCertService::RequestHandle request_handle2;
 
   error = service_->GetDomainBoundCert(
-      host, types, &type1, &private_key_info1, &der_cert1,
+      host, &private_key_info1, &der_cert1,
       callback1.callback(), &request_handle1);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle1.is_active());
-  // If we request RSA and EC in the 2nd request, should still join with the
-  // original request.
-  types.insert(types.begin(), CLIENT_CERT_RSA_SIGN);
+  // Should join with the original request.
   error = service_->GetDomainBoundCert(
-      host, types, &type2, &private_key_info2, &der_cert2,
+      host, &private_key_info2, &der_cert2,
       callback2.callback(), &request_handle2);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle2.is_active());
@@ -282,8 +245,6 @@
   error = callback2.WaitForResult();
   EXPECT_EQ(OK, error);
 
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
   EXPECT_EQ(2u, service_->requests());
   EXPECT_EQ(0u, service_->cert_store_hits());
   EXPECT_EQ(1u, service_->inflight_joins());
@@ -291,16 +252,13 @@
 
 TEST_F(ServerBoundCertServiceTest, ExtractValuesFromBytesEC) {
   std::string host("encrypted.google.com");
-  SSLClientCertType type;
   std::string private_key_info, der_cert;
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
 
   error = service_->GetDomainBoundCert(
-      host, types, &type, &private_key_info, &der_cert, callback.callback(),
+      host, &private_key_info, &der_cert, callback.callback(),
       &request_handle);
   EXPECT_EQ(ERR_IO_PENDING, error);
   EXPECT_TRUE(request_handle.is_active());
@@ -329,16 +287,11 @@
 // Tests that the callback of a canceled request is never made.
 TEST_F(ServerBoundCertServiceTest, CancelRequest) {
   std::string host("encrypted.google.com");
-  SSLClientCertType type;
   std::string private_key_info, der_cert;
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   ServerBoundCertService::RequestHandle request_handle;
 
   error = service_->GetDomainBoundCert(host,
-                                      types,
-                                      &type,
                                       &private_key_info,
                                       &der_cert,
                                       base::Bind(&FailTest),
@@ -362,17 +315,12 @@
 // Tests that destructing the RequestHandle cancels the request.
 TEST_F(ServerBoundCertServiceTest, CancelRequestByHandleDestruction) {
   std::string host("encrypted.google.com");
-  SSLClientCertType type;
   std::string private_key_info, der_cert;
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   {
     ServerBoundCertService::RequestHandle request_handle;
 
     error = service_->GetDomainBoundCert(host,
-                                         types,
-                                         &type,
                                          &private_key_info,
                                          &der_cert,
                                          base::Bind(&FailTest),
@@ -394,16 +342,11 @@
 
 TEST_F(ServerBoundCertServiceTest, DestructionWithPendingRequest) {
   std::string host("encrypted.google.com");
-  SSLClientCertType type;
   std::string private_key_info, der_cert;
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   ServerBoundCertService::RequestHandle request_handle;
 
   error = service_->GetDomainBoundCert(host,
-                                       types,
-                                       &type,
                                        &private_key_info,
                                        &der_cert,
                                        base::Bind(&FailTest),
@@ -438,16 +381,11 @@
 
   // Make a request that will force synchronous completion.
   std::string host("encrypted.google.com");
-  SSLClientCertType type;
   std::string private_key_info, der_cert;
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   ServerBoundCertService::RequestHandle request_handle;
 
   error = service_->GetDomainBoundCert(host,
-                                       types,
-                                       &type,
                                        &private_key_info,
                                        &der_cert,
                                        base::Bind(&FailTest),
@@ -460,30 +398,23 @@
 // Tests that simultaneous creation of different certs works.
 TEST_F(ServerBoundCertServiceTest, SimultaneousCreation) {
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
 
   std::string host1("encrypted.google.com");
-  SSLClientCertType type1;
   std::string private_key_info1, der_cert1;
   TestCompletionCallback callback1;
   ServerBoundCertService::RequestHandle request_handle1;
 
   std::string host2("foo.com");
-  SSLClientCertType type2;
   std::string private_key_info2, der_cert2;
   TestCompletionCallback callback2;
   ServerBoundCertService::RequestHandle request_handle2;
 
   std::string host3("bar.com");
-  SSLClientCertType type3;
   std::string private_key_info3, der_cert3;
   TestCompletionCallback callback3;
   ServerBoundCertService::RequestHandle request_handle3;
 
   error = service_->GetDomainBoundCert(host1,
-                                       types,
-                                       &type1,
                                        &private_key_info1,
                                        &der_cert1,
                                        callback1.callback(),
@@ -492,8 +423,6 @@
   EXPECT_TRUE(request_handle1.is_active());
 
   error = service_->GetDomainBoundCert(host2,
-                                       types,
-                                       &type2,
                                        &private_key_info2,
                                        &der_cert2,
                                        callback2.callback(),
@@ -502,8 +431,6 @@
   EXPECT_TRUE(request_handle2.is_active());
 
   error = service_->GetDomainBoundCert(host3,
-                                       types,
-                                       &type3,
                                        &private_key_info3,
                                        &der_cert3,
                                        callback3.callback(),
@@ -513,19 +440,16 @@
 
   error = callback1.WaitForResult();
   EXPECT_EQ(OK, error);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
   EXPECT_FALSE(private_key_info1.empty());
   EXPECT_FALSE(der_cert1.empty());
 
   error = callback2.WaitForResult();
   EXPECT_EQ(OK, error);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
   EXPECT_FALSE(private_key_info2.empty());
   EXPECT_FALSE(der_cert2.empty());
 
   error = callback3.WaitForResult();
   EXPECT_EQ(OK, error);
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type3);
   EXPECT_FALSE(private_key_info3.empty());
   EXPECT_FALSE(der_cert3.empty());
 
@@ -545,13 +469,11 @@
   ServerBoundCertStore* store = service_->GetCertStore();
   base::Time now = base::Time::Now();
   store->SetServerBoundCert("good",
-                            CLIENT_CERT_ECDSA_SIGN,
                             now,
                             now + base::TimeDelta::FromDays(1),
                             "a",
                             "b");
   store->SetServerBoundCert("expired",
-                            CLIENT_CERT_ECDSA_SIGN,
                             now - base::TimeDelta::FromDays(2),
                             now - base::TimeDelta::FromDays(1),
                             "c",
@@ -559,38 +481,99 @@
   EXPECT_EQ(2, service_->cert_count());
 
   int error;
-  std::vector<uint8> types;
-  types.push_back(CLIENT_CERT_ECDSA_SIGN);
   TestCompletionCallback callback;
   ServerBoundCertService::RequestHandle request_handle;
 
   // Cert is valid - synchronous completion.
-  SSLClientCertType type1;
   std::string private_key_info1, der_cert1;
   error = service_->GetDomainBoundCert(
-      "good", types, &type1, &private_key_info1, &der_cert1,
+      "good", &private_key_info1, &der_cert1,
       callback.callback(), &request_handle);
   EXPECT_EQ(OK, error);
   EXPECT_FALSE(request_handle.is_active());
   EXPECT_EQ(2, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type1);
   EXPECT_STREQ("a", private_key_info1.c_str());
   EXPECT_STREQ("b", der_cert1.c_str());
 
   // Expired cert is valid as well - synchronous completion.
-  SSLClientCertType type2;
   std::string private_key_info2, der_cert2;
   error = service_->GetDomainBoundCert(
-      "expired", types, &type2, &private_key_info2, &der_cert2,
+      "expired", &private_key_info2, &der_cert2,
       callback.callback(), &request_handle);
   EXPECT_EQ(OK, error);
   EXPECT_FALSE(request_handle.is_active());
   EXPECT_EQ(2, service_->cert_count());
-  EXPECT_EQ(CLIENT_CERT_ECDSA_SIGN, type2);
   EXPECT_STREQ("c", private_key_info2.c_str());
   EXPECT_STREQ("d", der_cert2.c_str());
 }
 
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetNoCertsInStore) {
+  MockServerBoundCertStoreWithAsyncGet* mock_store =
+      new MockServerBoundCertStoreWithAsyncGet();
+  service_ = scoped_ptr<ServerBoundCertService>(
+      new ServerBoundCertService(mock_store, sequenced_worker_pool_));
+
+  std::string host("encrypted.google.com");
+
+  int error;
+  TestCompletionCallback callback;
+  ServerBoundCertService::RequestHandle request_handle;
+
+  // Asynchronous completion with no certs in the store.
+  std::string private_key_info, der_cert;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key_info, &der_cert, callback.callback(), &request_handle);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle.is_active());
+
+  mock_store->CallGetServerBoundCertCallbackWithResult(
+      ERR_FILE_NOT_FOUND, base::Time(), std::string(), std::string());
+
+  error = callback.WaitForResult();
+  EXPECT_EQ(OK, error);
+  EXPECT_EQ(1, service_->cert_count());
+  EXPECT_FALSE(private_key_info.empty());
+  EXPECT_FALSE(der_cert.empty());
+  EXPECT_FALSE(request_handle.is_active());
+}
+
+TEST_F(ServerBoundCertServiceTest, AsyncStoreGetOneCertInStore) {
+  MockServerBoundCertStoreWithAsyncGet* mock_store =
+      new MockServerBoundCertStoreWithAsyncGet();
+  service_ = scoped_ptr<ServerBoundCertService>(
+      new ServerBoundCertService(mock_store, sequenced_worker_pool_));
+
+  std::string host("encrypted.google.com");
+
+  int error;
+  TestCompletionCallback callback;
+  ServerBoundCertService::RequestHandle request_handle;
+
+  // Asynchronous completion with a cert in the store.
+  std::string private_key_info, der_cert;
+  EXPECT_EQ(0, service_->cert_count());
+  error = service_->GetDomainBoundCert(
+      host, &private_key_info, &der_cert, callback.callback(), &request_handle);
+  EXPECT_EQ(ERR_IO_PENDING, error);
+  EXPECT_TRUE(request_handle.is_active());
+
+  mock_store->CallGetServerBoundCertCallbackWithResult(
+      OK, base::Time(), "ab", "cd");
+
+  error = callback.WaitForResult();
+  EXPECT_EQ(OK, error);
+  EXPECT_EQ(1, service_->cert_count());
+  EXPECT_EQ(1u, service_->requests());
+  EXPECT_EQ(1u, service_->cert_store_hits());
+  // Because the cert was found in the store, no new workers should have been
+  // created.
+  EXPECT_EQ(0u, service_->workers_created());
+  EXPECT_STREQ("ab", private_key_info.c_str());
+  EXPECT_STREQ("cd", der_cert.c_str());
+  EXPECT_FALSE(request_handle.is_active());
+}
+
 #endif  // !defined(USE_OPENSSL)
 
 }  // namespace
diff --git a/net/ssl/server_bound_cert_store.cc b/net/ssl/server_bound_cert_store.cc
index d0d520d..e778362 100644
--- a/net/ssl/server_bound_cert_store.cc
+++ b/net/ssl/server_bound_cert_store.cc
@@ -6,19 +6,16 @@
 
 namespace net {
 
-ServerBoundCertStore::ServerBoundCert::ServerBoundCert()
-    : type_(CLIENT_CERT_INVALID_TYPE) {
+ServerBoundCertStore::ServerBoundCert::ServerBoundCert() {
 }
 
 ServerBoundCertStore::ServerBoundCert::ServerBoundCert(
     const std::string& server_identifier,
-    SSLClientCertType type,
     base::Time creation_time,
     base::Time expiration_time,
     const std::string& private_key,
     const std::string& cert)
     : server_identifier_(server_identifier),
-      type_(type),
       creation_time_(creation_time),
       expiration_time_(expiration_time),
       private_key_(private_key),
@@ -29,7 +26,7 @@
 void ServerBoundCertStore::InitializeFrom(const ServerBoundCertList& list) {
   for (ServerBoundCertList::const_iterator i = list.begin(); i != list.end();
       ++i) {
-    SetServerBoundCert(i->server_identifier(), i->type(), i->creation_time(),
+    SetServerBoundCert(i->server_identifier(), i->creation_time(),
                        i->expiration_time(), i->private_key(), i->cert());
   }
 }
diff --git a/net/ssl/server_bound_cert_store.h b/net/ssl/server_bound_cert_store.h
index ad0ecb0..0de0f3e 100644
--- a/net/ssl/server_bound_cert_store.h
+++ b/net/ssl/server_bound_cert_store.h
@@ -12,7 +12,6 @@
 #include "base/threading/non_thread_safe.h"
 #include "base/time/time.h"
 #include "net/base/net_export.h"
-#include "net/ssl/ssl_client_cert_type.h"
 
 namespace net {
 
@@ -27,12 +26,11 @@
     : NON_EXPORTED_BASE(public base::NonThreadSafe) {
  public:
   // The ServerBoundCert class contains a private key in addition to the server
-  // cert, and cert type.
+  // cert.
   class NET_EXPORT ServerBoundCert {
    public:
     ServerBoundCert();
     ServerBoundCert(const std::string& server_identifier,
-                    SSLClientCertType type,
                     base::Time creation_time,
                     base::Time expiration_time,
                     const std::string& private_key,
@@ -41,8 +39,6 @@
 
     // Server identifier.  For domain bound certs, for instance "verisign.com".
     const std::string& server_identifier() const { return server_identifier_; }
-    // TLS ClientCertificateType.
-    SSLClientCertType type() const { return type_; }
     // The time the certificate was created, also the start of the certificate
     // validity period.
     base::Time creation_time() const { return creation_time_; }
@@ -57,7 +53,6 @@
 
    private:
     std::string server_identifier_;
-    SSLClientCertType type_;
     base::Time creation_time_;
     base::Time expiration_time_;
     std::string private_key_;
@@ -67,8 +62,8 @@
   typedef std::list<ServerBoundCert> ServerBoundCertList;
 
   typedef base::Callback<void(
+      int,
       const std::string&,
-      SSLClientCertType,
       base::Time,
       const std::string&,
       const std::string&)> GetCertCallback;
@@ -77,14 +72,13 @@
   virtual ~ServerBoundCertStore() {}
 
   // GetServerBoundCert may return the result synchronously through the
-  // output parameters, in which case it will return true.  Otherwise it will
-  // return false and the callback will be called with the result
+  // output parameters, in which case it will return either OK if a cert is
+  // found in the store, or ERR_FILE_NOT_FOUND if none is found.  If the
+  // result cannot be returned synchronously, GetServerBoundCert will
+  // return ERR_IO_PENDING and the callback will be called with the result
   // asynchronously.
-  // In either case, the type will be CLIENT_CERT_INVALID_TYPE if no cert
-  // existed for the given |server_identifier|.
-  virtual bool GetServerBoundCert(
+  virtual int GetServerBoundCert(
       const std::string& server_identifier,
-      SSLClientCertType* type,
       base::Time* expiration_time,
       std::string* private_key_result,
       std::string* cert_result,
@@ -93,7 +87,6 @@
   // Adds a server bound cert and the corresponding private key to the store.
   virtual void SetServerBoundCert(
       const std::string& server_identifier,
-      SSLClientCertType type,
       base::Time creation_time,
       base::Time expiration_time,
       const std::string& private_key,
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index d183ca8..ae77651 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -75,10 +75,6 @@
     patches/cbc.patch
     https://code.google.com/p/chromium/issues/detail?id=172658#c12
 
-  * Define AES_256_KEY_LENGTH if the system blapit.h header doesn't define it.
-    Remove this patch when all system NSS packages are NSS 3.12.10 or later.
-    patches/aes256keylength.patch
-
   * Change ssl3_SuiteBOnly to always return PR_TRUE. The softoken in NSS
     versions older than 3.15 report an EC key size range of 112 bits to 571
     bits, even when it is compiled to support only the NIST P-256, P-384, and
diff --git a/net/third_party/nss/patches/aes256keylength.patch b/net/third_party/nss/patches/aes256keylength.patch
deleted file mode 100644
index 2fc2506..0000000
--- a/net/third_party/nss/patches/aes256keylength.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff -pu a/nss/lib/ssl/sslsnce.c b/nss/lib/ssl/sslsnce.c
---- a/nss/lib/ssl/sslsnce.c	2013-07-31 12:07:10.974699609 -0700
-+++ b/nss/lib/ssl/sslsnce.c	2013-07-31 14:12:33.185058439 -0700
-@@ -86,6 +86,11 @@
- #include "nspr.h"
- #include "sslmutex.h"
- 
-+/* AES_256_KEY_LENGTH was added to blapit.h in NSS 3.12.10. */
-+#ifndef AES_256_KEY_LENGTH
-+#define AES_256_KEY_LENGTH      32  /* bytes */
-+#endif
-+
- /*
- ** Format of a cache entry in the shared memory.
- */ 
diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh
index 86444a2..81192a4 100755
--- a/net/third_party/nss/patches/applypatches.sh
+++ b/net/third_party/nss/patches/applypatches.sh
@@ -38,8 +38,6 @@
 
 patch -p4 < $patches_dir/cbc.patch
 
-patch -p4 < $patches_dir/aes256keylength.patch
-
 patch -p4 < $patches_dir/suitebonly.patch
 
 patch -p4 < $patches_dir/secitemarray.patch
diff --git a/net/third_party/nss/ssl.gyp b/net/third_party/nss/ssl.gyp
index 49cfbd8..fc52673 100644
--- a/net/third_party/nss/ssl.gyp
+++ b/net/third_party/nss/ssl.gyp
@@ -68,7 +68,6 @@
         'ssl/win32err.c',
         'ssl/win32err.h',
         'ssl/bodge/secitem_array.c',
-        'ssl/bodge/secure_memcmp.c',
       ],
       'sources!': [
         'ssl/os2_err.c',
diff --git a/net/third_party/nss/ssl/bodge/secure_memcmp.c b/net/third_party/nss/ssl/bodge/secure_memcmp.c
deleted file mode 100644
index b18579c..0000000
--- a/net/third_party/nss/ssl/bodge/secure_memcmp.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Netscape security libraries.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1994-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-// This file exists to provide the secure memcmp function. This was added in
-// NSS 3.12.5.
-
-#include <stdlib.h>
-
-/*
- * Perform a constant-time compare of two memory regions. The return value is
- * 0 if the memory regions are equal and non-zero otherwise.
- */
-int
-NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
-{
-    const unsigned char *a = (const unsigned char*) ia;
-    const unsigned char *b = (const unsigned char*) ib;
-    size_t i;
-    unsigned char r = 0;
-
-    for (i = 0; i < n; ++i) {
-        r |= *a++ ^ *b++;
-    }
-
-    return r;
-}
diff --git a/net/third_party/nss/ssl/sslsnce.c b/net/third_party/nss/ssl/sslsnce.c
index 4b8825a..b0446ad 100644
--- a/net/third_party/nss/ssl/sslsnce.c
+++ b/net/third_party/nss/ssl/sslsnce.c
@@ -86,11 +86,6 @@
 #include "nspr.h"
 #include "sslmutex.h"
 
-/* AES_256_KEY_LENGTH was added to blapit.h in NSS 3.12.10. */
-#ifndef AES_256_KEY_LENGTH
-#define AES_256_KEY_LENGTH      32  /* bytes */
-#endif
-
 /*
 ** Format of a cache entry in the shared memory.
 */ 
diff --git a/net/tools/quic/quic_server.cc b/net/tools/quic/quic_server.cc
index 36a9d4b..d18525f 100644
--- a/net/tools/quic/quic_server.cc
+++ b/net/tools/quic/quic_server.cc
@@ -179,6 +179,19 @@
   }
 }
 
+/* static */
+void QuicServer::MaybeDispatchPacket(QuicDispatcher* dispatcher,
+                                     const QuicEncryptedPacket& packet,
+                                     const IPEndPoint& server_address,
+                                     const IPEndPoint& client_address) {
+  QuicGuid guid;
+  if (!QuicFramer::ReadGuidFromPacket(packet, &guid)) {
+    return;
+  }
+
+  dispatcher->ProcessPacket(server_address, client_address, guid, packet);
+}
+
 bool QuicServer::ReadAndDispatchSinglePacket(int fd,
                                              int port,
                                              QuicDispatcher* dispatcher,
@@ -199,19 +212,9 @@
   }
 
   QuicEncryptedPacket packet(buf, bytes_read, false);
-  QuicGuid guid;
-  QuicDataReader reader(packet.data(), packet.length());
-  uint8 public_flags;
-  if (!reader.ReadBytes(&public_flags, 1)) {
-    LOG(DFATAL) << "Unable to read public flags.";
-    return false;
-  }
-  if (!reader.ReadUInt64(&guid)) {
-    return true;  // We read, we just didn't like the results.
-  }
 
   IPEndPoint server_address(server_ip, port);
-  dispatcher->ProcessPacket(server_address, client_address, guid, packet);
+  MaybeDispatchPacket(dispatcher, packet, server_address, client_address);
 
   return true;
 }
diff --git a/net/tools/quic/quic_server.h b/net/tools/quic/quic_server.h
index 6399566..142d1d1 100644
--- a/net/tools/quic/quic_server.h
+++ b/net/tools/quic/quic_server.h
@@ -59,6 +59,14 @@
 
   virtual void OnShutdown(EpollServer* eps, int fd) OVERRIDE {}
 
+  // Dispatches the given packet only if it looks like a valid QUIC packet.
+  // TODO(rjshade): Return a status describing why a packet was dropped, and log
+  //                somehow.  Maybe expose as a varz.
+  static void MaybeDispatchPacket(QuicDispatcher* dispatcher,
+                                  const QuicEncryptedPacket& packet,
+                                  const IPEndPoint& server_address,
+                                  const IPEndPoint& client_address);
+
   bool overflow_supported() { return overflow_supported_; }
 
   int packets_dropped() { return packets_dropped_; }
diff --git a/net/tools/quic/quic_server_test.cc b/net/tools/quic/quic_server_test.cc
new file mode 100644
index 0000000..7d1d669
--- /dev/null
+++ b/net/tools/quic/quic_server_test.cc
@@ -0,0 +1,74 @@
+// 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 "net/tools/quic/quic_server.h"
+
+#include "net/quic/crypto/quic_random.h"
+#include "net/quic/quic_utils.h"
+#include "net/tools/quic/test_tools/mock_quic_dispatcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace net {
+namespace tools {
+namespace test {
+
+namespace {
+
+class QuicServerDispatchPacketTest : public ::testing::Test {
+ public:
+  QuicServerDispatchPacketTest()
+      : crypto_config_("blah", QuicRandom::GetInstance()),
+        dispatcher_(config_, crypto_config_, 1234, &eps_) {}
+
+
+  void MaybeDispatchPacket(const QuicEncryptedPacket& packet) {
+    IPEndPoint client_addr, server_addr;
+    QuicServer::MaybeDispatchPacket(&dispatcher_, packet,
+                                    client_addr, server_addr);
+  }
+
+ protected:
+  QuicConfig config_;
+  QuicCryptoServerConfig crypto_config_;
+  EpollServer eps_;
+  MockQuicDispatcher dispatcher_;
+};
+
+TEST_F(QuicServerDispatchPacketTest, DoNotDispatchPacketWithoutGUID) {
+  // Packet too short to be considered valid.
+  unsigned char invalid_packet[] = { 0x00 };
+  QuicEncryptedPacket encrypted_invalid_packet(
+      QuicUtils::AsChars(invalid_packet), arraysize(invalid_packet), false);
+
+  // We expect the invalid packet to be dropped, and ProcessPacket should never
+  // be called.
+  EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _)).Times(0);
+  MaybeDispatchPacket(encrypted_invalid_packet);
+}
+
+TEST_F(QuicServerDispatchPacketTest, DispatchValidPacket) {
+  unsigned char valid_packet[] = {
+    // public flags (8 byte guid)
+    0x3C,
+    // guid
+    0x10, 0x32, 0x54, 0x76,
+    0x98, 0xBA, 0xDC, 0xFE,
+    // packet sequence number
+    0xBC, 0x9A, 0x78, 0x56,
+    0x34, 0x12,
+    // private flags
+    0x00 };
+  QuicEncryptedPacket encrypted_valid_packet(QuicUtils::AsChars(valid_packet),
+                                             arraysize(valid_packet), false);
+
+  EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _, _)).Times(1);
+  MaybeDispatchPacket(encrypted_valid_packet);
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.cc b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
new file mode 100644
index 0000000..3a2b1d9
--- /dev/null
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.cc
@@ -0,0 +1,21 @@
+// 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 "net/tools/quic/test_tools/mock_quic_dispatcher.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+MockQuicDispatcher::MockQuicDispatcher(
+    const QuicConfig& config,
+    const QuicCryptoServerConfig& crypto_config,
+    QuicGuid guid,
+    EpollServer* eps)
+    : QuicDispatcher(config, crypto_config, guid, eps) { }
+MockQuicDispatcher::~MockQuicDispatcher() {}
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
diff --git a/net/tools/quic/test_tools/mock_quic_dispatcher.h b/net/tools/quic/test_tools/mock_quic_dispatcher.h
new file mode 100644
index 0000000..563ab0d
--- /dev/null
+++ b/net/tools/quic/test_tools/mock_quic_dispatcher.h
@@ -0,0 +1,38 @@
+// 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 NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
+#define NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
+
+#include "net/base/ip_endpoint.h"
+#include "net/quic/crypto/crypto_server_config.h"
+#include "net/quic/quic_config.h"
+#include "net/quic/quic_protocol.h"
+#include "net/tools/flip_server/epoll_server.h"
+#include "net/tools/quic/quic_dispatcher.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace net {
+namespace tools {
+namespace test {
+
+class MockQuicDispatcher : public QuicDispatcher {
+ public:
+  MockQuicDispatcher(const QuicConfig& config,
+                     const QuicCryptoServerConfig& crypto_config,
+                     QuicGuid guid,
+                     EpollServer* eps);
+  virtual ~MockQuicDispatcher();
+
+  MOCK_METHOD4(ProcessPacket, void(const IPEndPoint& server_address,
+                                   const IPEndPoint& client_address,
+                                   QuicGuid guid,
+                                   const QuicEncryptedPacket& packet));
+};
+
+}  // namespace test
+}  // namespace tools
+}  // namespace net
+
+#endif  // NET_TOOLS_QUIC_TEST_TOOLS_MOCK_QUIC_DISPATCHER_H_
diff --git a/ppapi/api/dev/ppb_text_input_dev.idl b/ppapi/api/dev/ppb_text_input_dev.idl
index 27704b0..7ea4901 100644
--- a/ppapi/api/dev/ppb_text_input_dev.idl
+++ b/ppapi/api/dev/ppb_text_input_dev.idl
@@ -17,25 +17,25 @@
  * text input.
  */
 [assert_size(4)]
-enum PP_TextInput_Type {
+enum PP_TextInput_Type_Dev {
   /**
    * Input caret is not in an editable mode, no input method shall be used.
    */
-  PP_TEXTINPUT_TYPE_NONE = 0,
+  PP_TEXTINPUT_TYPE_DEV_NONE = 0,
   /**
    * Input caret is in a normal editable mode, any input method can be used.
    */
-  PP_TEXTINPUT_TYPE_TEXT = 1,
+  PP_TEXTINPUT_TYPE_DEV_TEXT = 1,
   /**
    * Input caret is in a password box, an input method may be used only if
    * it's suitable for password input.
    */
-  PP_TEXTINPUT_TYPE_PASSWORD = 2,
-  PP_TEXTINPUT_TYPE_SEARCH = 3,
-  PP_TEXTINPUT_TYPE_EMAIL = 4,
-  PP_TEXTINPUT_TYPE_NUMBER = 5,
-  PP_TEXTINPUT_TYPE_TELEPHONE = 6,
-  PP_TEXTINPUT_TYPE_URL = 7
+  PP_TEXTINPUT_TYPE_DEV_PASSWORD = 2,
+  PP_TEXTINPUT_TYPE_DEV_SEARCH = 3,
+  PP_TEXTINPUT_TYPE_DEV_EMAIL = 4,
+  PP_TEXTINPUT_TYPE_DEV_NUMBER = 5,
+  PP_TEXTINPUT_TYPE_DEV_TELEPHONE = 6,
+  PP_TEXTINPUT_TYPE_DEV_URL = 7
 };
 
 /**
@@ -52,7 +52,7 @@
    * used for composing East Asian characters).
    */
   void SetTextInputType([in] PP_Instance instance,
-                        [in] PP_TextInput_Type type);
+                        [in] PP_TextInput_Type_Dev type);
 
   /**
    * Informs the browser about the coordinates of the text input caret and the
diff --git a/ppapi/api/private/ppb_nacl_private.idl b/ppapi/api/private/ppb_nacl_private.idl
index 1054723..bf2918b 100644
--- a/ppapi/api/private/ppb_nacl_private.idl
+++ b/ppapi/api/private/ppb_nacl_private.idl
@@ -122,13 +122,16 @@
                     [in] PP_CompletionCallback callback);
 
   /* Report to the browser that translation of the pexe for |instance|
-   * has finished. The browser may then store the translation in the
-   * cache. The renderer must first have called GetNexeFd for the same
-   * instance. (It is not guaranteed to, however; if there is an error
-   * or the file is too big for the cache, or the browser is in incognito
-   * mode, no notification will be delivered to the plugin.)
+   * has finished, or aborted with an error. If |success| is true, the
+   * browser may then store the translation in the cache. The renderer
+   * must first have called GetNexeFd for the same instance. (The browser is
+   * not guaranteed to store the nexe even if |success| is true; if there is
+   * an error on the browser side, or the file is too big for the cache, or
+   * the browser is in incognito mode, no notification will be delivered to
+   * the plugin.)
    */
-  void ReportTranslationFinished([in] PP_Instance instance);
+  void ReportTranslationFinished([in] PP_Instance instance,
+                                 [in] PP_Bool success);
 
   /* Return true if we are off the record.
    */
diff --git a/ppapi/c/dev/ppb_text_input_dev.h b/ppapi/c/dev/ppb_text_input_dev.h
index 8b7df44..516f20f 100644
--- a/ppapi/c/dev/ppb_text_input_dev.h
+++ b/ppapi/c/dev/ppb_text_input_dev.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From dev/ppb_text_input_dev.idl modified Thu Mar 28 10:54:47 2013. */
+/* From dev/ppb_text_input_dev.idl modified Tue Aug  6 10:37:25 2013. */
 
 #ifndef PPAPI_C_DEV_PPB_TEXT_INPUT_DEV_H_
 #define PPAPI_C_DEV_PPB_TEXT_INPUT_DEV_H_
@@ -37,23 +37,23 @@
   /**
    * Input caret is not in an editable mode, no input method shall be used.
    */
-  PP_TEXTINPUT_TYPE_NONE = 0,
+  PP_TEXTINPUT_TYPE_DEV_NONE = 0,
   /**
    * Input caret is in a normal editable mode, any input method can be used.
    */
-  PP_TEXTINPUT_TYPE_TEXT = 1,
+  PP_TEXTINPUT_TYPE_DEV_TEXT = 1,
   /**
    * Input caret is in a password box, an input method may be used only if
    * it's suitable for password input.
    */
-  PP_TEXTINPUT_TYPE_PASSWORD = 2,
-  PP_TEXTINPUT_TYPE_SEARCH = 3,
-  PP_TEXTINPUT_TYPE_EMAIL = 4,
-  PP_TEXTINPUT_TYPE_NUMBER = 5,
-  PP_TEXTINPUT_TYPE_TELEPHONE = 6,
-  PP_TEXTINPUT_TYPE_URL = 7
-} PP_TextInput_Type;
-PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TextInput_Type, 4);
+  PP_TEXTINPUT_TYPE_DEV_PASSWORD = 2,
+  PP_TEXTINPUT_TYPE_DEV_SEARCH = 3,
+  PP_TEXTINPUT_TYPE_DEV_EMAIL = 4,
+  PP_TEXTINPUT_TYPE_DEV_NUMBER = 5,
+  PP_TEXTINPUT_TYPE_DEV_TELEPHONE = 6,
+  PP_TEXTINPUT_TYPE_DEV_URL = 7
+} PP_TextInput_Type_Dev;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TextInput_Type_Dev, 4);
 /**
  * @}
  */
@@ -75,7 +75,7 @@
    * keyboards in touch screen based devices, or input method editors often
    * used for composing East Asian characters).
    */
-  void (*SetTextInputType)(PP_Instance instance, PP_TextInput_Type type);
+  void (*SetTextInputType)(PP_Instance instance, PP_TextInput_Type_Dev type);
   /**
    * Informs the browser about the coordinates of the text input caret and the
    * bounding box of the text input area. Typical use of this information in
@@ -128,7 +128,7 @@
 typedef struct PPB_TextInput_Dev_0_2 PPB_TextInput_Dev;
 
 struct PPB_TextInput_Dev_0_1 {
-  void (*SetTextInputType)(PP_Instance instance, PP_TextInput_Type type);
+  void (*SetTextInputType)(PP_Instance instance, PP_TextInput_Type_Dev type);
   void (*UpdateCaretPosition)(PP_Instance instance,
                               const struct PP_Rect* caret,
                               const struct PP_Rect* bounding_box);
diff --git a/ppapi/c/ppb_text_input_controller.h b/ppapi/c/ppb_text_input_controller.h
index bc7cdb8..43b88ac 100644
--- a/ppapi/c/ppb_text_input_controller.h
+++ b/ppapi/c/ppb_text_input_controller.h
@@ -3,12 +3,11 @@
  * found in the LICENSE file.
  */
 
-/* From ppb_text_input_controller.idl modified Sat Jul 27 00:04:53 2013. */
+/* From ppb_text_input_controller.idl modified Thu Aug  1 09:30:48 2013. */
 
 #ifndef PPAPI_C_PPB_TEXT_INPUT_CONTROLLER_H_
 #define PPAPI_C_PPB_TEXT_INPUT_CONTROLLER_H_
 
-#include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_instance.h"
 #include "ppapi/c/pp_macros.h"
@@ -28,6 +27,39 @@
 
 
 /**
+ * @addtogroup Enums
+ * @{
+ */
+/**
+ * PP_TextInput_Type is used to indicate the status of a plugin in regard to
+ * text input.
+ */
+typedef enum {
+  /**
+   * Input caret is not in an editable mode, no input method shall be used.
+   */
+  PP_TEXTINPUT_TYPE_NONE = 0,
+  /**
+   * Input caret is in a normal editable mode, any input method can be used.
+   */
+  PP_TEXTINPUT_TYPE_TEXT = 1,
+  /**
+   * Input caret is in a password box, an input method may be used only if
+   * it's suitable for password input.
+   */
+  PP_TEXTINPUT_TYPE_PASSWORD = 2,
+  PP_TEXTINPUT_TYPE_SEARCH = 3,
+  PP_TEXTINPUT_TYPE_EMAIL = 4,
+  PP_TEXTINPUT_TYPE_NUMBER = 5,
+  PP_TEXTINPUT_TYPE_TELEPHONE = 6,
+  PP_TEXTINPUT_TYPE_URL = 7
+} PP_TextInput_Type;
+PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TextInput_Type, 4);
+/**
+ * @}
+ */
+
+/**
  * @addtogroup Interfaces
  * @{
  */
diff --git a/ppapi/c/private/ppb_nacl_private.h b/ppapi/c/private/ppb_nacl_private.h
index d89ed5b..8be2829 100644
--- a/ppapi/c/private/ppb_nacl_private.h
+++ b/ppapi/c/private/ppb_nacl_private.h
@@ -3,7 +3,7 @@
  * found in the LICENSE file.
  */
 
-/* From private/ppb_nacl_private.idl modified Mon Jul 29 16:44:58 2013. */
+/* From private/ppb_nacl_private.idl modified Tue Aug  6 11:51:26 2013. */
 
 #ifndef PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
 #define PPAPI_C_PRIVATE_PPB_NACL_PRIVATE_H_
@@ -141,13 +141,15 @@
                        PP_FileHandle* nexe_handle,
                        struct PP_CompletionCallback callback);
   /* Report to the browser that translation of the pexe for |instance|
-   * has finished. The browser may then store the translation in the
-   * cache. The renderer must first have called GetNexeFd for the same
-   * instance. (It is not guaranteed to, however; if there is an error
-   * or the file is too big for the cache, or the browser is in incognito
-   * mode, no notification will be delivered to the plugin.)
+   * has finished, or aborted with an error. If |success| is true, the
+   * browser may then store the translation in the cache. The renderer
+   * must first have called GetNexeFd for the same instance. (The browser is
+   * not guaranteed to store the nexe even if |success| is true; if there is
+   * an error on the browser side, or the file is too big for the cache, or
+   * the browser is in incognito mode, no notification will be delivered to
+   * the plugin.)
    */
-  void (*ReportTranslationFinished)(PP_Instance instance);
+  void (*ReportTranslationFinished)(PP_Instance instance, PP_Bool success);
   /* Return true if we are off the record.
    */
   PP_Bool (*IsOffTheRecord)(void);
diff --git a/ppapi/cpp/dev/text_input_dev.cc b/ppapi/cpp/dev/text_input_dev.cc
index 657a0b3..b0fff8a 100644
--- a/ppapi/cpp/dev/text_input_dev.cc
+++ b/ppapi/cpp/dev/text_input_dev.cc
@@ -57,7 +57,7 @@
   UpdateSurroundingText(std::string(), 0, 0);
 }
 
-void TextInput_Dev::SetTextInputType(PP_TextInput_Type type) {
+void TextInput_Dev::SetTextInputType(PP_TextInput_Type_Dev type) {
   if (has_interface<PPB_TextInput_Dev_0_2>()) {
     get_interface<PPB_TextInput_Dev_0_2>()->SetTextInputType(
         instance_.pp_instance(), type);
diff --git a/ppapi/cpp/dev/text_input_dev.h b/ppapi/cpp/dev/text_input_dev.h
index ea75597..fca8728 100644
--- a/ppapi/cpp/dev/text_input_dev.h
+++ b/ppapi/cpp/dev/text_input_dev.h
@@ -45,7 +45,7 @@
 
   virtual void RequestSurroundingText(uint32_t desired_number_of_characters);
 
-  void SetTextInputType(PP_TextInput_Type type);
+  void SetTextInputType(PP_TextInput_Type_Dev type);
   void UpdateCaretPosition(const Rect& caret, const Rect& bounding_box);
   void CancelCompositionText();
   void SelectionChanged();
diff --git a/ppapi/native_client/src/trusted/plugin/plugin.cc b/ppapi/native_client/src/trusted/plugin/plugin.cc
index 701fe01..5cbb9d7 100644
--- a/ppapi/native_client/src/trusted/plugin/plugin.cc
+++ b/ppapi/native_client/src/trusted/plugin/plugin.cc
@@ -44,7 +44,6 @@
 #include "ppapi/cpp/dev/find_dev.h"
 #include "ppapi/cpp/dev/printing_dev.h"
 #include "ppapi/cpp/dev/selection_dev.h"
-#include "ppapi/cpp/dev/text_input_dev.h"
 #include "ppapi/cpp/dev/url_util_dev.h"
 #include "ppapi/cpp/dev/zoom_dev.h"
 #include "ppapi/cpp/image_data.h"
@@ -52,6 +51,7 @@
 #include "ppapi/cpp/module.h"
 #include "ppapi/cpp/mouse_lock.h"
 #include "ppapi/cpp/rect.h"
+#include "ppapi/cpp/text_input_controller.h"
 
 #include "ppapi/native_client/src/trusted/plugin/file_utils.h"
 #include "ppapi/native_client/src/trusted/plugin/json_manifest.h"
@@ -318,7 +318,7 @@
   // This makes discrepancy among platforms and therefore we should remove
   // this hack when IME API is made available.
   // The default for non-Mac platforms is still off-the-spot IME mode.
-  pp::TextInput_Dev(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE);
+  pp::TextInputController(this).SetTextInputType(PP_TEXTINPUT_TYPE_NONE);
 #endif
 
   // Remember the embed/object argn/argv pairs.
diff --git a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
index e5649f3..18b4fae 100644
--- a/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
+++ b/ppapi/native_client/src/trusted/plugin/pnacl_coordinator.cc
@@ -336,13 +336,14 @@
 void PnaclCoordinator::TranslateFinished(int32_t pp_error) {
   PLUGIN_PRINTF(("PnaclCoordinator::TranslateFinished (pp_error=%"
                  NACL_PRId32 ")\n", pp_error));
-  // Bail out if there was an earlier error (e.g., pexe load failure).
-  if (translate_finish_error_ != PP_OK) {
-    ExitWithError();
-    return;
-  }
-  // Bail out if there is an error from the translation thread.
-  if (pp_error != PP_OK) {
+  // Bail out if there was an earlier error (e.g., pexe load failure),
+  // or if there is an error from the translation thread.
+  if (translate_finish_error_ != PP_OK || pp_error != PP_OK) {
+    if (use_new_cache_) {
+      plugin_->nacl_interface()->ReportTranslationFinished(
+          plugin_->pp_instance(),
+          PP_FALSE);
+    }
     ExitWithError();
     return;
   }
@@ -395,7 +396,7 @@
     // Report to the browser that translation finished. The browser will take
     // care of caching.
     plugin_->nacl_interface()->ReportTranslationFinished(
-        plugin_->pp_instance());
+        plugin_->pp_instance(), PP_TRUE);
     NexeReadDidOpen(PP_OK);
     return;
   }
@@ -977,6 +978,11 @@
       ss << "PnaclCoordinator: pexe load failed (pp_error=" << pp_error << ").";
       error_info_.SetReport(ERROR_PNACL_PEXE_FETCH_OTHER, ss.str());
     }
+    if (use_new_cache_) {
+      plugin_->nacl_interface()->ReportTranslationFinished(
+          plugin_->pp_instance(),
+          PP_FALSE);
+    }
     translate_thread_->AbortSubprocesses();
   } else {
     // Compare download completion pct (100% now), to compile completion pct.
@@ -1051,6 +1057,11 @@
     ReportPpapiError(ERROR_PNACL_CREATE_TEMP,
                      pp_error,
                      "Failed to open scratch object file.");
+    if (use_new_cache_) {
+      plugin_->nacl_interface()->ReportTranslationFinished(
+          plugin_->pp_instance(),
+          PP_FALSE);
+    }
     return;
   }
   // Open the nexe file for connecting ld and sel_ldr.
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 9eabc69..aa68044 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -1978,8 +1978,6 @@
 
 /* Not generating wrapper methods for PPB_TextInput_Dev_0_2 */
 
-/* Not generating wrapper methods for PPB_TextInput_Dev_None */
-
 /* Not generating wrapper methods for PPB_Trace_Event_Dev_0_1 */
 
 /* Not generating wrapper methods for PPB_Trace_Event_Dev_0_2 */
@@ -2858,9 +2856,9 @@
   return iface->GetNexeFd(instance, pexe_url, abi_version, opt_level, last_modified, etag, is_hit, nexe_handle, *callback);
 }
 
-static void Pnacl_M13_PPB_NaCl_Private_ReportTranslationFinished(PP_Instance instance) {
+static void Pnacl_M13_PPB_NaCl_Private_ReportTranslationFinished(PP_Instance instance, PP_Bool success) {
   const struct PPB_NaCl_Private_1_0 *iface = Pnacl_WrapperInfo_PPB_NaCl_Private_1_0.real_iface;
-  iface->ReportTranslationFinished(instance);
+  iface->ReportTranslationFinished(instance, success);
 }
 
 static PP_Bool Pnacl_M13_PPB_NaCl_Private_IsOffTheRecord(void) {
@@ -4410,8 +4408,6 @@
 
 /* Not generating wrapper interface for PPB_TextInput_Dev_0_2 */
 
-/* Not generating wrapper interface for PPB_TextInput_Dev_None */
-
 /* Not generating wrapper interface for PPB_Trace_Event_Dev_0_1 */
 
 /* Not generating wrapper interface for PPB_Trace_Event_Dev_0_2 */
@@ -4672,7 +4668,7 @@
     .GetReadonlyPnaclFd = (PP_FileHandle (*)(const char* filename))&Pnacl_M13_PPB_NaCl_Private_GetReadonlyPnaclFd,
     .CreateTemporaryFile = (PP_FileHandle (*)(PP_Instance instance))&Pnacl_M13_PPB_NaCl_Private_CreateTemporaryFile,
     .GetNexeFd = (int32_t (*)(PP_Instance instance, const char* pexe_url, uint32_t abi_version, uint32_t opt_level, const char* last_modified, const char* etag, PP_Bool* is_hit, PP_FileHandle* nexe_handle, struct PP_CompletionCallback callback))&Pnacl_M13_PPB_NaCl_Private_GetNexeFd,
-    .ReportTranslationFinished = (void (*)(PP_Instance instance))&Pnacl_M13_PPB_NaCl_Private_ReportTranslationFinished,
+    .ReportTranslationFinished = (void (*)(PP_Instance instance, PP_Bool success))&Pnacl_M13_PPB_NaCl_Private_ReportTranslationFinished,
     .IsOffTheRecord = (PP_Bool (*)(void))&Pnacl_M13_PPB_NaCl_Private_IsOffTheRecord,
     .IsPnaclEnabled = (PP_Bool (*)(void))&Pnacl_M13_PPB_NaCl_Private_IsPnaclEnabled,
     .ReportNaClError = (PP_ExternalPluginResult (*)(PP_Instance instance, PP_NaClError message_id))&Pnacl_M13_PPB_NaCl_Private_ReportNaClError,
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 6f73e25..7ee568f 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -21,7 +21,6 @@
 #include "ipc/ipc_platform_file.h"
 #include "ppapi/c/dev/pp_video_capture_dev.h"
 #include "ppapi/c/dev/pp_video_dev.h"
-#include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/dev/ppb_truetype_font_dev.h"
 #include "ppapi/c/dev/ppb_url_util_dev.h"
 #include "ppapi/c/dev/ppp_printing_dev.h"
@@ -37,6 +36,7 @@
 #include "ppapi/c/ppb_audio_config.h"
 #include "ppapi/c/ppb_image_data.h"
 #include "ppapi/c/ppb_tcp_socket.h"
+#include "ppapi/c/ppb_text_input_controller.h"
 #include "ppapi/c/ppb_udp_socket.h"
 #include "ppapi/c/private/pp_content_decryptor.h"
 #include "ppapi/c/private/pp_private_font_charset.h"
diff --git a/ppapi/shared_impl/tracked_callback.h b/ppapi/shared_impl/tracked_callback.h
index 4917990..c4bf5cf 100644
--- a/ppapi/shared_impl/tracked_callback.h
+++ b/ppapi/shared_impl/tracked_callback.h
@@ -98,6 +98,11 @@
   // completion.
   bool aborted() const { return aborted_; }
 
+  // Returns true if this is a blocking callback.
+  bool is_blocking() {
+    return !callback_.func;
+  }
+
   // Determines if the given callback is pending. A callback is pending if it
   // has not completed and has not been aborted. When receiving a plugin call,
   // use this to detect if |callback| represents an operation in progress. When
@@ -113,10 +118,6 @@
   static bool IsScheduledToRun(const scoped_refptr<TrackedCallback>& callback);
 
  protected:
-  bool is_blocking() {
-    return !callback_.func;
-  }
-
   bool is_required() {
     return (callback_.func &&
             !(callback_.flags & PP_COMPLETIONCALLBACK_FLAG_OPTIONAL));
diff --git a/ppapi/thunk/ppb_instance_api.h b/ppapi/thunk/ppb_instance_api.h
index 3fa2edf..c1d024e 100644
--- a/ppapi/thunk/ppb_instance_api.h
+++ b/ppapi/thunk/ppb_instance_api.h
@@ -7,7 +7,6 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/dev/ppb_url_util_dev.h"
 #include "ppapi/c/pp_bool.h"
 #include "ppapi/c/pp_completion_callback.h"
@@ -17,6 +16,7 @@
 #include "ppapi/c/ppb_gamepad.h"
 #include "ppapi/c/ppb_instance.h"
 #include "ppapi/c/ppb_mouse_cursor.h"
+#include "ppapi/c/ppb_text_input_controller.h"
 #include "ppapi/c/private/pp_content_decryptor.h"
 #include "ppapi/c/private/ppb_instance_private.h"
 #include "ppapi/shared_impl/api_id.h"
diff --git a/ppapi/thunk/ppb_text_input_thunk.cc b/ppapi/thunk/ppb_text_input_thunk.cc
index 55fb4c9..a59146b 100644
--- a/ppapi/thunk/ppb_text_input_thunk.cc
+++ b/ppapi/thunk/ppb_text_input_thunk.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/basictypes.h"
+#include "ppapi/c/dev/ppb_text_input_dev.h"
 #include "ppapi/c/ppb_text_input_controller.h"
-
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_instance_api.h"
@@ -14,12 +15,40 @@
 
 namespace {
 
+COMPILE_ASSERT(int(PP_TEXTINPUT_TYPE_DEV_NONE) == int(PP_TEXTINPUT_TYPE_NONE),
+               mismatching_enums);
+COMPILE_ASSERT(int(PP_TEXTINPUT_TYPE_DEV_TEXT) == int(PP_TEXTINPUT_TYPE_TEXT),
+               mismatching_enums);
+COMPILE_ASSERT(
+    int(PP_TEXTINPUT_TYPE_DEV_PASSWORD) == int(PP_TEXTINPUT_TYPE_PASSWORD),
+    mismatching_enums);
+COMPILE_ASSERT(
+    int(PP_TEXTINPUT_TYPE_DEV_SEARCH) == int(PP_TEXTINPUT_TYPE_SEARCH),
+    mismatching_enums);
+COMPILE_ASSERT(int(PP_TEXTINPUT_TYPE_DEV_EMAIL) == int(PP_TEXTINPUT_TYPE_EMAIL),
+               mismatching_enums);
+COMPILE_ASSERT(
+    int(PP_TEXTINPUT_TYPE_DEV_NUMBER) == int(PP_TEXTINPUT_TYPE_NUMBER),
+    mismatching_enums);
+COMPILE_ASSERT(
+    int(PP_TEXTINPUT_TYPE_DEV_TELEPHONE) == int(PP_TEXTINPUT_TYPE_TELEPHONE),
+    mismatching_enums);
+COMPILE_ASSERT(int(PP_TEXTINPUT_TYPE_DEV_URL) == int(PP_TEXTINPUT_TYPE_URL),
+               mismatching_enums);
+
 void SetTextInputType(PP_Instance instance, PP_TextInput_Type type) {
   EnterInstance enter(instance);
   if (enter.succeeded())
     enter.functions()->SetTextInputType(instance, type);
 }
 
+void SetTextInputType_0_2(PP_Instance instance, PP_TextInput_Type_Dev type) {
+  EnterInstance enter(instance);
+  if (enter.succeeded())
+    enter.functions()->SetTextInputType(instance,
+                                        static_cast<PP_TextInput_Type>(type));
+}
+
 void UpdateCaretPosition_0_2(PP_Instance instance,
                          const PP_Rect* caret,
                          const PP_Rect* bounding_box) {
@@ -66,13 +95,13 @@
 }
 
 const PPB_TextInput_Dev_0_1 g_ppb_textinput_0_1_thunk = {
-  &SetTextInputType,
+  &SetTextInputType_0_2,
   &UpdateCaretPosition_0_2,
   &CancelCompositionText,
 };
 
 const PPB_TextInput_Dev_0_2 g_ppb_textinput_0_2_thunk = {
-  &SetTextInputType,
+  &SetTextInputType_0_2,
   &UpdateCaretPosition_0_2,
   &CancelCompositionText,
   &UpdateSurroundingText_0_2,
diff --git a/remoting/android/java/AndroidManifest.xml b/remoting/android/java/AndroidManifest.xml
index 51889e8..ff27b57 100644
--- a/remoting/android/java/AndroidManifest.xml
+++ b/remoting/android/java/AndroidManifest.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="org.chromium.chromoting"
-        android:versionCode="8"
-        android:versionName="0.08">
+        android:versionCode="9"
+        android:versionName="0.09">
     <uses-sdk android:minSdkVersion="14"
             android:targetSdkVersion="14"/>
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
diff --git a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
index 60c6b95..cfcbf49 100644
--- a/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
+++ b/remoting/android/java/src/org/chromium/chromoting/Chromoting.java
@@ -201,7 +201,7 @@
                     mAccount = new Account(accountName, accountType);
                     mToken = authToken;
                     getPreferences(MODE_PRIVATE).edit().putString("account_name", accountName).
-                            putString("account_type", accountType).commit();
+                            putString("account_type", accountType).apply();
                 }
 
                 // Send our HTTP request to the directory server.
diff --git a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
index 4806252..1e18f91 100644
--- a/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
+++ b/remoting/android/java/src/org/chromium/chromoting/DesktopView.java
@@ -266,7 +266,9 @@
     }
 
     /** Called when a mouse action is made. */
-    private void handleMouseMovement(float[] coordinates, int button, boolean pressed) {
+    private void handleMouseMovement(float x, float y, int button, boolean pressed) {
+        float[] coordinates = {x, y};
+
         // Coordinates are relative to the canvas, but we need image coordinates.
         Matrix canvasToImage = new Matrix();
         mTransform.invert(canvasToImage);
@@ -289,7 +291,8 @@
         boolean handled = mScroller.onTouchEvent(event) || mZoomer.onTouchEvent(event);
 
         if (event.getPointerCount() == 1) {
-            float[] coordinates = {event.getRawX(), event.getY()};
+            float x = event.getRawX();
+            float y = event.getY();
 
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
@@ -312,8 +315,7 @@
                     if (mMouseButton == BUTTON_UNDEFINED) {
                         // The user pressed and released without moving: do left click and release.
                         Log.i("mouse", "\tStarting and finishing left click");
-                        handleMouseMovement(new float[] {coordinates[0], coordinates[1]},
-                                BUTTON_LEFT, true);
+                        handleMouseMovement(x, y, BUTTON_LEFT, true);
                         mMouseButton = BUTTON_LEFT;
                         mMousePressed = false;
                     }
@@ -329,7 +331,7 @@
                 default:
                     return handled;
             }
-            handleMouseMovement(coordinates, mMouseButton, mMousePressed);
+            handleMouseMovement(x, y, mMouseButton, mMousePressed);
 
             return true;
         }
@@ -404,18 +406,19 @@
                 return;
             }
 
-            float[] coordinates = new float[] {e.getRawX(), e.getY()};
+            float x = e.getRawX();
+            float y = e.getY();
 
             Log.i("mouse", "Finger held down");
             if (mMousePressed) {
                 Log.i("mouse", "\tReleasing the currently-pressed button");
-                handleMouseMovement(coordinates, mMouseButton, false);
+                handleMouseMovement(x, y, mMouseButton, false);
             }
 
             Log.i("mouse", "\tStarting right click");
             mMouseButton = BUTTON_RIGHT;
             mMousePressed = true;
-            handleMouseMovement(coordinates, mMouseButton, mMousePressed);
+            handleMouseMovement(x, y, mMouseButton, mMousePressed);
         }
     }
 }
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
index f791d1e..039bcb9 100644
--- a/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
+++ b/remoting/android/java/src/org/chromium/chromoting/jni/JniInterface.java
@@ -9,13 +9,15 @@
 import android.app.ProgressDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.SharedPreferences;
 import android.graphics.Bitmap;
 import android.os.Looper;
 import android.text.InputType;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.View;
 import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
+import android.widget.CheckBox;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -92,7 +94,9 @@
         }
 
         sSuccessCallback = successCallback;
-        connectNative(username, authToken, hostJid, hostId, hostPubkey);
+        SharedPreferences prefs = sContext.getPreferences(Activity.MODE_PRIVATE);
+        connectNative(username, authToken, hostJid, hostId, hostPubkey,
+                prefs.getString(hostId + "_id", ""), prefs.getString(hostId + "_secret", ""));
         sConnected = true;
     }
 
@@ -113,8 +117,8 @@
     }
 
     /** Performs the native portion of the connection. */
-    private static native void connectNative(
-            String username, String authToken, String hostJid, String hostId, String hostPubkey);
+    private static native void connectNative(String username, String authToken, String hostJid,
+            String hostId, String hostPubkey, String pairId, String pairSecret);
 
     /** Performs the native portion of the cleanup. */
     private static native void disconnectNative();
@@ -188,10 +192,7 @@
         pinPrompt.setMessage(sContext.getString(R.string.pin_entry_message));
         pinPrompt.setIcon(android.R.drawable.ic_lock_lock);
 
-        final EditText pinEntry = new EditText(sContext);
-        pinEntry.setInputType(
-                InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-        pinEntry.setImeOptions(EditorInfo.IME_ACTION_DONE);
+        final View pinEntry = sContext.getLayoutInflater().inflate(R.layout.pin_dialog, null);
         pinPrompt.setView(pinEntry);
 
         pinPrompt.setPositiveButton(
@@ -199,7 +200,11 @@
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
                         Log.i("jniiface", "User provided a PIN code");
-                        authenticationResponse(String.valueOf(pinEntry.getText()));
+                        authenticationResponse(String.valueOf(
+                                ((TextView)
+                                        pinEntry.findViewById(R.id.pin_dialog_text)).getText()),
+                                ((CheckBox)
+                                        pinEntry.findViewById(R.id.pin_dialog_check)).isChecked());
                     }
                 });
 
@@ -217,7 +222,7 @@
 
         final AlertDialog pinDialog = pinPrompt.create();
 
-        pinEntry.setOnEditorActionListener(
+        ((TextView)pinEntry.findViewById(R.id.pin_dialog_text)).setOnEditorActionListener(
                 new TextView.OnEditorActionListener() {
                     @Override
                     public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
@@ -240,6 +245,16 @@
         pinDialog.show();
     }
 
+    /** Saves newly-received pairing credentials to permanent storage. */
+    private static void commitPairingCredentials(String host, byte[] id, byte[] secret) {
+        synchronized (sContext) {
+            sContext.getPreferences(Activity.MODE_PRIVATE).edit().
+                    putString(host + "_id", new String(id)).
+                    putString(host + "_secret", new String(secret)).
+                    apply();
+        }
+    }
+
     /**
      * Sets the redraw callback to the provided functor. Provide a value of null whenever the
      * window is no longer visible so that we don't continue to draw onto it.
@@ -304,7 +319,7 @@
     }
 
     /** Performs the native response to the user's PIN. */
-    private static native void authenticationResponse(String pin);
+    private static native void authenticationResponse(String pin, boolean createPair);
 
     /** Schedules a redraw on the native graphics thread. */
     private static native void scheduleRedrawNative();
diff --git a/remoting/base/resources_unittest.cc b/remoting/base/resources_unittest.cc
index d2b2d23..d1bc851 100644
--- a/remoting/base/resources_unittest.cc
+++ b/remoting/base/resources_unittest.cc
@@ -26,14 +26,9 @@
   bool resources_available_;
 };
 
-// TODO(alexeypa): Reenable the test once http://crbug.com/269143 is fixed.
-#if !defined(OS_CHROMEOS)
-#define MAYBE_ProductName ProductName
-#else
-#define MAYBE_ProductName DISABLED_ProductName
-#endif
-
-TEST_F(ResourcesTest, MAYBE_ProductName) {
+// TODO(alexeypa): Reenable the test once http://crbug.com/269143 (ChromeOS) and
+// http://crbug.com/268043 (MacOS) are fixed.
+TEST_F(ResourcesTest, DISABLED_ProductName) {
 #if defined(GOOGLE_CHROME_BUILD)
   std::string expected_product_name = "Chrome Remote Desktop";
 #else  // defined(GOOGLE_CHROME_BUILD)
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc
index b2790b8..3e11b2f 100644
--- a/remoting/client/jni/chromoting_jni_instance.cc
+++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -9,6 +9,7 @@
 #include "remoting/client/audio_player.h"
 #include "remoting/client/jni/android_keymap.h"
 #include "remoting/client/jni/chromoting_jni_runtime.h"
+#include "remoting/protocol/host_stub.h"
 #include "remoting/protocol/libjingle_transport_factory.h"
 
 // TODO(solb) Move into location shared with client plugin.
@@ -23,13 +24,18 @@
                                              const char* auth_token,
                                              const char* host_jid,
                                              const char* host_id,
-                                             const char* host_pubkey)
+                                             const char* host_pubkey,
+                                             const char* pairing_id,
+                                             const char* pairing_secret)
     : jni_runtime_(jni_runtime),
       username_(username),
       auth_token_(auth_token),
       host_jid_(host_jid),
       host_id_(host_id),
-      host_pubkey_(host_pubkey) {
+      host_pubkey_(host_pubkey),
+      pairing_id_(pairing_id),
+      pairing_secret_(pairing_secret),
+      create_pairing_(false) {
   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
 
   jni_runtime_->display_task_runner()->PostTask(
@@ -60,10 +66,13 @@
                  this));
 }
 
-void ChromotingJniInstance::ProvideSecret(const std::string& pin) {
+void ChromotingJniInstance::ProvideSecret(const std::string& pin,
+                                          bool create_pairing) {
   DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread());
   DCHECK(!pin_callback_.is_null());
 
+  create_pairing_ = create_pairing;
+
   jni_runtime_->network_task_runner()->PostTask(FROM_HERE,
                                                 base::Bind(pin_callback_, pin));
 }
@@ -132,28 +141,40 @@
 void ChromotingJniInstance::OnConnectionState(
     protocol::ConnectionToHost::State state,
     protocol::ErrorCode error) {
-  if (!jni_runtime_->ui_task_runner()->BelongsToCurrentThread()) {
-    jni_runtime_->ui_task_runner()->PostTask(
-            FROM_HERE,
-            base::Bind(&ChromotingJniInstance::OnConnectionState,
-                       this,
-                       state,
-                       error));
-    return;
+  DCHECK(jni_runtime_->network_task_runner()->BelongsToCurrentThread());
+
+  if (create_pairing_ && state == protocol::ConnectionToHost::CONNECTED) {
+    LOG(INFO) << "Attempting to pair with host";
+    protocol::PairingRequest request;
+    request.set_client_name("Android");
+    connection_->host_stub()->RequestPairing(request);
   }
 
-  jni_runtime_->ReportConnectionStatus(state, error);
+  jni_runtime_->ui_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromotingJniRuntime::ReportConnectionStatus,
+                 base::Unretained(jni_runtime_),
+                 state,
+                 error));
 }
 
 void ChromotingJniInstance::OnConnectionReady(bool ready) {
-  // We ignore this message, since OnConnectionState() tells us the same thing.
+  // We ignore this message, since OnConnectoinState tells us the same thing.
 }
 
 void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) {}
 
 void ChromotingJniInstance::SetPairingResponse(
     const protocol::PairingResponse& response) {
-  NOTIMPLEMENTED();
+  LOG(INFO) << "Successfully established pairing with host";
+
+  jni_runtime_->ui_task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&ChromotingJniRuntime::CommitPairingCredentials,
+                 base::Unretained(jni_runtime_),
+                 host_id_,
+                 response.client_id(),
+                 response.shared_secret()));
 }
 
 protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() {
@@ -207,6 +228,13 @@
       this);
   client_config_->authentication_tag = host_id_;
 
+  if (!pairing_id_.empty() && !pairing_secret_.empty()) {
+    client_config_->client_pairing_id = pairing_id_;
+    client_config_->client_paired_secret = pairing_secret_;
+    client_config_->authentication_methods.push_back(
+        protocol::AuthenticationMethod::FromString("spake2_pair"));
+  }
+
   client_config_->authentication_methods.push_back(
       protocol::AuthenticationMethod::FromString("spake2_hmac"));
   client_config_->authentication_methods.push_back(
@@ -275,6 +303,13 @@
     return;
   }
 
+  if (!pairing_id_.empty() || !pairing_secret_.empty()) {
+    // We attempted to connect using an existing pairing that was rejected.
+    // Unless we forget about the stale credentials, we'll continue trying them.
+    LOG(INFO) << "Deleting rejected pairing credentials";
+    jni_runtime_->CommitPairingCredentials(host_id_, "", "");
+  }
+
   pin_callback_ = callback;
   jni_runtime_->DisplayAuthenticationPrompt();
 }
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h
index d6c7dbc..a8684bf 100644
--- a/remoting/client/jni/chromoting_jni_instance.h
+++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -37,13 +37,16 @@
     public base::RefCountedThreadSafe<ChromotingJniInstance> {
  public:
   // Initiates a connection with the specified host. Call from the UI thread.
-  // The instance does not take ownership of |jni_runtime|.
+  // The instance does not take ownership of |jni_runtime|. To connect with an
+  // unpaired host, pass in |pairing_id| and |pairing_secret| as empty strings.
   ChromotingJniInstance(ChromotingJniRuntime* jni_runtime,
                         const char* username,
                         const char* auth_token,
                         const char* host_jid,
                         const char* host_id,
-                        const char* host_pubkey);
+                        const char* host_pubkey,
+                        const char* pairing_id,
+                        const char* pairing_secret);
 
   // Terminates the current connection (if it hasn't already failed) and cleans
   // up. Must be called before destruction.
@@ -52,7 +55,7 @@
   // Provides the user's PIN and resumes the host authentication attempt. Call
   // on the UI thread once the user has finished entering this PIN into the UI,
   // but only after the UI has been asked to provide a PIN (via FetchSecret()).
-  void ProvideSecret(const std::string& pin);
+  void ProvideSecret(const std::string& pin, bool create_pair);
 
   // Schedules a redraw on the display thread. May be called from any thread.
   void RedrawDesktop();
@@ -131,6 +134,14 @@
   std::string host_jid_;
   std::string host_id_;
   std::string host_pubkey_;
+  std::string pairing_id_;
+  std::string pairing_secret_;
+
+  // Indicates whether to establish a new pairing with this host. This is
+  // modified in ProvideSecret(), but thereafter to be used only from the
+  // network thread. (This is safe because ProvideSecret() is invoked at most
+  // once per run, and always before any reference to this flag.)
+  bool create_pairing_;
 
   friend class base::RefCountedThreadSafe<ChromotingJniInstance>;
 
diff --git a/remoting/client/jni/chromoting_jni_runtime.cc b/remoting/client/jni/chromoting_jni_runtime.cc
index 4913594..8fa9018 100644
--- a/remoting/client/jni/chromoting_jni_runtime.cc
+++ b/remoting/client/jni/chromoting_jni_runtime.cc
@@ -76,7 +76,9 @@
                                   const char* auth_token,
                                   const char* host_jid,
                                   const char* host_id,
-                                  const char* host_pubkey) {
+                                  const char* host_pubkey,
+                                  const char* pairing_id,
+                                  const char* pairing_secret) {
   DCHECK(ui_task_runner_->BelongsToCurrentThread());
   DCHECK(!session_);
   session_ = new ChromotingJniInstance(this,
@@ -84,7 +86,9 @@
                                        auth_token,
                                        host_jid,
                                        host_id,
-                                       host_pubkey);
+                                       host_pubkey,
+                                       pairing_id,
+                                       pairing_secret);
 }
 
 void ChromotingJniRuntime::DisconnectFromHost() {
@@ -117,6 +121,34 @@
       env->GetStaticMethodID(class_, "displayAuthenticationPrompt", "()V"));
 }
 
+void ChromotingJniRuntime::CommitPairingCredentials(const std::string& host,
+                                                    const std::string& id,
+                                                    const std::string& secret) {
+  DCHECK(ui_task_runner_->BelongsToCurrentThread());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  jstring host_jstr = env->NewStringUTF(host.c_str());
+  jbyteArray id_arr = env->NewByteArray(id.size());
+  env->SetByteArrayRegion(id_arr, 0, id.size(),
+      reinterpret_cast<const jbyte*>(id.c_str()));
+  jbyteArray secret_arr = env->NewByteArray(secret.size());
+  env->SetByteArrayRegion(secret_arr, 0, secret.size(),
+      reinterpret_cast<const jbyte*>(secret.c_str()));
+
+  env->CallStaticVoidMethod(
+      class_,
+      env->GetStaticMethodID(
+          class_,
+          "commitPairingCredentials",
+          "(Ljava/lang/String;[B[B)V"),
+      host_jstr,
+      id_arr,
+      secret_arr);
+
+  // Because we passed them as arguments, their corresponding Java objects were
+  // GCd as soon as the managed method returned, so we mustn't release it here.
+}
+
 void ChromotingJniRuntime::UpdateImageBuffer(int width,
                                              int height,
                                              jobject buffer) {
diff --git a/remoting/client/jni/chromoting_jni_runtime.h b/remoting/client/jni/chromoting_jni_runtime.h
index ec85d7c..1a6952b 100644
--- a/remoting/client/jni/chromoting_jni_runtime.h
+++ b/remoting/client/jni/chromoting_jni_runtime.h
@@ -45,12 +45,15 @@
 
   // Initiates a connection with the specified host. Only call when a host
   // connection is active (i.e. between a call to Connect() and the
-  // corresponding call to Disconnect()).
+  // corresponding call to Disconnect()). To skip the attempt at pair-based
+  // authentication, leave |pairing_id| and |pairing_secret| as empty strings.
   void ConnectToHost(const char* username,
                      const char* auth_token,
                      const char* host_jid,
                      const char* host_id,
-                     const char* host_pubkey);
+                     const char* host_pubkey,
+                     const char* pairing_id,
+                     const char* pairing_secret);
 
   // Terminates any ongoing connection attempt and cleans up by nullifying
   // |session_|. This is a no-op unless |session| is currently non-null.
@@ -63,13 +66,18 @@
     return session_;
   }
 
-  // Notifies the user that the connection status has changed.
+  // Notifies the user of the current connection status. Call on UI thread.
   void ReportConnectionStatus(protocol::ConnectionToHost::State state,
                               protocol::ErrorCode error);
 
-  // Pops up a dialog box asking the user to enter a PIN.
+  // Pops up a dialog box asking the user to enter a PIN. Call on UI thread.
   void DisplayAuthenticationPrompt();
 
+  // Saves new pairing credentials to permanent storage. Call on UI thread.
+  void CommitPairingCredentials(const std::string& host,
+                                const std::string& id,
+                                const std::string& secret);
+
   // Updates image dimensions and canvas memory space. Call on display thread.
   void UpdateImageBuffer(int width, int height, jobject buffer);
 
diff --git a/remoting/client/jni/jni_interface.cc b/remoting/client/jni/jni_interface.cc
index 088ac82..5180558 100644
--- a/remoting/client/jni/jni_interface.cc
+++ b/remoting/client/jni/jni_interface.cc
@@ -69,25 +69,33 @@
     jstring auth_token_jstr,
     jstring host_jid_jstr,
     jstring host_id_jstr,
-    jstring host_pubkey_jstr) {
+    jstring host_pubkey_jstr,
+    jstring pair_id_jstr,
+    jstring pair_secret_jstr) {
   const char* username_cstr = env->GetStringUTFChars(username_jstr, NULL);
   const char* auth_token_cstr = env->GetStringUTFChars(auth_token_jstr, NULL);
   const char* host_jid_cstr = env->GetStringUTFChars(host_jid_jstr, NULL);
   const char* host_id_cstr = env->GetStringUTFChars(host_id_jstr, NULL);
   const char* host_pubkey_cstr = env->GetStringUTFChars(host_pubkey_jstr, NULL);
+  const char* pair_id_cstr = env->GetStringUTFChars(pair_id_jstr, NULL);
+  const char* pair_secret_cstr = env->GetStringUTFChars(pair_secret_jstr, NULL);
 
   remoting::ChromotingJniRuntime::GetInstance()->ConnectToHost(
       username_cstr,
       auth_token_cstr,
       host_jid_cstr,
       host_id_cstr,
-      host_pubkey_cstr);
+      host_pubkey_cstr,
+      pair_id_cstr,
+      pair_secret_cstr);
 
   env->ReleaseStringUTFChars(username_jstr, username_cstr);
   env->ReleaseStringUTFChars(auth_token_jstr, auth_token_cstr);
   env->ReleaseStringUTFChars(host_jid_jstr, host_jid_cstr);
   env->ReleaseStringUTFChars(host_id_jstr, host_id_cstr);
   env->ReleaseStringUTFChars(host_pubkey_jstr, host_pubkey_cstr);
+  env->ReleaseStringUTFChars(pair_id_jstr, pair_id_cstr);
+  env->ReleaseStringUTFChars(pair_secret_jstr, pair_secret_cstr);
 }
 
 JNIEXPORT void JNICALL JNI_IMPLEMENTATION(disconnectNative)(JNIEnv* env,
@@ -98,11 +106,12 @@
 JNIEXPORT void JNICALL JNI_IMPLEMENTATION(authenticationResponse)(
     JNIEnv* env,
     jobject that,
-    jstring pin_jstr) {
+    jstring pin_jstr,
+    jboolean create_pair) {
   const char* pin_cstr = env->GetStringUTFChars(pin_jstr, NULL);
 
   remoting::ChromotingJniRuntime::GetInstance()->
-      session()->ProvideSecret(pin_cstr);
+      session()->ProvideSecret(pin_cstr, create_pair);
 
   env->ReleaseStringUTFChars(pin_jstr, pin_cstr);
 }
diff --git a/remoting/host/installer/linux/debian/control b/remoting/host/installer/linux/debian/control
index a3fb4f5..1b2ba92 100644
--- a/remoting/host/installer/linux/debian/control
+++ b/remoting/host/installer/linux/debian/control
@@ -12,7 +12,7 @@
 
 Package: chrome-remote-desktop
 Architecture: any
-Depends: xvfb-randr | xvfb, python (>= 2.6), python-psutil, ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
+Depends: xvfb-randr | xvfb, gksu, python (>= 2.6), python-psutil, ${shlibs:Depends}, ${misc:Depends}, ${python:Depends}
 Recommends: xvfb-randr
 Suggests: google-chrome-stable | google-chrome-beta | google-chrome-unstable
 Description: Access your computer securely over the Internet.
diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp
index 5675799..48bcf44 100644
--- a/remoting/remoting.gyp
+++ b/remoting/remoting.gyp
@@ -1844,6 +1844,7 @@
               'files': [
                 'resources/layout/main.xml',
                 'resources/layout/host.xml',
+                'resources/layout/pin_dialog.xml',
               ],
             },
             {
@@ -2825,20 +2826,6 @@
             ],
           },
         }],
-        ['OS=="mac"', {
-          'mac_bundle': 1,
-          'xcode_settings': {
-            'INFOPLIST_FILE': 'unittests-Info.plist',
-            'INFOPLIST_PREPROCESS': 'YES',
-          },
-          'mac_bundle_resources': [
-            'unittests-Info.plist',
-            '<!@pymod_do_main(remoting_copy_locales -o -p <(OS) -x <(PRODUCT_DIR) <(remoting_locales))',
-          ],
-          'mac_bundle_resources!': [
-            'unittests-Info.plist',
-          ],
-        }],  # OS=="mac"
         ['OS=="mac" or (OS=="linux" and chromeos==0)', {
           # Javascript unittests are disabled on CrOS because they cause
           # valgrind and test errors.
diff --git a/remoting/resources/layout/pin_dialog.xml b/remoting/resources/layout/pin_dialog.xml
new file mode 100644
index 0000000..b8bd552
--- /dev/null
+++ b/remoting/resources/layout/pin_dialog.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_height="wrap_content"
+        android:layout_width="fill_parent">
+    <EditText android:id="@+id/pin_dialog_text"
+            android:inputType="numberPassword"
+            android:imeOptions="actionDone"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"/>
+    <CheckBox android:id="@+id/pin_dialog_check"
+            android:text="@string/pin_entry_pair"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"/>
+</LinearLayout>
diff --git a/remoting/resources/strings.xml b/remoting/resources/strings.xml
index 84a57a8..949a2aa 100644
--- a/remoting/resources/strings.xml
+++ b/remoting/resources/strings.xml
@@ -13,6 +13,7 @@
     <string name="progress_title">Starting remote desktop session</string>
     <string name="pin_entry_title">Authenticate to host</string>
     <string name="pin_entry_message">Enter the host\'s PIN</string>
+    <string name="pin_entry_pair">Don\'t ask in the future</string>
     <string name="pin_entry_connect">Connect</string>
     <string name="pin_entry_cancel">Cancel</string>
 
diff --git a/remoting/unittests-Info.plist b/remoting/unittests-Info.plist
deleted file mode 100644
index fcb8ee6..0000000
--- a/remoting/unittests-Info.plist
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>English</string>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.chromium.chromoting.remoting_unittests</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundlePackageType</key>
-	<string>BRPL</string>
-	<key>CFBundleShortVersionString</key>
-	<string>1.0.0.0</string>
-	<key>CFBundleVersion</key>
-	<string>1.0.0.0</string>
-	<key>CFBundleSignature</key>
-	<string>${CHROMIUM_CREATOR}</string>
-	<key>LSMinimumSystemVersion</key>
-	<string>10.5.0</string>
-</dict>
-</plist>
diff --git a/skia/ext/convolver_unittest.cc b/skia/ext/convolver_unittest.cc
index f99bf78..8d0c852 100644
--- a/skia/ext/convolver_unittest.cc
+++ b/skia/ext/convolver_unittest.cc
@@ -212,7 +212,13 @@
   ASSERT_EQ(0, filter_length);
 }
 
-TEST(Convolver, SIMDVerification) {
+#if defined(THREAD_SANITIZER)
+// Times out under ThreadSanitizer, http://crbug.com/134400.
+#define MAYBE_SIMDVerification DISABLED_SIMDVerification
+#else
+#define MAYBE_SIMDVerification SIMDVerification
+#endif
+TEST(Convolver, MAYBE_SIMDVerification) {
   int source_sizes[][2] = {
     {1,1}, {1,2}, {1,3}, {1,4}, {1,5},
     {2,1}, {2,2}, {2,3}, {2,4}, {2,5},
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi
index e91bfcb..2dca283 100644
--- a/skia/skia_library.gypi
+++ b/skia/skia_library.gypi
@@ -127,6 +127,8 @@
     '../third_party/skia/src/ports/SkTLS_pthread.cpp',
     '../third_party/skia/src/ports/SkTLS_win.cpp',
 
+    '../third_party/skia/src/sfnt/SkOTTable_name.cpp',
+    '../third_party/skia/src/sfnt/SkOTTable_name.h',
     '../third_party/skia/src/sfnt/SkOTUtils.cpp',
     '../third_party/skia/src/sfnt/SkOTUtils.h',
 
diff --git a/skia/skia_library.target.darwin-arm.mk b/skia/skia_library.target.darwin-arm.mk
index 52cf5d4..7d2cb16 100644
--- a/skia/skia_library.target.darwin-arm.mk
+++ b/skia/skia_library.target.darwin-arm.mk
@@ -39,6 +39,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -240,6 +241,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/skia/skia_library.target.darwin-mips.mk b/skia/skia_library.target.darwin-mips.mk
index 115fb00..34fe628 100644
--- a/skia/skia_library.target.darwin-mips.mk
+++ b/skia/skia_library.target.darwin-mips.mk
@@ -39,6 +39,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -240,6 +241,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/skia/skia_library.target.darwin-x86.mk b/skia/skia_library.target.darwin-x86.mk
index bf9b65e..69b4e75 100644
--- a/skia/skia_library.target.darwin-x86.mk
+++ b/skia/skia_library.target.darwin-x86.mk
@@ -40,6 +40,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -241,6 +242,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/skia/skia_library.target.linux-arm.mk b/skia/skia_library.target.linux-arm.mk
index 52cf5d4..7d2cb16 100644
--- a/skia/skia_library.target.linux-arm.mk
+++ b/skia/skia_library.target.linux-arm.mk
@@ -39,6 +39,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -240,6 +241,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/skia/skia_library.target.linux-mips.mk b/skia/skia_library.target.linux-mips.mk
index 115fb00..34fe628 100644
--- a/skia/skia_library.target.linux-mips.mk
+++ b/skia/skia_library.target.linux-mips.mk
@@ -39,6 +39,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -240,6 +241,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/skia/skia_library.target.linux-x86.mk b/skia/skia_library.target.linux-x86.mk
index bf9b65e..69b4e75 100644
--- a/skia/skia_library.target.linux-x86.mk
+++ b/skia/skia_library.target.linux-x86.mk
@@ -40,6 +40,7 @@
 	third_party/skia/src/ports/SkThread_pthread.cpp \
 	third_party/skia/src/ports/SkTime_Unix.cpp \
 	third_party/skia/src/ports/SkTLS_pthread.cpp \
+	third_party/skia/src/sfnt/SkOTTable_name.cpp \
 	third_party/skia/src/sfnt/SkOTUtils.cpp \
 	third_party/skia/src/utils/debugger/SkDebugCanvas.cpp \
 	third_party/skia/src/utils/debugger/SkDrawCommand.cpp \
@@ -241,6 +242,7 @@
 	third_party/skia/src/effects/SkColorFilterImageFilter.cpp \
 	third_party/skia/src/effects/SkColorMatrix.cpp \
 	third_party/skia/src/effects/SkColorMatrixFilter.cpp \
+	third_party/skia/src/effects/SkComposeImageFilter.cpp \
 	third_party/skia/src/effects/SkCornerPathEffect.cpp \
 	third_party/skia/src/effects/SkDashPathEffect.cpp \
 	third_party/skia/src/effects/SkDiscretePathEffect.cpp \
diff --git a/testing/gtest_ios/run-unittest.sh b/testing/gtest_ios/run-unittest.sh
index a19c18f..1598630 100755
--- a/testing/gtest_ios/run-unittest.sh
+++ b/testing/gtest_ios/run-unittest.sh
@@ -52,7 +52,7 @@
   fi
 
   for device in 'iPhone' 'iPad'; do
-    iosVersion="5.1"
+    iosVersion="6.1"
     KillSimulator
     local command=(
       "${SimExecutable}" "-d${device}" "-s${iosVersion}" "${appPath}"
diff --git a/third_party/android_testrunner/run_command.py b/third_party/android_testrunner/run_command.py
index 6b84156..5c82c61 100644
--- a/third_party/android_testrunner/run_command.py
+++ b/third_party/android_testrunner/run_command.py
@@ -22,6 +22,7 @@
 import tempfile
 import threading
 import time
+import sys
 
 # local imports
 import errors
@@ -93,12 +94,15 @@
     stdin_dest = subprocess.PIPE
   else:
     stdin_dest = None
+  stderr_dest = subprocess.STDOUT
+  if os.environ.get('ADB_TRACE'):
+    stderr_dest = sys.stdout
   pipe = subprocess.Popen(
       cmd,
       executable='/bin/bash',
       stdin=stdin_dest,
       stdout=output_dest,
-      stderr=subprocess.STDOUT,
+      stderr=stderr_dest,
       shell=True, close_fds=True,
       preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
 
diff --git a/third_party/cld/OWNERS b/third_party/cld/OWNERS
index 2dc9123..a214ab1 100644
--- a/third_party/cld/OWNERS
+++ b/third_party/cld/OWNERS
@@ -1,2 +1,3 @@
+hajimehoshi@chromium.org
 mad@chromium.org
 toyoshim@chromium.org
diff --git a/third_party/protobuf/README.chromium b/third_party/protobuf/README.chromium
index 6e82e82..e15fcae 100644
--- a/third_party/protobuf/README.chromium
+++ b/third_party/protobuf/README.chromium
@@ -26,7 +26,7 @@
 targets that depend on it can be componentized. See http://crbug.com/172800 for
 details, and r179806 for the patch.
 
-Revisions r427, r430, r475 and r476 were cherry-picked from upstream.
+Revisions r427, r430, r475, r476 and 504 were cherry-picked from upstream.
 Patch from http://code.google.com/p/protobuf/issues/detail?id=425 was
 cherry-picked from upstream.
 
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
index 89045cd..9b795ee 100644
--- a/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops.h
@@ -160,8 +160,11 @@
 #define GOOGLE_PROTOBUF_ATOMICOPS_ERROR \
 #error "Atomic operations are not supported on your platform"
 
+// ThreadSanitizer, http://clang.llvm.org/docs/ThreadSanitizer.html.
+#if defined(THREAD_SANITIZER)
+#include <google/protobuf/stubs/atomicops_internals_tsan.h>
 // MSVC.
-#if defined(_MSC_VER)
+#elif defined(_MSC_VER)
 #if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
 #include <google/protobuf/stubs/atomicops_internals_x86_msvc.h>
 #else
diff --git a/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_tsan.h b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_tsan.h
new file mode 100644
index 0000000..ca492b0
--- /dev/null
+++ b/third_party/protobuf/src/google/protobuf/stubs/atomicops_internals_tsan.h
@@ -0,0 +1,392 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// This file is an internal atomic implementation for compiler-based
+// ThreadSanitizer (http://clang.llvm.org/docs/ThreadSanitizer.html).
+// Use atomicops.h instead.
+
+#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
+#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#ifndef TSAN_INTERFACE_ATOMIC_H
+#define TSAN_INTERFACE_ATOMIC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef char  __tsan_atomic8;
+typedef short __tsan_atomic16;  // NOLINT
+typedef int   __tsan_atomic32;
+typedef long  __tsan_atomic64;  // NOLINT
+
+#if defined(__SIZEOF_INT128__) \
+    || (__clang_major__ * 100 + __clang_minor__ >= 302)
+typedef __int128 __tsan_atomic128;
+#define __TSAN_HAS_INT128 1
+#else
+typedef char     __tsan_atomic128;
+#define __TSAN_HAS_INT128 0
+#endif
+
+typedef enum {
+  __tsan_memory_order_relaxed,
+  __tsan_memory_order_consume,
+  __tsan_memory_order_acquire,
+  __tsan_memory_order_release,
+  __tsan_memory_order_acq_rel,
+  __tsan_memory_order_seq_cst,
+} __tsan_memory_order;
+
+__tsan_atomic8 __tsan_atomic8_load(const volatile __tsan_atomic8 *a,
+    __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_load(const volatile __tsan_atomic16 *a,
+    __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_load(const volatile __tsan_atomic32 *a,
+    __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_load(const volatile __tsan_atomic64 *a,
+    __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_load(const volatile __tsan_atomic128 *a,
+    __tsan_memory_order mo);
+
+void __tsan_atomic8_store(volatile __tsan_atomic8 *a, __tsan_atomic8 v,
+    __tsan_memory_order mo);
+void __tsan_atomic16_store(volatile __tsan_atomic16 *a, __tsan_atomic16 v,
+    __tsan_memory_order mo);
+void __tsan_atomic32_store(volatile __tsan_atomic32 *a, __tsan_atomic32 v,
+    __tsan_memory_order mo);
+void __tsan_atomic64_store(volatile __tsan_atomic64 *a, __tsan_atomic64 v,
+    __tsan_memory_order mo);
+void __tsan_atomic128_store(volatile __tsan_atomic128 *a, __tsan_atomic128 v,
+    __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_exchange(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_exchange(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_exchange(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_exchange(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_exchange(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_add(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_add(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_add(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_add(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_add(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_and(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_and(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_and(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_and(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_and(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_or(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_or(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_or(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_or(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_or(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_xor(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_xor(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_xor(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_xor(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_xor(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+__tsan_atomic8 __tsan_atomic8_fetch_nand(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 v, __tsan_memory_order mo);
+__tsan_atomic16 __tsan_atomic16_fetch_nand(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 v, __tsan_memory_order mo);
+__tsan_atomic32 __tsan_atomic32_fetch_nand(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 v, __tsan_memory_order mo);
+__tsan_atomic64 __tsan_atomic64_fetch_nand(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 v, __tsan_memory_order mo);
+__tsan_atomic128 __tsan_atomic128_fetch_nand(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 v, __tsan_memory_order mo);
+
+int __tsan_atomic8_compare_exchange_weak(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_weak(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_weak(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_weak(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_weak(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+
+int __tsan_atomic8_compare_exchange_strong(volatile __tsan_atomic8 *a,
+    __tsan_atomic8 *c, __tsan_atomic8 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic16_compare_exchange_strong(volatile __tsan_atomic16 *a,
+    __tsan_atomic16 *c, __tsan_atomic16 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic32_compare_exchange_strong(volatile __tsan_atomic32 *a,
+    __tsan_atomic32 *c, __tsan_atomic32 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic64_compare_exchange_strong(volatile __tsan_atomic64 *a,
+    __tsan_atomic64 *c, __tsan_atomic64 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+int __tsan_atomic128_compare_exchange_strong(volatile __tsan_atomic128 *a,
+    __tsan_atomic128 *c, __tsan_atomic128 v, __tsan_memory_order mo,
+    __tsan_memory_order fail_mo);
+
+__tsan_atomic8 __tsan_atomic8_compare_exchange_val(
+    volatile __tsan_atomic8 *a, __tsan_atomic8 c, __tsan_atomic8 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic16 __tsan_atomic16_compare_exchange_val(
+    volatile __tsan_atomic16 *a, __tsan_atomic16 c, __tsan_atomic16 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic32 __tsan_atomic32_compare_exchange_val(
+    volatile __tsan_atomic32 *a, __tsan_atomic32 c, __tsan_atomic32 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic64 __tsan_atomic64_compare_exchange_val(
+    volatile __tsan_atomic64 *a, __tsan_atomic64 c, __tsan_atomic64 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+__tsan_atomic128 __tsan_atomic128_compare_exchange_val(
+    volatile __tsan_atomic128 *a, __tsan_atomic128 c, __tsan_atomic128 v,
+    __tsan_memory_order mo, __tsan_memory_order fail_mo);
+
+void __tsan_atomic_thread_fence(__tsan_memory_order mo);
+void __tsan_atomic_signal_fence(__tsan_memory_order mo);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // #ifndef TSAN_INTERFACE_ATOMIC_H
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32 *ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32 *ptr,
+                                         Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_AtomicExchange(volatile Atomic32 *ptr,
+                                       Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_AtomicExchange(volatile Atomic32 *ptr,
+                                       Atomic32 new_value) {
+  return __tsan_atomic32_exchange(ptr, new_value,
+      __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                          Atomic32 increment) {
+  return increment + __tsan_atomic32_fetch_add(ptr, increment,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32 *ptr,
+                                        Atomic32 increment) {
+  return increment + __tsan_atomic32_fetch_add(ptr, increment,
+      __tsan_memory_order_acq_rel);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+  return cmp;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32 *ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 cmp = old_value;
+  __tsan_atomic32_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_release, __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline void NoBarrier_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_relaxed);
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic32 *ptr, Atomic32 value) {
+  __tsan_atomic32_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32 *ptr) {
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32 *ptr) {
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32 *ptr) {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+  return __tsan_atomic32_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64 *ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_relaxed, __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64 *ptr,
+                                         Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_AtomicExchange(volatile Atomic64 *ptr,
+                                       Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_AtomicExchange(volatile Atomic64 *ptr,
+                                       Atomic64 new_value) {
+  return __tsan_atomic64_exchange(ptr, new_value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                          Atomic64 increment) {
+  return increment + __tsan_atomic64_fetch_add(ptr, increment,
+      __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64 *ptr,
+                                        Atomic64 increment) {
+  return increment + __tsan_atomic64_fetch_add(ptr, increment,
+      __tsan_memory_order_acq_rel);
+}
+
+inline void NoBarrier_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_relaxed);
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+inline void Release_Store(volatile Atomic64 *ptr, Atomic64 value) {
+  __tsan_atomic64_store(ptr, value, __tsan_memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64 *ptr) {
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64 *ptr) {
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64 *ptr) {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+  return __tsan_atomic64_load(ptr, __tsan_memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_acquire, __tsan_memory_order_acquire);
+  return cmp;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64 *ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 cmp = old_value;
+  __tsan_atomic64_compare_exchange_strong(ptr, &cmp, new_value,
+      __tsan_memory_order_release, __tsan_memory_order_relaxed);
+  return cmp;
+}
+
+inline void MemoryBarrier() {
+  __tsan_atomic_thread_fence(__tsan_memory_order_seq_cst);
+}
+
+}  // namespace internal
+}  // namespace protobuf
+}  // namespace google
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_TSAN_H_
diff --git a/tools/heapcheck/suppressions.txt b/tools/heapcheck/suppressions.txt
index 994ad65..5f767c1 100644
--- a/tools/heapcheck/suppressions.txt
+++ b/tools/heapcheck/suppressions.txt
@@ -493,7 +493,7 @@
    bug_157885
    Heapcheck:Leak
    ...
-   fun:dom_storage::DomStorageContext::CreateSessionNamespace
+   fun:content::DOMStorageContextImpl::CreateSessionNamespace
 }
 {
    bug_159191
@@ -558,47 +558,6 @@
    fun:ash::Shell::Init
 }
 {
-   bug_169185_a
-   Heapcheck:Leak
-   fun:v8::internal::SlotsBufferAllocator::AllocateBuffer
-   fun:v8::internal::SlotsBuffer::AddTo
-   fun:v8::internal::MarkCompactCollector::Record*
-   ...
-   fun:v8::internal::StaticMarkingVisitor::IterateBody
-   fun:v8::internal::IncrementalMarking::VisitObject
-   fun:v8::internal::IncrementalMarking::ProcessMarkingDeque
-   fun:v8::internal::IncrementalMarking::Step
-   ...
-   fun:v8::internal::*Space::AllocateRaw
-}
-{
-   bug_169678_b
-   Heapcheck:Leak
-   fun:v8::internal::SlotsBufferAllocator::AllocateBuffer
-   fun:v8::internal::SlotsBuffer::AddTo
-   fun:v8::internal::MarkCompactCollector::RecordCodeEntrySlot
-   fun:v8::internal::StaticMarkingVisitor::VisitCodeEntry
-   ...
-   fun:v8::internal::IncrementalMarking::VisitObject
-   ...
-   fun:v8::internal::IncrementalMarking::OldSpaceStep
-   fun:v8::internal::FreeList::Allocate
-}
-{
-   bug_169678_c
-   Heapcheck:Leak
-   fun:v8::internal::SlotsBufferAllocator::AllocateBuffer
-   fun:v8::internal::SlotsBuffer::AddTo
-   fun:v8::internal::MarkCompactCollector::Record*
-   ...
-   fun:v8::internal::Heap::DoScavenge*
-   fun:v8::internal::Heap::Scavenge*
-   ...
-   fun:v8::internal::Heap::PerformGarbageCollection
-   fun:v8::internal::Heap::CollectGarbage
-   fun:v8::internal::Heap::CollectGarbage
-}
-{
    bug_171547_b
    Heapcheck:Leak
    ...
@@ -875,3 +834,24 @@
    fun:GetWeakPtr
    fun:base::WeakPtrTest_MoveOwnershipAfterInvalidate_Test::TestBody
 }
+{
+   bug_269716a
+   Heapcheck:Leak
+   fun:PL_ArenaAllocate
+   fun:net::NSSCertDatabase::DeleteCertAndKey
+   fun:chromeos::NetworkCertMigratorTest::CleanupTestCert
+}
+{
+   bug_269716b
+   Heapcheck:Leak
+   fun:PR_NewLock
+   fun:net::NSSCertDatabase::DeleteCertAndKey
+   fun:chromeos::NetworkCertMigratorTest::CleanupTestCert
+}
+{
+   bug_269716c
+   Heapcheck:Leak
+   fun:nss_ZAlloc
+   fun:net::NSSCertDatabase::DeleteCertAndKey
+   fun:chromeos::NetworkCertMigratorTest::CleanupTestCert
+}
diff --git a/tools/json_to_struct/element_generator.py b/tools/json_to_struct/element_generator.py
index 3a592d8..20d3069 100644
--- a/tools/json_to_struct/element_generator.py
+++ b/tools/json_to_struct/element_generator.py
@@ -42,7 +42,7 @@
     # json.dumps quotes the string and escape characters as required.
     lines.append('  L%s,' % _JSONToCString16(json.dumps(content)))
 
-def _GenerateArray(field_info, content, lines):
+def _GenerateArray(element_name, field_info, content, lines):
   """Generates an array to be included in a static structure initializer. If
   content is not specified, uses NULL. The array is assigned to a temporary
   variable which is initialized before the structure.
@@ -55,7 +55,7 @@
   # Create a new array variable and use it in the structure initializer.
   # This prohibits nested arrays. Add a clash detection and renaming mechanism
   # to solve the problem.
-  var = 'array_%s' % field_info['field'];
+  var = 'array_%s_%s' % (element_name, field_info['field']);
   lines.append('  %s,' % var)
   lines.append('  %s,' % len(content))  # Size of the array.
   # Generate the array content.
@@ -64,7 +64,8 @@
   array_lines.append(struct_generator.GenerateField(
                      field_info['contents']) + '[] = {')
   for subcontent in content:
-    GenerateFieldContent(field_info['contents'], subcontent, array_lines)
+    GenerateFieldContent(element_name, field_info['contents'], subcontent,
+                         array_lines)
   array_lines.append('};')
   # Prepend the generated array so it is initialized before the structure.
   lines.reverse()
@@ -72,7 +73,7 @@
   lines.extend(array_lines)
   lines.reverse()
 
-def GenerateFieldContent(field_info, content, lines):
+def GenerateFieldContent(element_name, field_info, content, lines):
   """Generate the content of a field to be included in the static structure
   initializer. If the field's content is not specified, uses the default value
   if one exists.
@@ -87,7 +88,7 @@
   elif type == 'string16':
     _GenerateString16(content, lines)
   elif type == 'array':
-    _GenerateArray(field_info, content, lines)
+    _GenerateArray(element_name, field_info, content, lines)
   else:
     raise RuntimeError('Unknown field type "%s"' % type)
 
@@ -101,7 +102,7 @@
     if (content == None and not field_info.get('optional', False)):
       raise RuntimeError('Mandatory field "%s" omitted in element "%s".' %
                          (field_info['field'], element_name))
-    GenerateFieldContent(field_info, content, lines)
+    GenerateFieldContent(element_name, field_info, content, lines)
   lines.append('};')
   return '\n'.join(lines)
 
diff --git a/tools/json_to_struct/element_generator_test.py b/tools/json_to_struct/element_generator_test.py
index 484e83f..67459a1 100755
--- a/tools/json_to_struct/element_generator_test.py
+++ b/tools/json_to_struct/element_generator_test.py
@@ -10,70 +10,72 @@
 class ElementGeneratorTest(unittest.TestCase):
   def testGenerateIntFieldContent(self):
     lines = [];
-    GenerateFieldContent({'type': 'int', 'default': 5}, None, lines)
+    GenerateFieldContent('', {'type': 'int', 'default': 5}, None, lines)
     self.assertEquals(['  5,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'int', 'default': 5}, 12, lines)
+    GenerateFieldContent('', {'type': 'int', 'default': 5}, 12, lines)
     self.assertEquals(['  12,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'int'}, -3, lines)
+    GenerateFieldContent('', {'type': 'int'}, -3, lines)
     self.assertEquals(['  -3,'], lines)
 
   def testGenerateStringFieldContent(self):
     lines = [];
-    GenerateFieldContent({'type': 'string', 'default': 'foo_bar'}, None, lines)
+    GenerateFieldContent('', {'type': 'string', 'default': 'foo_bar'}, None,
+                         lines)
     self.assertEquals(['  "foo_bar",'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string', 'default': 'foo'}, 'bar\n', lines)
+    GenerateFieldContent('', {'type': 'string', 'default': 'foo'}, 'bar\n',
+                         lines)
     self.assertEquals(['  "bar\\n",'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string'}, None, lines)
+    GenerateFieldContent('', {'type': 'string'}, None, lines)
     self.assertEquals(['  NULL,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string'}, 'foo', lines)
+    GenerateFieldContent('', {'type': 'string'}, 'foo', lines)
     self.assertEquals(['  "foo",'], lines)
 
   def testGenerateString16FieldContent(self):
     lines = [];
-    GenerateFieldContent({'type': 'string16', 'default': u'f\u00d8\u00d81a'},
-                         None, lines)
+    GenerateFieldContent('', {'type': 'string16',
+                              'default': u'f\u00d8\u00d81a'}, None, lines)
     self.assertEquals(['  L"f\\x00d8" L"\\x00d8" L"1a",'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string16', 'default': 'foo'}, u'b\uc3a5r',
-                         lines)
+    GenerateFieldContent('', {'type': 'string16', 'default': 'foo'},
+                         u'b\uc3a5r', lines)
     self.assertEquals(['  L"b\\xc3a5" L"r",'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string16'}, None, lines)
+    GenerateFieldContent('', {'type': 'string16'}, None, lines)
     self.assertEquals(['  NULL,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'string16'}, u'foo\\u1234', lines)
+    GenerateFieldContent('', {'type': 'string16'}, u'foo\\u1234', lines)
     self.assertEquals(['  L"foo\\\\u1234",'], lines)
 
   def testGenerateEnumFieldContent(self):
     lines = [];
-    GenerateFieldContent({'type': 'enum', 'default': 'RED'}, None, lines)
+    GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, None, lines)
     self.assertEquals(['  RED,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'enum', 'default': 'RED'}, 'BLACK', lines)
+    GenerateFieldContent('', {'type': 'enum', 'default': 'RED'}, 'BLACK', lines)
     self.assertEquals(['  BLACK,'], lines)
     lines = [];
-    GenerateFieldContent({'type': 'enum'}, 'BLUE', lines)
+    GenerateFieldContent('', {'type': 'enum'}, 'BLUE', lines)
     self.assertEquals(['  BLUE,'], lines)
 
   def testGenerateArrayFieldContent(self):
     lines = ['STRUCT BEGINS'];
-    GenerateFieldContent({'type': 'array', 'contents': {'type': 'int'}},
+    GenerateFieldContent('test', {'type': 'array', 'contents': {'type': 'int'}},
                          None, lines)
     self.assertEquals(['STRUCT BEGINS', '  NULL,', '  0,'], lines)
     lines = ['STRUCT BEGINS'];
-    GenerateFieldContent({'field': 'my_array', 'type': 'array',
-                          'contents': {'type': 'int'}}, [3, 4], lines)
-    self.assertEquals('const int array_my_array[] = {\n' +
+    GenerateFieldContent('test', {'field': 'my_array', 'type': 'array',
+                                  'contents': {'type': 'int'}}, [3, 4], lines)
+    self.assertEquals('const int array_test_my_array[] = {\n' +
       '  3,\n' +
       '  4,\n' +
       '};\n' +
       'STRUCT BEGINS\n' +
-      '  array_my_array,\n' +
+      '  array_test_my_array,\n' +
       '  2,', '\n'.join(lines))
 
   def testGenerateElements(self):
@@ -115,7 +117,7 @@
                '  NULL,\n' +
                '  0,\n'
                '};\n',
-      'elem2': 'const wchar_t* const array_f3[] = {\n' +
+      'elem2': 'const wchar_t* const array_elem2_f3[] = {\n' +
                '  L"bar",\n' +
                '  L"foo",\n' +
                '};\n' +
@@ -123,7 +125,7 @@
                '  1000,\n' +
                '  "foo_bar",\n' +
                '  MAYBE,\n' +
-               '  array_f3,\n' +
+               '  array_elem2_f3,\n' +
                '  2,\n'
                '};\n'
     }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f1069c1..3e7fe9d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5977,6 +5977,66 @@
   </summary>
 </histogram>
 
+<histogram name="Net.DailyHttpContentLengthViaDataReductionProxy" units="KB">
+  <summary>
+    Total size in KB of all response bodies in the previous calendar day that
+    were received through the data reduction proxy.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyHttpContentLengthWithDataReductionProxyEnabled"
+    units="KB">
+  <summary>
+    Total size in KB of all response bodies in the previous calendar day that
+    were received when the data reduction proxy was enabled.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyHttpContentSavings" units="Percent">
+  <summary>
+    The percentage of data saving in the previous calendar day. A negative
+    saving will be shown as zero.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyHttpContentSavings_DataReductionProxy"
+    units="Percent">
+  <summary>
+    The percentage of data saving in the previous calendar day when the data
+    reduction proxy was enabled for at least some responses during the day. A
+    negative saving will be shown as zero.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyHttpOriginalContentLength" units="KB">
+  <summary>
+    Total size in KB specified in the X-Original-Content-Length headers of all
+    responses in the previous calendar day. If the header is not present in a
+    response, the size of the response body is used.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyHttpReceivedContentLength" units="KB">
+  <summary>
+    Total size in KB of all response bodies in the previous calendar day.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyReceivedContentViaDataReductionProxy" units="Percent">
+  <summary>
+    The percentage of Net.DailyHttpContentLengthViaDataReductionProxy in
+    Net.DailyHttpReceivedContentLength.
+  </summary>
+</histogram>
+
+<histogram name="Net.DailyReceivedContentWithDataReductionProxyEnabled"
+    units="Percent">
+  <summary>
+    The percentage of Net.DailyHttpContentLengthWithDataReductionProxyEnabled in
+    Net.DailyHttpReceivedContentLength.
+  </summary>
+</histogram>
+
 <histogram name="Net.DhcpWpadCancelTime" units="milliseconds">
   <summary>
     Measures time from initiating a fetch of a PAC file from DHCP WPAD to
@@ -21918,6 +21978,8 @@
   <int value="9" label="DONT_PROCEED_AUTHORITY"/>
   <int value="10" label="MORE"/>
   <int value="11" label="SHOW_UNDERSTAND"/>
+  <int value="12" label="SHOW_INTERNAL_HOSTNAME"/>
+  <int value="13" label="PROCEED_INTERNAL_HOSTNAME"/>
 </enum>
 
 <enum name="SuspendStatus" type="int">
diff --git a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
index 13bb286..50ca98b 100644
--- a/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
+++ b/tools/telemetry/telemetry/core/backends/chrome/chrome_browser_backend.py
@@ -177,6 +177,14 @@
       raise exceptions.BrowserConnectionGoneException()
 
   @property
+  def browser_directory(self):
+    raise NotImplementedError()
+
+  @property
+  def profile_directory(self):
+    raise NotImplementedError()
+
+  @property
   def chrome_branch_number(self):
     return self._chrome_branch_number
 
diff --git a/tools/telemetry/telemetry/core/browser.py b/tools/telemetry/telemetry/core/browser.py
index f8dbb39..a04b058 100644
--- a/tools/telemetry/telemetry/core/browser.py
+++ b/tools/telemetry/telemetry/core/browser.py
@@ -232,6 +232,16 @@
     return self._browser_backend.GetTraceResultAndReset()
 
   def Start(self):
+    options = self._browser_backend.options
+    if options.clear_sytem_cache_for_browser_and_profile_on_start:
+      if self._platform.CanFlushIndividualFilesFromSystemCache():
+        self._platform.FlushSystemCacheForDirectory(
+            self._browser_backend.profile_directory)
+        self._platform.FlushSystemCacheForDirectory(
+            self._browser_backend.browser_directory)
+      else:
+        self._platform.FlushEntireSystemCache()
+
     self._browser_backend.Start()
     self._browser_backend.SetBrowser(self)
 
diff --git a/tools/telemetry/telemetry/core/browser_options.py b/tools/telemetry/telemetry/core/browser_options.py
index 2daf439..c27d158 100644
--- a/tools/telemetry/telemetry/core/browser_options.py
+++ b/tools/telemetry/telemetry/core/browser_options.py
@@ -37,6 +37,7 @@
     self.extra_wpr_args = []
     self.show_stdout = False
     self.extensions_to_load = []
+    self.clear_sytem_cache_for_browser_and_profile_on_start = False
 
     self.cros_remote = None
     self.wpr_mode = wpr_modes.WPR_OFF
diff --git a/tools/telemetry/telemetry/core/chrome/android_browser_backend.py b/tools/telemetry/telemetry/core/chrome/android_browser_backend.py
index ec6b133..34aa933 100644
--- a/tools/telemetry/telemetry/core/chrome/android_browser_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/android_browser_backend.py
@@ -28,7 +28,7 @@
 
   def RemoveProfile(self):
     self.adb.RunShellCommand(
-        'su -c rm -r "%s"' % self._profile_dir)
+        'su -c rm -r "%s"' % self.profile_dir)
 
   def PushProfile(self, _):
     logging.critical('Profiles cannot be overriden with current configuration')
@@ -39,7 +39,7 @@
     return False
 
   @property
-  def _profile_dir(self):
+  def profile_dir(self):
     raise NotImplementedError()
 
 
@@ -59,10 +59,10 @@
     return 'localabstract:chrome_devtools_remote'
 
   def PushProfile(self, new_profile_dir):
-    self.adb.Push(new_profile_dir, self._profile_dir)
+    self.adb.Push(new_profile_dir, self.profile_dir)
 
   @property
-  def _profile_dir(self):
+  def profile_dir(self):
     return '/data/data/%s/app_chrome/' % self.package
 
 
@@ -83,7 +83,7 @@
     return True
 
   @property
-  def _profile_dir(self):
+  def profile_dir(self):
     return '/data/data/%s/app_content_shell/' % self.package
 
 
@@ -104,7 +104,7 @@
     return True
 
   @property
-  def _profile_dir(self):
+  def profile_dir(self):
     return '/data/data/%s/app_chromiumtestshell/' % self.package
 
 
@@ -139,7 +139,7 @@
     return 'localabstract:webview_devtools_remote_%s' % str(pid)
 
   @property
-  def _profile_dir(self):
+  def profile_dir(self):
     return '/data/data/%s/app_webview/' % self.package
 
 
@@ -244,6 +244,14 @@
   def pid(self):
     return int(self._adb.ExtractPid(self._backend_settings.package)[0])
 
+  @property
+  def browser_directory(self):
+    return None
+
+  @property
+  def profile_directory(self):
+    return self._backend_settings.profile_dir
+
   def __del__(self):
     self.Close()
 
diff --git a/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py b/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
index a3daeee..bad383c 100644
--- a/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/cros_browser_backend.py
@@ -18,8 +18,9 @@
                   '/usr/local/opt/google/chrome/chrome ']
 
   def __init__(self, browser_type, options, cri, is_guest):
-    super(CrOSBrowserBackend, self).__init__(is_content_shell=False,
-        supports_extensions=not is_guest, options=options)
+    super(CrOSBrowserBackend, self).__init__(
+        is_content_shell=False, supports_extensions=not is_guest,
+        options=options)
     # Initialize fields so that an explosion during init doesn't break in Close.
     self._browser_type = browser_type
     self._options = options
@@ -84,6 +85,8 @@
             '--disable-default-apps',
             # Jump to the login screen, skipping network selection, eula, etc.
             '--login-screen=login',
+            # Skip user image selection screen, and post login screens.
+            '--oobe-skip-postlogin',
             # Allow devtools to connect to chrome.
             '--remote-debugging-port=%i' % self._remote_debugging_port,
             # Open a maximized window.
@@ -110,9 +113,8 @@
         return pid
     return None
 
-  @property
-  def pid(self):
-    """Locates the pid of the main chrome browser process.
+  def _GetChromeProcess(self):
+    """Locates the the main chrome browser process.
 
     Chrome on cros is usually in /opt/google/chrome, but could be in
     /usr/local/ for developer workflows - debug chrome is too large to fit on
@@ -134,10 +136,28 @@
         continue
       for path in self.CHROME_PATHS:
         if process.startswith(path):
-          return pid
+          return {'pid': pid, 'path': path}
     return None
 
   @property
+  def pid(self):
+    result = self._GetChromeProcess()
+    if 'pid' in result:
+      return result['pid']
+    return None
+
+  @property
+  def browser_directory(self):
+    result = self._GetChromeProcess()
+    if 'path' in result:
+      return result['path']
+    return None
+
+  @property
+  def profile_directory(self):
+    return '/home/chronos/Default'
+
+  @property
   def hwid(self):
     return self._cri.RunCmdOnDevice(['/usr/bin/crossystem', 'hwid'])[0]
 
@@ -268,8 +288,8 @@
 
   def _HandleUserImageSelectionScreen(self):
     """If we're stuck on the user image selection screen, we click the ok
-    button. TODO(achuith): Figure out a better way to bypass user image
-    selection. crbug.com/249182."""
+    button.
+    """
     oobe = self.oobe
     if oobe:
       try:
@@ -285,7 +305,8 @@
   def _IsLoggedIn(self):
     """Returns True if we're logged in (cryptohome has mounted), and the oobe
     has been dismissed."""
-    self._HandleUserImageSelectionScreen()
+    if self.chrome_branch_number <= 1547:
+      self._HandleUserImageSelectionScreen()
     return self._IsCryptohomeMounted() and not self.oobe
 
   def _StartupWindow(self):
diff --git a/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py b/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
index 0e90658..834278d 100644
--- a/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
+++ b/tools/telemetry/telemetry/core/chrome/desktop_browser_backend.py
@@ -17,7 +17,7 @@
   Mac or Windows.
   """
   def __init__(self, options, executable, flash_path, is_content_shell,
-               delete_profile_dir_after_run=True):
+               browser_directory, delete_profile_dir_after_run=True):
     super(DesktopBrowserBackend, self).__init__(
         is_content_shell=is_content_shell,
         supports_extensions=not is_content_shell,
@@ -43,6 +43,7 @@
       raise browser_backend.ExtensionsNotSupportedException(
           'Content shell does not support extensions.')
 
+    self._browser_directory = browser_directory
     self._port = util.GetAvailableLocalPort()
     self._profile_dir = None
     self._supports_net_benchmarking = True
@@ -120,6 +121,10 @@
     return None
 
   @property
+  def browser_directory(self):
+    return self._browser_directory
+
+  @property
   def profile_directory(self):
     return self._tmpdir
 
diff --git a/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py b/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
index c2f625e..8ef4d6d 100644
--- a/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
+++ b/tools/telemetry/telemetry/core/chrome/desktop_browser_finder.py
@@ -33,11 +33,12 @@
   """A desktop browser that can be controlled."""
 
   def __init__(self, browser_type, options, executable, flash_path,
-               is_content_shell, is_local_build=False):
+               is_content_shell, browser_directory, is_local_build=False):
     super(PossibleDesktopBrowser, self).__init__(browser_type, options)
     self._local_executable = executable
     self._flash_path = flash_path
     self._is_content_shell = is_content_shell
+    self._browser_directory = browser_directory
     self.is_local_build = is_local_build
 
   def __repr__(self):
@@ -48,7 +49,7 @@
   def _CreateBrowserInternal(self, delete_profile_dir_after_run):
     backend = desktop_browser_backend.DesktopBrowserBackend(
         self._options, self._local_executable, self._flash_path,
-        self._is_content_shell,
+        self._is_content_shell, self._browser_directory,
         delete_profile_dir_after_run=delete_profile_dir_after_run)
     b = browser.Browser(backend,
                         core_platform.CreatePlatformBackendForCurrentOS())
@@ -153,18 +154,21 @@
   if options.browser_executable:
     normalized_executable = os.path.expanduser(options.browser_executable)
     if os.path.exists(normalized_executable):
+      browser_directory = os.path.dirname(options.browser_executable)
       browsers.append(PossibleDesktopBrowser('exact', options,
                                              normalized_executable, flash_path,
-                                             False))
+                                             False, browser_directory))
     else:
       logging.warning('%s specified by browser_executable does not exist',
                       normalized_executable)
 
   def AddIfFound(browser_type, build_dir, type_dir, app_name, content_shell):
-    app = os.path.join(chrome_root, build_dir, type_dir, app_name)
+    browser_directory = os.path.join(chrome_root, build_dir, type_dir)
+    app = os.path.join(browser_directory, app_name)
     if os.path.exists(app):
       browsers.append(PossibleDesktopBrowser(browser_type, options,
                                              app, flash_path, content_shell,
+                                             browser_directory,
                                              is_local_build=True))
       return True
     return False
@@ -178,16 +182,19 @@
 
   # Mac-specific options.
   if sys.platform == 'darwin':
-    mac_canary = ('/Applications/Google Chrome Canary.app/'
-                 'Contents/MacOS/Google Chrome Canary')
-    mac_system = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
+    mac_canary_root = '/Applications/Google Chrome Canary.app/'
+    mac_canary = mac_canary_root + 'Contents/MacOS/Google Chrome Canary'
+    mac_system_root = '/Applications/Google Chrome.app'
+    mac_system = mac_system_root + '/Contents/MacOS/Google Chrome'
     if os.path.exists(mac_canary):
       browsers.append(PossibleDesktopBrowser('canary', options,
-                                             mac_canary, None, False))
+                                             mac_canary, None, False,
+                                             mac_canary_root))
 
     if os.path.exists(mac_system):
       browsers.append(PossibleDesktopBrowser('system', options,
-                                             mac_system, None, False))
+                                             mac_system, None, False,
+                                             mac_system_root))
 
   # Linux specific options.
   if sys.platform.startswith('linux'):
@@ -201,7 +208,8 @@
       pass
     if found:
       browsers.append(PossibleDesktopBrowser('system', options,
-                                             'google-chrome', None, False))
+                                             'google-chrome', None, False,
+                                             '/opt/google/chrome'))
 
   # Win32-specific options.
   if sys.platform.startswith('win'):
@@ -213,10 +221,12 @@
                         os.getenv('LOCALAPPDATA')]
 
     def AddIfFoundWin(browser_name, app_path):
-      app = os.path.join(path, app_path, chromium_app_name)
+      browser_directory = os.path.join(path, app_path)
+      app = os.path.join(browser_directory, chromium_app_name)
       if os.path.exists(app):
         browsers.append(PossibleDesktopBrowser(browser_name, options,
-                                               app, flash_path, False))
+                                               app, flash_path, False,
+                                               browser_directory))
         return True
       return False
 
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 0464b0f..6d773b7 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -1197,6 +1197,25 @@
    fun:_ZN7WebCore16HTMLScriptRunner36executePendingScriptAndDispatchEventERNS_13PendingScriptE
 }
 
+# http://crbug.com/269278 causes really widespread, flaky leaks in
+# value objects that own some memory.  These suppressions will cover
+# all such objects, even though it's possible to get real leaks that
+# look the same way (e.g. by allocating such an object in an arena).
+{
+   bug_269278a
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN4base4Bind*Callback*BindState*
+}
+{
+   bug_269278b
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN9__gnu_cxx13new_allocator*allocate*
+   fun:_ZNSt12_Vector_base*_M_allocate*
+}
+
+
 #-----------------------------------------------------------------------
 # 3. Suppressions for real chromium bugs that are not yet fixed.
 # These should all be in chromium's bug tracking system (but a few aren't yet).
@@ -5764,19 +5783,6 @@
    fun:_ZN11dom_storage17DomStorageContext18DeleteLocalStorageERK4GURL
 }
 {
-   bug_166485
-   Memcheck:Leak
-   fun:_Znw*
-   fun:_ZN9__gnu_cxx13new_allocator*FilePath*allocate*
-   fun:_ZNSt12_Vector_base*FilePath*_M_allocate*
-   fun:_ZNSt6vector*FilePath*_M_insert_aux*
-   fun:_ZNSt6vector*FilePath*push_back*
-   fun:_ZN9file_util26CreateDirectoryAndGetError*
-   fun:_ZN9file_util15CreateDirectory*
-   fun:_ZN11dom_storage17DomStorageContext19GetStorageNamespaceEl
-   fun:_ZN11dom_storage17DomStorageContext18DeleteLocalStorageERK4GURL
-}
-{
    bug_166709
    Memcheck:Leak
    fun:_Znw*
@@ -7216,3 +7222,12 @@
   fun:_ZN7content10PluginList17ReadWebPluginInfoERKN4base8FilePathEPNS_13WebPluginInfoE
   fun:_ZN7content10PluginList14ReadPluginInfoERKN4base8FilePathEPNS_13WebPluginInfoE
 }
+{
+   bug_269201
+   Memcheck:Unaddressable
+   ...
+   fun:_ZN4base8internal17IncomingTaskQueue18AddToIncomingQueueERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEENS_9TimeDeltaEb
+   fun:_ZN4base11MessageLoop8PostTaskERKN15tracked_objects8LocationERKNS_8CallbackIFvvEEE
+   fun:_ZN8printing8PrintJob21UpdatePrintedDocumentEPNS_15PrintedDocumentE
+   fun:_ZN8printing8PrintJob4StopEv
+ }
diff --git a/tools/valgrind/tsan/suppressions.txt b/tools/valgrind/tsan/suppressions.txt
index fcd4803..b0de50b 100644
--- a/tools/valgrind/tsan/suppressions.txt
+++ b/tools/valgrind/tsan/suppressions.txt
@@ -134,12 +134,11 @@
   fun:uprv_malloc_46
 }
 
+# http://bugs.icu-project.org/trac/ticket/10295
 {
-  Two writes, same value (ICU gLibCleanupFunctions[UCLN_UPLUG])
+  Two writes, same value (ICU gLibCleanupFunctions[*])
   ThreadSanitizer:Race
   fun:ucln_registerCleanup_46
-  fun:uplug_init_46
-  fun:u_init_46
 }
 
 # Reading a pointer to a mutex being initialized in a concurrent thread.
@@ -1128,3 +1127,12 @@
   fun:base::MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking
   fun:base::MessagePumpLibevent::OnLibeventNotification
 }
+{
+  bug_268924
+  ThreadSanitizer:Race
+  fun:base::PowerMonitor::PowerMonitor
+  fun:content::ChildThread::Init
+  fun:content::ChildThread::ChildThread
+  fun:content::UtilityThreadImpl::UtilityThreadImpl
+  fun:content::UtilityMainThread::InitInternal
+}
diff --git a/ui/android/java/src/org/chromium/ui/SelectFileDialog.java b/ui/android/java/src/org/chromium/ui/SelectFileDialog.java
index 9aa11e4..91533b5 100644
--- a/ui/android/java/src/org/chromium/ui/SelectFileDialog.java
+++ b/ui/android/java/src/org/chromium/ui/SelectFileDialog.java
@@ -64,17 +64,16 @@
         Intent camcorder = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
         Intent soundRecorder = new Intent(
                 MediaStore.Audio.Media.RECORD_SOUND_ACTION);
-        String lowMemoryError = window.getContext().getString(R.string.low_memory_error);
 
         // Quick check - if the |capture| parameter is set and |fileTypes| has the appropriate MIME
         // type, we should just launch the appropriate intent. Otherwise build up a chooser based on
         // the accept type and then display that to the user.
         if (captureCamera()) {
-            if (window.showIntent(camera, this, lowMemoryError)) return;
+            if (window.showIntent(camera, this, R.string.low_memory_error)) return;
         } else if (captureCamcorder()) {
-            if (window.showIntent(camcorder, this, lowMemoryError)) return;
+            if (window.showIntent(camcorder, this, R.string.low_memory_error)) return;
         } else if (captureMicrophone()) {
-            if (window.showIntent(soundRecorder, this, lowMemoryError)) return;
+            if (window.showIntent(soundRecorder, this, R.string.low_memory_error)) return;
         }
 
         Intent getContentIntent = new Intent(Intent.ACTION_GET_CONTENT);
@@ -109,7 +108,9 @@
 
         chooser.putExtra(Intent.EXTRA_INTENT, getContentIntent);
 
-        if (!window.showIntent(chooser, this, lowMemoryError)) onFileNotSelected();
+        if (!window.showIntent(chooser, this, R.string.low_memory_error)) {
+            onFileNotSelected();
+        }
     }
 
     /**
diff --git a/ui/android/java/src/org/chromium/ui/WindowAndroid.java b/ui/android/java/src/org/chromium/ui/WindowAndroid.java
index 477e5e6..316690b 100644
--- a/ui/android/java/src/org/chromium/ui/WindowAndroid.java
+++ b/ui/android/java/src/org/chromium/ui/WindowAndroid.java
@@ -52,10 +52,11 @@
      * Shows an intent and returns the results to the callback object.
      * @param intent The intent that needs to be showed.
      * @param callback The object that will receive the results for the intent.
-     * @param error The error string to be show if activity is paused before intent results.
+     * @param errorId The ID of error string to be show if activity is paused before intent
+     *        results.
      * @return Whether the intent was shown.
      */
-    public boolean showIntent(Intent intent, IntentCallback callback, String error) {
+    public boolean showIntent(Intent intent, IntentCallback callback, int errorId) {
         int requestCode = REQUEST_CODE_PREFIX + mNextRequestCode;
         mNextRequestCode = (mNextRequestCode + 1) % REQUEST_CODE_RANGE_SIZE;
 
@@ -66,7 +67,7 @@
         }
 
         mOutstandingIntents.put(requestCode, callback);
-        if (error != null) mIntentErrors.put(requestCode, error);
+        mIntentErrors.put(requestCode, mActivity.getString(errorId));
 
         return true;
     }
diff --git a/ui/app_list/cocoa/apps_grid_controller.mm b/ui/app_list/cocoa/apps_grid_controller.mm
index c2873c4..d32a791 100644
--- a/ui/app_list/cocoa/apps_grid_controller.mm
+++ b/ui/app_list/cocoa/apps_grid_controller.mm
@@ -22,7 +22,7 @@
 
 // Padding space in pixels for fixed layout.
 const CGFloat kGridTopPadding = 1;
-const CGFloat kLeftRightPadding = 16;
+const CGFloat kLeftRightPadding = 21;
 const CGFloat kScrollerPadding = 16;
 
 // Preferred tile size when showing in fixed layout. These should be even
diff --git a/ui/app_list/cocoa/apps_grid_view_item.mm b/ui/app_list/cocoa/apps_grid_view_item.mm
index 908bb87..34fe975 100644
--- a/ui/app_list/cocoa/apps_grid_view_item.mm
+++ b/ui/app_list/cocoa/apps_grid_view_item.mm
@@ -30,6 +30,10 @@
 const CGFloat kProgressBarHorizontalPadding = 8;
 const CGFloat kProgressBarVerticalPadding = 13;
 
+// On Mac, fonts of the same enum from ResourceBundle are larger. The smallest
+// enum is already used, so it needs to be reduced further to match Windows.
+const int kMacFontSizeDelta = -1;
+
 }  // namespace
 
 @class AppsGridItemBackgroundView;
@@ -238,8 +242,10 @@
   [paragraphStyle setAlignment:NSCenterTextAlignment];
   NSDictionary* titleAttributes = @{
     NSParagraphStyleAttributeName : paragraphStyle,
-    NSFontAttributeName : ui::ResourceBundle::GetSharedInstance().GetFont(
-        app_list::kItemTextFontStyle).GetNativeFont(),
+    NSFontAttributeName : ui::ResourceBundle::GetSharedInstance()
+        .GetFont(app_list::kItemTextFontStyle)
+        .DeriveFont(kMacFontSizeDelta)
+        .GetNativeFont(),
     NSForegroundColorAttributeName : [self isSelected] ?
         gfx::SkColorToSRGBNSColor(app_list::kGridTitleHoverColor) :
         gfx::SkColorToSRGBNSColor(app_list::kGridTitleColor)
diff --git a/ui/base/default_theme_provider.h b/ui/base/default_theme_provider.h
index 6487b42..2594dfb 100644
--- a/ui/base/default_theme_provider.h
+++ b/ui/base/default_theme_provider.h
@@ -34,11 +34,10 @@
       ui::ScaleFactor scale_factor) const OVERRIDE;
 
 #if defined(OS_MACOSX) && !defined(TOOLKIT_VIEWS)
-  virtual NSImage* GetNSImageNamed(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSImageColorNamed(int id,
-                                        bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColor(int id, bool allow_default) const OVERRIDE;
-  virtual NSColor* GetNSColorTint(int id, bool allow_default) const OVERRIDE;
+  virtual NSImage* GetNSImageNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSImageColorNamed(int id) const OVERRIDE;
+  virtual NSColor* GetNSColor(int id) const OVERRIDE;
+  virtual NSColor* GetNSColorTint(int id) const OVERRIDE;
   virtual NSGradient* GetNSGradient(int id) const OVERRIDE;
 #elif defined(OS_POSIX) && !defined(TOOLKIT_VIEWS) && !defined(OS_ANDROID)
   virtual GdkPixbuf* GetRTLEnabledPixbufNamed(int id) const OVERRIDE;
diff --git a/ui/base/default_theme_provider_mac.mm b/ui/base/default_theme_provider_mac.mm
index 08725c2..cc33728 100644
--- a/ui/base/default_theme_provider_mac.mm
+++ b/ui/base/default_theme_provider_mac.mm
@@ -11,25 +11,21 @@
 namespace ui {
 
 #if !defined(TOOLKIT_VIEWS)
-NSImage* DefaultThemeProvider::GetNSImageNamed(int id,
-                                               bool allow_default) const {
+NSImage* DefaultThemeProvider::GetNSImageNamed(int id) const {
  return ResourceBundle::GetSharedInstance().
      GetNativeImageNamed(id).ToNSImage();
 }
 
-NSColor* DefaultThemeProvider::GetNSImageColorNamed(int id,
-                                                    bool allow_default) const {
-  NSImage* image = GetNSImageNamed(id, allow_default);
+NSColor* DefaultThemeProvider::GetNSImageColorNamed(int id) const {
+  NSImage* image = GetNSImageNamed(id);
   return [NSColor colorWithPatternImage:image];
 }
 
-NSColor* DefaultThemeProvider::GetNSColor(int id,
-                                          bool allow_default) const {
+NSColor* DefaultThemeProvider::GetNSColor(int id) const {
   return [NSColor redColor];
 }
 
-NSColor* DefaultThemeProvider::GetNSColorTint(int id,
-                                              bool allow_default) const {
+NSColor* DefaultThemeProvider::GetNSColorTint(int id) const {
   return [NSColor redColor];
 }
 
diff --git a/ui/base/ime/character_composer.cc b/ui/base/ime/character_composer.cc
index 9ffb288..0402be2 100644
--- a/ui/base/ime/character_composer.cc
+++ b/ui/base/ime/character_composer.cc
@@ -38,8 +38,10 @@
   uint32 output_char;  // the character to be inserted if the filter is matched.
   bool consume;  // true if the original key event will be consumed.
 } kBlackListedDeadKeys[] = {
+  { GDK_KEY_dead_acute, GDK_KEY_m, GDK_KEY_apostrophe, false },
   { GDK_KEY_dead_acute, GDK_KEY_s, GDK_KEY_apostrophe, false },
   { GDK_KEY_dead_acute, GDK_KEY_t, GDK_KEY_apostrophe, false },
+  { GDK_KEY_dead_acute, GDK_KEY_v, GDK_KEY_apostrophe, false },
   { GDK_KEY_dead_acute, GDK_KEY_dead_acute, GDK_KEY_apostrophe, true },
 };
 
diff --git a/chrome/common/time_format.cc b/ui/base/l10n/time_format.cc
similarity index 98%
rename from chrome/common/time_format.cc
rename to ui/base/l10n/time_format.cc
index 8e19e66..5ba606c 100644
--- a/chrome/common/time_format.cc
+++ b/ui/base/l10n/time_format.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/common/time_format.h"
+#include "ui/base/l10n/time_format.h"
 
 #include <vector>
 
@@ -14,7 +14,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "grit/generated_resources.h"
+#include "grit/ui_strings.h"
 #include "third_party/icu/source/common/unicode/locid.h"
 #include "third_party/icu/source/i18n/unicode/datefmt.h"
 #include "third_party/icu/source/i18n/unicode/plurfmt.h"
@@ -158,8 +158,6 @@
   FORMAT_ELAPSED,
 };
 
-}  // namespace
-
 class TimeFormatter {
   public:
     const std::vector<icu::PluralFormat*>& formatter(FormatType format_type) {
@@ -311,7 +309,7 @@
   return format;
 }
 
-static string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
+string16 FormatTimeImpl(const TimeDelta& delta, FormatType format_type) {
   if (delta.ToInternalValue() < 0) {
     NOTREACHED() << "Negative duration";
     return string16();
@@ -360,6 +358,10 @@
   return result;
 }
 
+}  // namespace
+
+namespace ui {
+
 // static
 string16 TimeFormat::TimeElapsed(const TimeDelta& delta) {
   return FormatTimeImpl(delta, FORMAT_ELAPSED);
@@ -402,3 +404,5 @@
     return l10n_util::GetStringUTF16(IDS_PAST_TIME_YESTERDAY);
   return string16();
 }
+
+}  // namespace ui
diff --git a/chrome/common/time_format.h b/ui/base/l10n/time_format.h
similarity index 91%
rename from chrome/common/time_format.h
rename to ui/base/l10n/time_format.h
index 93ec595..075b698 100644
--- a/chrome/common/time_format.h
+++ b/ui/base/l10n/time_format.h
@@ -2,19 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_COMMON_TIME_FORMAT_H_
-#define CHROME_COMMON_TIME_FORMAT_H_
+#ifndef UI_BASE_L10N_TIME_FORMAT_H_
+#define UI_BASE_L10N_TIME_FORMAT_H_
 
 #include "base/basictypes.h"
 #include "base/strings/string16.h"
+#include "ui/base/ui_export.h"
 
 namespace base {
 class Time;
 class TimeDelta;
 }
 
+namespace ui {
+
 // Methods to format time values as strings.
-class TimeFormat {
+class UI_EXPORT TimeFormat {
  public:
   // TimeElapsed, TimeRemaining and TimeRemainingShort functions:
   // These functions return a localized string of approximate time duration. The
@@ -59,4 +62,6 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(TimeFormat);
 };
 
-#endif  // CHROME_COMMON_TIME_FORMAT_H_
+}  // namespace ui
+
+#endif  // UI_BASE_L10N_TIME_FORMAT_H_
diff --git a/chrome/common/time_format_unittest.cc b/ui/base/l10n/time_format_unittest.cc
similarity index 95%
rename from chrome/common/time_format_unittest.cc
rename to ui/base/l10n/time_format_unittest.cc
index 60c84e7..eaee957 100644
--- a/chrome/common/time_format_unittest.cc
+++ b/ui/base/l10n/time_format_unittest.cc
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/common/time_format.h"
+#include "ui/base/l10n/time_format.h"
 
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/resource/resource_bundle.h"
 
+namespace ui {
 namespace {
 
 using base::TimeDelta;
@@ -68,3 +70,4 @@
 }
 
 }  // namespace
+}  // namespace ui
diff --git a/ui/base/ozone/surface_factory_ozone.cc b/ui/base/ozone/surface_factory_ozone.cc
index a617efe..f082e7d 100644
--- a/ui/base/ozone/surface_factory_ozone.cc
+++ b/ui/base/ozone/surface_factory_ozone.cc
@@ -29,10 +29,6 @@
       const gfx::Rect& bounds) OVERRIDE {
     return false;
   }
-  virtual bool AcceleratedWidgetCanBeResized(
-      gfx::AcceleratedWidget w) OVERRIDE {
-    return false;
-  }
   virtual gfx::VSyncProvider* GetVSyncProvider(
       gfx::AcceleratedWidget w) OVERRIDE {
     return NULL;
diff --git a/ui/base/ozone/surface_factory_ozone.h b/ui/base/ozone/surface_factory_ozone.h
index d98882d..50a9b4b 100644
--- a/ui/base/ozone/surface_factory_ozone.h
+++ b/ui/base/ozone/surface_factory_ozone.h
@@ -60,11 +60,6 @@
       gfx::AcceleratedWidget w,
       const gfx::Rect& bounds) = 0;
 
-  // TODO(rjkroege): keeping the old API for downstream compat asked by
-  // rjkroege; he promised to remove as soon as his implementation gets fixed,
-  // but we should take this function API as deprecated for now.
-  virtual bool AcceleratedWidgetCanBeResized(gfx::AcceleratedWidget w) = 0;
-
   // Returns a gfx::VsyncProvider for the provided AcceleratedWidget. Note
   // that this may be called after we have entered the sandbox so if there are
   // operations (e.g. opening a file descriptor providing vsync events) that
diff --git a/ui/base/strings/ui_strings.grd b/ui/base/strings/ui_strings.grd
index 21d7001..1a243e5 100644
--- a/ui/base/strings/ui_strings.grd
+++ b/ui/base/strings/ui_strings.grd
@@ -206,6 +206,1072 @@
   <release seq="1" allow_pseudo="false">
     <messages fallback_to_english="true">
 
+      <!-- time format -->
+      <message name="IDS_TIME_SECS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_SEC_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_SEC_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_SECS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_SECS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_SECS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_SECS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_SECS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_SECS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_SECS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_SECS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_MINS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_MIN_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_MIN_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_MINS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_MINS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_MINS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_MINS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_MINS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_MINS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_MINS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_MINS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_HOURS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_HOUR_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_HOUR_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_HOURS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_HOURS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_HOURS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_HOURS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_HOURS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_HOURS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_HOURS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_HOURS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_DAYS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_DAY_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_DAY_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_DAYS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_DAYS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_DAYS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DAYS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_DAYS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DAYS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_DAYS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_DAYS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_REMAINING_SECS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs left
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_REMAINING_SEC_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec left
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_REMAINING_SEC_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_REMAINING_SECS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs left
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_REMAINING_SECS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_SECS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs left
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_SECS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_SECS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs left
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_SECS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_REMAINING_SECS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs left
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_REMAINING_SECS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_REMAINING_MINS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins left
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_REMAINING_MIN_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min left
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_REMAINING_MIN_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_REMAINING_MINS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins left
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_REMAINING_MINS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_MINS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins left
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_MINS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_MINS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins left
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_MINS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_REMAINING_MINS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins left
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_REMAINING_MINS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_REMAINING_LONG_MINS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes left
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute left
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MIN_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes left
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_LONG_MINS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes left
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_LONG_MINS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes left
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_REMAINING_LONG_MINS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes left
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_REMAINING_LONG_MINS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_REMAINING_HOURS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours left
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_REMAINING_HOUR_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour left
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_REMAINING_HOUR_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_REMAINING_HOURS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours left
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_HOURS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours left
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_HOURS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours left
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_REMAINING_HOURS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours left
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_REMAINING_HOURS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_REMAINING_DAYS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days left
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_REMAINING_DAY_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day left
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_REMAINING_DAY_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_REMAINING_DAYS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days left
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_DAYS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days left
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_REMAINING_DAYS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days left
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_REMAINING_DAYS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days left
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_REMAINING_DAYS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_DURATION_LONG_SECS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> seconds
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> second
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_SEC_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_DURATION_LONG_SECS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> seconds
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_DURATION_LONG_SECS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> seconds
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_DURATION_LONG_SECS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> seconds
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_DURATION_LONG_SECS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> seconds
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_SECS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_DURATION_LONG_MINS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> minutes
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> minute
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_MIN_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_DURATION_LONG_MINS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> minutes
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_DURATION_LONG_MINS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> minutes
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_DURATION_LONG_MINS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> minutes
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_DURATION_LONG_MINS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> minutes
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_DURATION_LONG_MINS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_TIME_ELAPSED_SECS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> secs ago
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_ELAPSED_SEC_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> sec ago
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_SEC_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_ELAPSED_SECS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> secs ago
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_SECS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> secs ago
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_SECS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> secs ago
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_ELAPSED_SECS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> secs ago
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_ELAPSED_SECS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_ELAPSED_MINS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> mins ago
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_ELAPSED_MIN_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> min ago
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_MIN_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_ELAPSED_MINS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> mins ago
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_MINS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> mins ago
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_MINS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> mins ago
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_ELAPSED_MINS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> mins ago
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_ELAPSED_MINS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_ELAPSED_HOURS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> hours ago
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> hour ago
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_HOUR_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_ELAPSED_HOURS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> hours ago
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_HOURS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> hours ago
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_HOURS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> hours ago
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_ELAPSED_HOURS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> hours ago
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_ELAPSED_HOURS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+
+      <message name="IDS_TIME_ELAPSED_DAYS_DEFAULT"
+               desc="This is necessary for every language. This is the default for all the numbers NOT covered by special cases (singular, dual/two, few, many) some languages need. For CJK, Vietnamese, Turkish and Kannada, this is the only string necessary. For languages with singular-plural distinction, this is the generic plural. For Lithuanian, NUMBER_DEFAULT is 11 .. 19.">
+        <ph name="NUMBER_DEFAULT"><ex>37</ex>#</ph> days ago
+      </message>
+
+      <if expr="lang not in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message name="IDS_TIME_ELAPSED_DAY_SINGULAR"
+               desc="NUMBER_ONE is one or one-like numbers : 1 (many European and most Indian languages), 1 and 0 (French, Brazilian Portuguese and Hindi), 1,21,31, .. (Russian, Ukrainian, Croatian, Serbian, Latvian, Lithuanian), or 1, 101, 201, .. (Slovenian). Do NOT translate this for CJK, Vietnamese, Turkish and Kannada">
+        <ph name="NUMBER_ONE"><ex>1</ex>#</ph> day ago
+      </message>
+      </if>
+      <if expr="lang in ['zh-CN', 'zh-TW', 'ko', 'ja', 'vi', 'tr', 'kn']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_DAY_SINGULAR"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ar', 'ro', 'lv']">
+      <message name="IDS_TIME_ELAPSED_DAYS_ZERO"
+               desc="NUMBER_ZERO is 0 (Arabic, Latvian) or 0, 2..19, 101..119, ... (Romanian). For other languages, do NOT translate.">
+        <ph name="NUMBER_ZERO"><ex>0</ex>#</ph> days ago
+      </message>
+      </if>
+      <if expr="lang not in ['ar', 'ro', 'lv']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_ZERO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang in ['ga', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_DAYS_TWO"
+               desc="NUMBER_TWO is two or two-like/dual numbers :  2 (Arabic and Irish) or  2, 102, 202 ... (Slovenian). For other languages, do NOT translated.">
+        <ph name="NUMBER_TWO"><ex>2</ex>#</ph> days ago
+      </message>
+      </if>
+      <if expr="lang not in ['ga', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_TWO"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang  in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message name="IDS_TIME_ELAPSED_DAYS_FEW"
+               desc="NUMBER_FEW is few or few-like numbers in Arabic, Russian, Polish, Croatian, Serbian, Ukrainian, Czech, Slovak, Slovenian, Latvian. For other languages, do NOT translate.">
+        <ph name="NUMBER_FEW"><ex>3</ex>#</ph> days ago
+      </message>
+      </if>
+      <if expr="lang not in ['ru', 'lt', 'hr', 'uk', 'cs', 'sk', 'pl', 'sl', 'ar']">
+      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_FEW"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <if expr="lang == 'ar'">
+      <message name="IDS_TIME_ELAPSED_DAYS_MANY"
+               desc="NUMBER_MANY is 11 through 99 in Arabic. For all other languages, do NOT translate.">
+        <ph name="NUMBER_MANY"><ex>23</ex>#</ph> days ago
+      </message>
+      </if>
+      <if expr="lang != 'ar'">
+      <message translateable="false" name="IDS_TIME_ELAPSED_DAYS_MANY"
+               desc="">
+        NA
+      </message>
+      </if>
+
+      <message name="IDS_PAST_TIME_TODAY" desc="Relative day today">
+        Today
+      </message>
+      <message name="IDS_PAST_TIME_YESTERDAY" desc="Relative day yesterday">
+        Yesterday
+      </message>
+
       <!-- Menus -->
       <message name="IDS_APP_MENU_EMPTY_SUBMENU" desc="Used when a submenu has no entries">
         (empty)
@@ -464,9 +1530,16 @@
       <message name="IDS_MESSAGE_CENTER_SETTINGS_GO_BACK_BUTTON_TOOLTIP" desc="The tooltip on back button that returns from settings to the notification list.">
         Go back to notifications
       </message>
-      <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog.">
-        Allow notifications from the following:
-      </message>
+      <if expr="is_macosx">
+        <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog.">
+          Allow notifications from the following:
+        </message>
+      </if>
+      <if expr="not is_macosx">
+        <message name="IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION" desc="The label to describe the settings dialog.">
+          Manage notifications per profile:
+        </message>
+      </if>
       <message name="IDS_MESSAGE_CENTER_SETTINGS" desc="The menu entry or button for visiting the appropriate settings page.">
         Settings...
       </message>
diff --git a/ui/base/theme_provider.h b/ui/base/theme_provider.h
index 007094f..22f70a0 100644
--- a/ui/base/theme_provider.h
+++ b/ui/base/theme_provider.h
@@ -78,29 +78,17 @@
 
 #if defined(OS_MACOSX) && !defined(TOOLKIT_VIEWS)
   // Gets the NSImage with the specified |id|.
-  //
-  // The bitmap is not assumed to exist. If a theme does not provide an image,
-  // if |allow_default| is true, then the default image will be returned, else
-  // this function will return nil.
-  virtual NSImage* GetNSImageNamed(int id, bool allow_default) const = 0;
+  virtual NSImage* GetNSImageNamed(int id) const = 0;
 
   // Gets the NSImage that GetNSImageNamed (above) would return, but returns it
   // as a pattern color.
-  virtual NSColor* GetNSImageColorNamed(int id, bool allow_default) const = 0;
+  virtual NSColor* GetNSImageColorNamed(int id) const = 0;
 
   // Gets the NSColor with the specified |id|.
-  //
-  // The color is not assumed to exist. If a theme does not provide an color, if
-  // |allow_default| is true, then the default color will be returned, else this
-  // function will return nil.
-  virtual NSColor* GetNSColor(int id, bool allow_default) const = 0;
+  virtual NSColor* GetNSColor(int id) const = 0;
 
   // Gets the NSColor for tinting with the specified |id|.
-  //
-  // The tint is not assumed to exist. If a theme does not provide a tint with
-  // that id, if |allow_default| is true, then the default tint will be
-  // returned, else this function will return nil.
-  virtual NSColor* GetNSColorTint(int id, bool allow_default) const = 0;
+  virtual NSColor* GetNSColorTint(int id) const = 0;
 
   // Gets the NSGradient with the specified |id|.
   virtual NSGradient* GetNSGradient(int id) const = 0;
diff --git a/ui/gl/android/surface_texture_bridge.cc b/ui/gl/android/surface_texture_bridge.cc
index 19ce2a7..c4206a9 100644
--- a/ui/gl/android/surface_texture_bridge.cc
+++ b/ui/gl/android/surface_texture_bridge.cc
@@ -43,8 +43,7 @@
 
 namespace gfx {
 
-SurfaceTextureBridge::SurfaceTextureBridge(int texture_id)
-    : texture_id_(texture_id) {
+SurfaceTextureBridge::SurfaceTextureBridge(int texture_id) {
   JNIEnv* env = AttachCurrentThread();
   CHECK(env);
   RegisterNativesIfNeeded(env);
diff --git a/ui/gl/android/surface_texture_bridge.h b/ui/gl/android/surface_texture_bridge.h
index f3f3bcf..fc7fb54 100644
--- a/ui/gl/android/surface_texture_bridge.h
+++ b/ui/gl/android/surface_texture_bridge.h
@@ -53,10 +53,6 @@
   // by calling ANativeWindow_release().
   ANativeWindow* CreateSurface();
 
-  int texture_id() const {
-    return texture_id_;
-  }
-
   const base::android::JavaRef<jobject>& j_surface_texture() const {
     return j_surface_texture_;
   }
@@ -65,8 +61,6 @@
   friend class base::RefCountedThreadSafe<SurfaceTextureBridge>;
   ~SurfaceTextureBridge();
 
-  const int texture_id_;
-
   // Java SurfaceTexture instance.
   base::android::ScopedJavaGlobalRef<jobject> j_surface_texture_;
 
diff --git a/ui/message_center/cocoa/settings_controller.h b/ui/message_center/cocoa/settings_controller.h
index d81b99b..380ae14 100644
--- a/ui/message_center/cocoa/settings_controller.h
+++ b/ui/message_center/cocoa/settings_controller.h
@@ -26,6 +26,7 @@
   // Overridden from NotifierSettingsObserver:
   virtual void UpdateIconImage(const NotifierId& notifier_id,
                                const gfx::Image& icon) OVERRIDE;
+  virtual void NotifierGroupChanged() OVERRIDE;
 
  private:
   MCSettingsController* settings_controller_;  // weak, owns this
diff --git a/ui/message_center/cocoa/settings_controller.mm b/ui/message_center/cocoa/settings_controller.mm
index 45c66ea..f34f9f0 100644
--- a/ui/message_center/cocoa/settings_controller.mm
+++ b/ui/message_center/cocoa/settings_controller.mm
@@ -110,6 +110,8 @@
   [settings_controller_ setIcon:icon.AsNSImage() forNotifierId:notifier_id];
 }
 
+void NotifierSettingsObserverMac::NotifierGroupChanged() {}
+
 }  // namespace message_center
 
 @implementation MCSettingsController
diff --git a/ui/message_center/fake_notifier_settings_provider.cc b/ui/message_center/fake_notifier_settings_provider.cc
index 0695d08..66b193b 100644
--- a/ui/message_center/fake_notifier_settings_provider.cc
+++ b/ui/message_center/fake_notifier_settings_provider.cc
@@ -4,14 +4,36 @@
 
 #include "ui/message_center/fake_notifier_settings_provider.h"
 
+#include "base/strings/utf_string_conversions.h"
+#include "ui/gfx/image/image.h"
+
 namespace message_center {
 
 FakeNotifierSettingsProvider::FakeNotifierSettingsProvider(
     const std::vector<Notifier*>& notifiers)
-    : notifiers_(notifiers), closed_called_count_(0) {}
+    : notifiers_(notifiers),
+      notifier_group_(gfx::Image(),
+                      UTF8ToUTF16("Fake name"),
+                      UTF8ToUTF16("fake@email.com"),
+                      true),
+      closed_called_count_(0) {}
 
 FakeNotifierSettingsProvider::~FakeNotifierSettingsProvider() {}
 
+size_t FakeNotifierSettingsProvider::GetNotifierGroupCount() const { return 1; }
+
+const message_center::NotifierGroup&
+FakeNotifierSettingsProvider::GetNotifierGroupAt(size_t index) const {
+  return notifier_group_;
+}
+
+void FakeNotifierSettingsProvider::SwitchToNotifierGroup(size_t index) {}
+
+const message_center::NotifierGroup&
+FakeNotifierSettingsProvider::GetActiveNotifierGroup() const {
+  return notifier_group_;
+}
+
 void FakeNotifierSettingsProvider::GetNotifierList(
     std::vector<Notifier*>* notifiers) {
   notifiers->clear();
diff --git a/ui/message_center/fake_notifier_settings_provider.h b/ui/message_center/fake_notifier_settings_provider.h
index 47a3549..f2c5cd7 100644
--- a/ui/message_center/fake_notifier_settings_provider.h
+++ b/ui/message_center/fake_notifier_settings_provider.h
@@ -14,7 +14,14 @@
 class FakeNotifierSettingsProvider : public NotifierSettingsProvider {
  public:
   FakeNotifierSettingsProvider(const std::vector<Notifier*>& notifiers);
-  ~FakeNotifierSettingsProvider();
+  virtual ~FakeNotifierSettingsProvider();
+
+  virtual size_t GetNotifierGroupCount() const OVERRIDE;
+  virtual const message_center::NotifierGroup& GetNotifierGroupAt(
+      size_t index) const OVERRIDE;
+  virtual void SwitchToNotifierGroup(size_t index) OVERRIDE;
+  virtual const message_center::NotifierGroup& GetActiveNotifierGroup() const
+      OVERRIDE;
 
   virtual void GetNotifierList(std::vector<Notifier*>* notifiers) OVERRIDE;
 
@@ -31,6 +38,7 @@
  private:
   std::vector<Notifier*> notifiers_;
   std::map<const Notifier*, bool> enabled_;
+  const NotifierGroup notifier_group_;
   int closed_called_count_;
 };
 
diff --git a/ui/message_center/message_center.gyp b/ui/message_center/message_center.gyp
index eac6938..dc1f1ab 100644
--- a/ui/message_center/message_center.gyp
+++ b/ui/message_center/message_center.gyp
@@ -70,6 +70,8 @@
         'views/message_bubble_base.h',
         'views/message_center_bubble.cc',
         'views/message_center_bubble.h',
+        'views/message_center_button_bar.cc',
+        'views/message_center_button_bar.h',
         'views/message_center_view.cc',
         'views/message_center_view.h',
         'views/message_popup_collection.cc',
diff --git a/ui/message_center/notifier_settings.cc b/ui/message_center/notifier_settings.cc
index 85c6097..4355b94 100644
--- a/ui/message_center/notifier_settings.cc
+++ b/ui/message_center/notifier_settings.cc
@@ -50,8 +50,15 @@
 Notifier::~Notifier() {
 }
 
-std::string ToString(
-    NotifierId::SystemComponentNotifierType type) {
+NotifierGroup::NotifierGroup(const gfx::Image& icon,
+                             const string16& name,
+                             const string16& login_info,
+                             size_t index)
+    : icon(icon), name(name), login_info(login_info), index(index) {}
+
+NotifierGroup::~NotifierGroup() {}
+
+std::string ToString(NotifierId::SystemComponentNotifierType type) {
   switch (type) {
     case NotifierId::SCREENSHOT:
       return "screenshot";
diff --git a/ui/message_center/notifier_settings.h b/ui/message_center/notifier_settings.h
index c494048..05fc7fe 100644
--- a/ui/message_center/notifier_settings.h
+++ b/ui/message_center/notifier_settings.h
@@ -84,6 +84,30 @@
   DISALLOW_COPY_AND_ASSIGN(Notifier);
 };
 
+struct MESSAGE_CENTER_EXPORT NotifierGroup {
+  NotifierGroup(const gfx::Image& icon,
+                const string16& name,
+                const string16& login_info,
+                size_t index);
+  ~NotifierGroup();
+
+  // Icon of a notifier group.
+  const gfx::Image icon;
+
+  // Display name of a notifier group.
+  const string16 name;
+
+  // More display information about the notifier group.
+  string16 login_info;
+
+  // Unique identifier for the notifier group so that they can be selected in
+  // the UI.
+  const size_t index;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NotifierGroup);
+};
+
 MESSAGE_CENTER_EXPORT std::string ToString(
     NotifierId::SystemComponentNotifierType type);
 MESSAGE_CENTER_EXPORT NotifierId::SystemComponentNotifierType
@@ -96,16 +120,36 @@
   // Called when an icon in the controller has been updated.
   virtual void UpdateIconImage(const NotifierId& notifier_id,
                                const gfx::Image& icon) = 0;
+
+  // Called when any change happens to the set of notifier groups.
+  virtual void NotifierGroupChanged() = 0;
 };
 
 // A class used by NotifierSettingsView to integrate with a setting system
 // for the clients of this module.
 class MESSAGE_CENTER_EXPORT NotifierSettingsProvider {
  public:
+  virtual ~NotifierSettingsProvider() {};
+
   // Sets the delegate.
   virtual void AddObserver(NotifierSettingsObserver* observer) = 0;
   virtual void RemoveObserver(NotifierSettingsObserver* observer) = 0;
 
+  // Returns the number of notifier groups available.
+  virtual size_t GetNotifierGroupCount() const = 0;
+
+  // Requests the model for a particular notifier group.
+  virtual const message_center::NotifierGroup& GetNotifierGroupAt(
+      size_t index) const = 0;
+
+  // Informs the settings provider that further requests to GetNotifierList
+  // should return notifiers for the specified notifier group.
+  virtual void SwitchToNotifierGroup(size_t index) = 0;
+
+  // Requests the currently active notifier group.
+  virtual const message_center::NotifierGroup& GetActiveNotifierGroup()
+      const = 0;
+
   // Collects the current notifier list and fills to |notifiers|. Caller takes
   // the ownership of the elements of |notifiers|.
   virtual void GetNotifierList(std::vector<Notifier*>* notifiers) = 0;
diff --git a/ui/message_center/views/message_center_button_bar.cc b/ui/message_center/views/message_center_button_bar.cc
new file mode 100644
index 0000000..b436bf3
--- /dev/null
+++ b/ui/message_center/views/message_center_button_bar.cc
@@ -0,0 +1,210 @@
+// 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 "ui/message_center/views/message_center_button_bar.h"
+
+#include "grit/ui_resources.h"
+#include "grit/ui_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/text_constants.h"
+#include "ui/message_center/message_center.h"
+#include "ui/message_center/message_center_style.h"
+#include "ui/message_center/notifier_settings.h"
+#include "ui/message_center/views/message_center_view.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/menu_button.h"
+#include "ui/views/controls/button/menu_button_listener.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/menu_runner.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/grid_layout.h"
+
+namespace message_center {
+
+namespace {
+const int kButtonSize = 40;
+const int kChevronMargin = 4;
+const int kFooterLeftMargin = 17;
+const int kFooterRightMargin = 14;
+}  // namespace
+
+// NotificationCenterButton ////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+class NotificationCenterButton : public views::ToggleImageButton {
+ public:
+  NotificationCenterButton(views::ButtonListener* listener,
+                           int normal_id,
+                           int hover_id,
+                           int pressed_id,
+                           int text_id);
+
+ protected:
+  // Overridden from views::View:
+  virtual gfx::Size GetPreferredSize() OVERRIDE;
+  virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NotificationCenterButton);
+};
+
+NotificationCenterButton::NotificationCenterButton(
+    views::ButtonListener* listener,
+    int normal_id,
+    int hover_id,
+    int pressed_id,
+    int text_id)
+    : views::ToggleImageButton(listener) {
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_id));
+  SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hover_id));
+  SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pressed_id));
+  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
+                    views::ImageButton::ALIGN_MIDDLE);
+  SetTooltipText(resource_bundle.GetLocalizedString(text_id));
+  set_focusable(true);
+  set_request_focus_on_press(false);
+}
+
+gfx::Size NotificationCenterButton::GetPreferredSize() {
+  return gfx::Size(kButtonSize, kButtonSize);
+}
+
+void NotificationCenterButton::OnPaintFocusBorder(gfx::Canvas* canvas) {
+  if (HasFocus() && (focusable() || IsAccessibilityFocusable())) {
+    canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3),
+                     kFocusBorderColor);
+  }
+}
+
+// MessageCenterButtonBar /////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+MessageCenterButtonBar::MessageCenterButtonBar(
+    MessageCenterView* message_center_view,
+    MessageCenter* message_center,
+    NotifierSettingsProvider* notifier_settings_provider,
+    bool settings_initially_visible)
+    : message_center_view_(message_center_view),
+      message_center_(message_center),
+      close_all_button_(NULL),
+      quiet_mode_button_(NULL) {
+  if (get_use_acceleration_when_possible())
+    SetPaintToLayer(true);
+  set_background(
+      views::Background::CreateSolidBackground(kMessageCenterBackgroundColor));
+
+  views::Label* notification_label = new views::Label(
+      l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_FOOTER_TITLE));
+  notification_label->SetAutoColorReadabilityEnabled(false);
+  notification_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  notification_label->SetEnabledColor(kRegularTextColor);
+  AddChildView(notification_label);
+
+  views::View* button_container = new views::View;
+  button_container->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
+  quiet_mode_button_ = new NotificationCenterButton(
+      this,
+      IDR_NOTIFICATION_DO_NOT_DISTURB,
+      IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER,
+      IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED,
+      IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP);
+  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
+  quiet_mode_button_->SetToggledImage(
+      views::Button::STATE_NORMAL,
+      resource_bundle.GetImageSkiaNamed(
+          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
+  quiet_mode_button_->SetToggledImage(
+      views::Button::STATE_HOVERED,
+      resource_bundle.GetImageSkiaNamed(
+          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
+  quiet_mode_button_->SetToggledImage(
+      views::Button::STATE_PRESSED,
+      resource_bundle.GetImageSkiaNamed(
+          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
+  quiet_mode_button_->SetToggled(message_center->IsQuietMode());
+  button_container->AddChildView(quiet_mode_button_);
+
+  close_all_button_ =
+      new NotificationCenterButton(this,
+                                   IDR_NOTIFICATION_CLEAR_ALL,
+                                   IDR_NOTIFICATION_CLEAR_ALL_HOVER,
+                                   IDR_NOTIFICATION_CLEAR_ALL_PRESSED,
+                                   IDS_MESSAGE_CENTER_CLEAR_ALL);
+  button_container->AddChildView(close_all_button_);
+  settings_button_ =
+      new NotificationCenterButton(this,
+                                   IDR_NOTIFICATION_SETTINGS,
+                                   IDR_NOTIFICATION_SETTINGS_HOVER,
+                                   IDR_NOTIFICATION_SETTINGS_PRESSED,
+                                   IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL);
+  button_container->AddChildView(settings_button_);
+
+  gfx::ImageSkia* settings_image =
+      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+          IDR_NOTIFICATION_SETTINGS);
+  int image_margin = std::max(0, (kButtonSize - settings_image->width()) / 2);
+  views::GridLayout* layout = new views::GridLayout(this);
+  SetLayoutManager(layout);
+  layout->SetInsets(
+      0, kFooterLeftMargin, 0, std::max(0, kFooterRightMargin - image_margin));
+  views::ColumnSet* column = layout->AddColumnSet(0);
+  column->AddColumn(views::GridLayout::FILL,
+                    views::GridLayout::FILL,
+                    1.0f,
+                    views::GridLayout::USE_PREF,
+                    0,
+                    0);
+  column->AddColumn(views::GridLayout::LEADING,
+                    views::GridLayout::FILL,
+                    0,
+                    views::GridLayout::USE_PREF,
+                    0,
+                    0);
+  layout->StartRow(0, 0);
+  layout->AddView(notification_label);
+  layout->AddView(button_container);
+}
+
+MessageCenterButtonBar::~MessageCenterButtonBar() {}
+
+void MessageCenterButtonBar::SetAllButtonsEnabled(bool enabled) {
+  if (close_all_button_)
+    close_all_button_->SetEnabled(enabled);
+  settings_button_->SetEnabled(enabled);
+  quiet_mode_button_->SetEnabled(enabled);
+}
+
+void MessageCenterButtonBar::SetCloseAllButtonVisible(bool visible) {
+  if (close_all_button_)
+    close_all_button_->SetVisible(visible);
+}
+
+void MessageCenterButtonBar::ChildVisibilityChanged(views::View* child) {
+  InvalidateLayout();
+}
+
+void MessageCenterButtonBar::ButtonPressed(views::Button* sender,
+                                           const ui::Event& event) {
+  if (sender == close_all_button_) {
+    message_center_view()->ClearAllNotifications();
+  } else if (sender == settings_button_) {
+    MessageCenterView* center_view = message_center_view();
+    center_view->SetSettingsVisible(!center_view->settings_visible());
+  } else if (sender == quiet_mode_button_) {
+    if (message_center()->IsQuietMode())
+      message_center()->SetQuietMode(false);
+    else
+      message_center()->EnterQuietModeWithExpire(base::TimeDelta::FromDays(1));
+    quiet_mode_button_->SetToggled(message_center()->IsQuietMode());
+  } else {
+    NOTREACHED();
+  }
+}
+
+}  // namespace message_center
diff --git a/ui/message_center/views/message_center_button_bar.h b/ui/message_center/views/message_center_button_bar.h
new file mode 100644
index 0000000..72b30c9
--- /dev/null
+++ b/ui/message_center/views/message_center_button_bar.h
@@ -0,0 +1,68 @@
+// 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 UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_
+#define UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_
+
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace views {
+class Label;
+}
+
+namespace message_center {
+
+class ButtonBarSettingsLabel;
+class MessageCenter;
+class MessageCenterTray;
+class MessageCenterView;
+class NotificationCenterButton;
+class NotifierSettingsProvider;
+
+// MessageCenterButtonBar is the class that shows the content outside the main
+// notification area - the label (or NotifierGroup switcher) and the buttons.
+class MessageCenterButtonBar : public views::View,
+                               public views::ButtonListener {
+ public:
+  MessageCenterButtonBar(MessageCenterView* message_center_view,
+                         MessageCenter* message_center,
+                         NotifierSettingsProvider* notifier_settings_provider,
+                         bool settings_initially_visible);
+  virtual ~MessageCenterButtonBar();
+
+  // Enables or disables all of the buttons in the center.  This is used to
+  // prevent user clicks during the close-all animation.
+  virtual void SetAllButtonsEnabled(bool enabled);
+
+  // Sometimes we shouldn't see the close-all button.
+  void SetCloseAllButtonVisible(bool visible);
+
+ private:
+  // Overridden from views::View:
+  virtual void ChildVisibilityChanged(views::View* child) OVERRIDE;
+
+  // Overridden from views::ButtonListener:
+  virtual void ButtonPressed(views::Button* sender,
+                             const ui::Event& event) OVERRIDE;
+
+  MessageCenterView* message_center_view() const {
+    return message_center_view_;
+  }
+  MessageCenter* message_center() const { return message_center_; }
+
+  MessageCenterView* message_center_view_;  // Weak reference.
+  MessageCenter* message_center_;           // Weak reference.
+
+  // Sub-views of the button bar.
+  views::Button* close_all_button_;
+  NotificationCenterButton* settings_button_;
+  NotificationCenterButton* quiet_mode_button_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageCenterButtonBar);
+};
+
+}  // namespace message_center
+
+#endif  // UI_MESSAGE_CENTER_VIEWS_MESSAGE_CENTER_BUTTON_BAR_H_
diff --git a/ui/message_center/views/message_center_view.cc b/ui/message_center/views/message_center_view.cc
index ee7ac74..9f0d2fd 100644
--- a/ui/message_center/views/message_center_view.cc
+++ b/ui/message_center/views/message_center_view.cc
@@ -10,22 +10,17 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
-#include "grit/ui_resources.h"
 #include "grit/ui_strings.h"
 #include "ui/base/animation/multi_animation.h"
 #include "ui/base/animation/slide_animation.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/insets.h"
-#include "ui/gfx/point.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
-#include "ui/gfx/text_constants.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_tray.h"
-#include "ui/message_center/message_center_util.h"
+#include "ui/message_center/views/message_center_button_bar.h"
 #include "ui/message_center/views/message_view.h"
 #include "ui/message_center/views/notification_view.h"
 #include "ui/message_center/views/notifier_settings_view.h"
@@ -34,238 +29,30 @@
 #include "ui/views/background.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/button.h"
-#include "ui/views/controls/button/label_button.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
 #include "ui/views/layout/box_layout.h"
-#include "ui/views/layout/grid_layout.h"
-#include "ui/views/painter.h"
 #include "ui/views/widget/widget.h"
 
 namespace message_center {
 
 namespace {
 
-const int kMinScrollViewHeight = 100;
-const int kFooterLeftMargin = 17;
-const int kFooterRightMargin = 14;
-const int kButtonSize = 40;
-const SkColor kNoNotificationsTextColor = SkColorSetRGB(0xb4, 0xb4, 0xb4);
 const SkColor kBorderDarkColor = SkColorSetRGB(0xaa, 0xaa, 0xaa);
-const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0);
 const SkColor kButtonTextHighlightColor = SkColorSetRGB(0x2a, 0x2a, 0x2a);
 const SkColor kButtonTextHoverColor = SkColorSetRGB(0x2a, 0x2a, 0x2a);
+const SkColor kNoNotificationsTextColor = SkColorSetRGB(0xb4, 0xb4, 0xb4);
+const SkColor kTransparentColor = SkColorSetARGB(0, 0, 0, 0);
 const int kAnimateClearingNextNotificationDelayMS = 40;
+const int kButtonBarBorderThickness = 1;
+const int kMinScrollViewHeight = 100;
 
-static const int kDefaultFrameRateHz = 60;
 static const int kDefaultAnimationDurationMs = 120;
+static const int kDefaultFrameRateHz = 60;
 
 }  // namespace
 
-// NotificationCenterButton ////////////////////////////////////////////////////
-
-class NotificationCenterButton : public views::ToggleImageButton {
- public:
-  NotificationCenterButton(views::ButtonListener* listener,
-                           int normal_id,
-                           int hover_id,
-                           int pressed_id,
-                           int text_id);
-
- protected:
-  // Overridden from views::View:
-  virtual gfx::Size GetPreferredSize() OVERRIDE;
-  virtual void OnPaintFocusBorder(gfx::Canvas* canvas) OVERRIDE;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(NotificationCenterButton);
-};
-
-NotificationCenterButton::NotificationCenterButton(
-    views::ButtonListener* listener,
-    int normal_id,
-    int hover_id,
-    int pressed_id,
-    int text_id)
-    : views::ToggleImageButton(listener) {
-  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
-  SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_id));
-  SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hover_id));
-  SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pressed_id));
-  SetImageAlignment(views::ImageButton::ALIGN_CENTER,
-                    views::ImageButton::ALIGN_MIDDLE);
-  SetTooltipText(resource_bundle.GetLocalizedString(text_id));
-  set_focusable(true);
-  set_request_focus_on_press(false);
-}
-
-gfx::Size NotificationCenterButton::GetPreferredSize() {
-  return gfx::Size(kButtonSize, kButtonSize);
-}
-
-void NotificationCenterButton::OnPaintFocusBorder(gfx::Canvas* canvas) {
-  if (HasFocus() && (focusable() || IsAccessibilityFocusable())) {
-    canvas->DrawRect(gfx::Rect(2, 1, width() - 4, height() - 3),
-                     kFocusBorderColor);
-  }
-}
-
-// MessageCenterButtonBar //////////////////////////////////////////////////
-
-class MessageCenterButtonBar : public views::View,
-                               public views::ButtonListener {
- public:
-  MessageCenterButtonBar(MessageCenterView* message_center_view,
-                         MessageCenter* message_center);
-  virtual ~MessageCenterButtonBar();
-
-  virtual void SetAllButtonsEnabled(bool enabled);
-  void SetCloseAllVisible(bool visible);
-
- private:
-  // Overridden from views::View:
-  virtual void ChildVisibilityChanged(views::View* child) OVERRIDE;
-
-  // Overridden from views::ButtonListener:
-  virtual void ButtonPressed(views::Button* sender, const ui::Event& event)
-      OVERRIDE;
-
-  MessageCenterView* message_center_view() const {
-    return message_center_view_;
-  }
-  MessageCenter* message_center() const { return message_center_; }
-  MessageCenterTray* tray() const { return tray_; }
-  views::Button* close_all_button() const { return close_all_button_; }
-  void set_close_all_button(views::Button* button) {
-    close_all_button_ = button;
-  }
-
-  MessageCenterView* message_center_view_;  // Weak reference.
-  MessageCenter* message_center_;  // Weak reference.
-  MessageCenterTray* tray_;  // Weak reference.
-  views::Button* close_all_button_;
-  NotificationCenterButton* settings_button_;
-  NotificationCenterButton* quiet_mode_button_;
-
-  DISALLOW_COPY_AND_ASSIGN(MessageCenterButtonBar);
-};
-
-MessageCenterButtonBar::MessageCenterButtonBar(
-    MessageCenterView* message_center_view,
-    MessageCenter* message_center)
-    : message_center_view_(message_center_view),
-      message_center_(message_center),
-      close_all_button_(NULL) {
-  if (get_use_acceleration_when_possible())
-    SetPaintToLayer(true);
-  set_background(views::Background::CreateSolidBackground(
-      kMessageCenterBackgroundColor));
-
-  views::Label* notification_label = new views::Label(l10n_util::GetStringUTF16(
-      IDS_MESSAGE_CENTER_FOOTER_TITLE));
-  notification_label->SetAutoColorReadabilityEnabled(false);
-  notification_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  notification_label->SetEnabledColor(kRegularTextColor);
-  AddChildView(notification_label);
-
-  views::View* button_container = new views::View;
-  button_container->SetLayoutManager(
-      new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0));
-  quiet_mode_button_ = new NotificationCenterButton(
-      this,
-      IDR_NOTIFICATION_DO_NOT_DISTURB,
-      IDR_NOTIFICATION_DO_NOT_DISTURB_HOVER,
-      IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED,
-      IDS_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP);
-  ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
-  quiet_mode_button_->SetToggledImage(
-      views::Button::STATE_NORMAL,
-      resource_bundle.GetImageSkiaNamed(
-          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
-  quiet_mode_button_->SetToggledImage(
-      views::Button::STATE_HOVERED,
-      resource_bundle.GetImageSkiaNamed(
-          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
-  quiet_mode_button_->SetToggledImage(
-      views::Button::STATE_PRESSED,
-      resource_bundle.GetImageSkiaNamed(
-          IDR_NOTIFICATION_DO_NOT_DISTURB_PRESSED));
-  quiet_mode_button_->SetToggled(message_center->IsQuietMode());
-  button_container->AddChildView(quiet_mode_button_);
-
-  NotificationCenterButton* close_all_button = new NotificationCenterButton(
-      this,
-      IDR_NOTIFICATION_CLEAR_ALL,
-      IDR_NOTIFICATION_CLEAR_ALL_HOVER,
-      IDR_NOTIFICATION_CLEAR_ALL_PRESSED,
-      IDS_MESSAGE_CENTER_CLEAR_ALL);
-  button_container->AddChildView(close_all_button);
-  set_close_all_button(close_all_button);
-  settings_button_ = new NotificationCenterButton(
-      this,
-      IDR_NOTIFICATION_SETTINGS,
-      IDR_NOTIFICATION_SETTINGS_HOVER,
-      IDR_NOTIFICATION_SETTINGS_PRESSED,
-      IDS_MESSAGE_CENTER_SETTINGS_BUTTON_LABEL);
-  button_container->AddChildView(settings_button_);
-
-  gfx::ImageSkia* settings_image =
-      ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-          IDR_NOTIFICATION_SETTINGS);
-  int image_margin = std::max(0, (kButtonSize - settings_image->width()) / 2);
-  views::GridLayout* layout = new views::GridLayout(this);
-  SetLayoutManager(layout);
-  layout->SetInsets(
-      0, kFooterLeftMargin, 0, std::max(0, kFooterRightMargin - image_margin));
-  views::ColumnSet* column = layout->AddColumnSet(0);
-  column->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL,
-                    1.0f, views::GridLayout::USE_PREF, 0, 0);
-  column->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL,
-                    0, views::GridLayout::USE_PREF, 0, 0);
-  layout->StartRow(0, 0);
-  layout->AddView(notification_label);
-  layout->AddView(button_container);
-}
-
-MessageCenterButtonBar::~MessageCenterButtonBar() {}
-
-void MessageCenterButtonBar::SetAllButtonsEnabled(bool enabled) {
-  if (close_all_button_)
-    close_all_button_->SetEnabled(enabled);
-  settings_button_->SetEnabled(enabled);
-  quiet_mode_button_->SetEnabled(enabled);
-}
-
-void MessageCenterButtonBar::SetCloseAllVisible(bool visible) {
-  if (close_all_button_)
-    close_all_button_->SetVisible(visible);
-}
-
-// Overridden from views::View:
-void MessageCenterButtonBar::ChildVisibilityChanged(views::View* child) {
-  InvalidateLayout();
-}
-
-// Overridden from views::ButtonListener:
-void MessageCenterButtonBar::ButtonPressed(views::Button* sender,
-                                           const ui::Event& event) {
-  if (sender == close_all_button()) {
-    message_center_view()->ClearAllNotifications();
-  } else if (sender == settings_button_) {
-    MessageCenterView* center_view = static_cast<MessageCenterView*>(parent());
-    center_view->SetSettingsVisible(!center_view->settings_visible());
-  } else if (sender == quiet_mode_button_) {
-    if (message_center()->IsQuietMode())
-      message_center()->SetQuietMode(false);
-    else
-      message_center()->EnterQuietModeWithExpire(base::TimeDelta::FromDays(1));
-    quiet_mode_button_->SetToggled(message_center()->IsQuietMode());
-  } else {
-    NOTREACHED();
-  }
-}
-
 // BoundedScrollView ///////////////////////////////////////////////////////////
 
 // A custom scroll view whose height has a minimum and maximum value and whose
@@ -806,17 +593,33 @@
       tray_(tray),
       top_down_(top_down),
       settings_visible_(initially_settings_visible),
+      source_view_(NULL),
+      source_height_(0),
+      target_view_(NULL),
+      target_height_(0),
       is_closing_(false) {
   message_center_->AddObserver(this);
   set_notify_enter_exit_on_child(true);
   set_background(views::Background::CreateSolidBackground(
       kMessageCenterBackgroundColor));
 
-  button_bar_ = new MessageCenterButtonBar(this, message_center);
+  NotifierSettingsProvider* notifier_settings_provider =
+      message_center_->GetNotifierSettingsProvider();
+  button_bar_ = new MessageCenterButtonBar(this,
+                                           message_center,
+                                           notifier_settings_provider,
+                                           initially_settings_visible);
 
   const int button_height = button_bar_->GetPreferredSize().height();
-  scroller_ = new BoundedScrollView(kMinScrollViewHeight,
-                                    max_height - button_height);
+  button_bar_->set_border(views::Border::CreateSolidSidedBorder(
+      top_down_ ? 0 : kButtonBarBorderThickness,
+      0,
+      top_down_ ? kButtonBarBorderThickness : 0,
+      0,
+      kFooterDelimiterColor));
+
+  scroller_ =
+      new BoundedScrollView(kMinScrollViewHeight, max_height - button_height);
 
   if (get_use_acceleration_when_possible()) {
     scroller_->SetPaintToLayer(true);
@@ -832,8 +635,7 @@
   message_list_view_->AddChildView(no_notifications_message_view_);
   scroller_->SetContents(message_list_view_);
 
-  settings_view_ = new NotifierSettingsView(
-      message_center_->GetNotifierSettingsProvider());
+  settings_view_ = new NotifierSettingsView(notifier_settings_provider);
 
   if (initially_settings_visible)
     scroller_->SetVisible(false);
@@ -915,13 +717,6 @@
   settings_transition_animation_->Start();
 }
 
-void MessageCenterView::SetIsClosing(bool is_closing) {
-  is_closing_ = is_closing;
-  if (is_closing)
-    message_center_->RemoveObserver(this);
-  else
-    message_center_->AddObserver(this);
-}
 
 void MessageCenterView::ClearAllNotifications() {
   if (is_closing_)
@@ -942,11 +737,26 @@
   return message_list_view_->child_count();
 }
 
+void MessageCenterView::OnSettingsChanged() {
+  scroller_->InvalidateLayout();
+  PreferredSizeChanged();
+  Layout();
+}
+
+void MessageCenterView::SetIsClosing(bool is_closing) {
+  is_closing_ = is_closing;
+  if (is_closing)
+    message_center_->RemoveObserver(this);
+  else
+    message_center_->AddObserver(this);
+}
+
 void MessageCenterView::Layout() {
   if (is_closing_)
     return;
 
-  int button_height = button_bar_->GetHeightForWidth(width());
+  int button_height = button_bar_->GetHeightForWidth(width()) +
+                      button_bar_->GetInsets().height();
   // Skip unnecessary re-layout of contents during the resize animation.
   if (settings_transition_animation_ &&
       settings_transition_animation_->is_animating() &&
@@ -966,27 +776,6 @@
                             width(),
                             height() - button_height);
 
-  bool is_scrollable = false;
-  if (scroller_->visible())
-    is_scrollable = scroller_->height() < message_list_view_->height();
-  else
-    is_scrollable = settings_view_->IsScrollable();
-
-  if (is_scrollable && !button_bar_->border()) {
-    // Draw separator line on the top of the button bar if it is on the bottom
-    // or draw it at the bottom if the bar is on the top.
-    button_bar_->set_border(views::Border::CreateSolidSidedBorder(
-        top_down_ ? 0 : 1,
-        0,
-        top_down_ ? 1 : 0,
-        0,
-        kFooterDelimiterColor));
-    button_bar_->SchedulePaint();
-  } else if (!is_scrollable && button_bar_->border()) {
-    button_bar_->set_border(NULL);
-    button_bar_->SchedulePaint();
-  }
-
   button_bar_->SetBounds(0,
                          top_down_ ? 0 : height() - button_height,
                          width(),
@@ -1030,7 +819,8 @@
     content_height += scroller_->GetHeightForWidth(width);
   else
     content_height += settings_view_->GetHeightForWidth(width);
-  return button_bar_->GetHeightForWidth(width) + content_height;
+  return button_bar_->GetHeightForWidth(width) +
+         button_bar_->GetInsets().height() + content_height;
 }
 
 bool MessageCenterView::OnMouseWheel(const ui::MouseWheelEvent& event) {
@@ -1178,15 +968,12 @@
 }
 
 void MessageCenterView::NotificationsChanged() {
-  if (!message_views_.empty()) {
-    no_notifications_message_view_->SetVisible(false);
-    button_bar_->SetCloseAllVisible(true);
-    scroller_->set_focusable(true);
-  } else {
-    no_notifications_message_view_->SetVisible(true);
-    button_bar_->SetCloseAllVisible(false);
-    scroller_->set_focusable(false);
-  }
+  bool no_message_views = message_views_.empty();
+
+  no_notifications_message_view_->SetVisible(no_message_views);
+  button_bar_->SetCloseAllButtonVisible(!no_message_views);
+  scroller_->set_focusable(!no_message_views);
+
   scroller_->InvalidateLayout();
   PreferredSizeChanged();
   Layout();
diff --git a/ui/message_center/views/message_center_view.h b/ui/message_center/views/message_center_view.h
index 506a3a4..d53910c 100644
--- a/ui/message_center/views/message_center_view.h
+++ b/ui/message_center/views/message_center_view.h
@@ -54,6 +54,7 @@
   size_t NumMessageViewsForTest() const;
 
   void SetSettingsVisible(bool visible);
+  void OnSettingsChanged();
   bool settings_visible() const { return settings_visible_; }
 
   void SetIsClosing(bool is_closing);
@@ -86,7 +87,9 @@
 
   MessageCenter* message_center_;  // Weak reference.
   MessageCenterTray* tray_;  // Weak reference.
-  std::vector<MessageView*> message_views_;
+  std::vector<MessageView*> message_views_;  // Weak references.
+
+  // Child views.
   views::ScrollView* scroller_;
   MessageListView* message_list_view_;
   NotifierSettingsView* settings_view_;
@@ -96,12 +99,18 @@
 
   // Data for transition animation between settings view and message list.
   bool settings_visible_;
-  views::View* source_view_;
-  views::View* target_view_;
-  int source_height_;
-  int target_height_;
+
+  // Animation managing transition between message center and settings (and vice
+  // versa).
   scoped_ptr<ui::MultiAnimation> settings_transition_animation_;
 
+  // Helper data to keep track of the transition between settings and
+  // message center views.
+  views::View* source_view_;
+  int source_height_;
+  views::View* target_view_;
+  int target_height_;
+
   // True when the widget is closing so that further operations should be
   // ignored.
   bool is_closing_;
diff --git a/ui/message_center/views/notifier_settings_view.cc b/ui/message_center/views/notifier_settings_view.cc
index 5673070..b97bc84 100644
--- a/ui/message_center/views/notifier_settings_view.cc
+++ b/ui/message_center/views/notifier_settings_view.cc
@@ -8,14 +8,18 @@
 #include <string>
 
 #include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
 #include "grit/ui_resources.h"
 #include "grit/ui_strings.h"
+#include "skia/ext/image_operations.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/keycodes/keyboard_codes.h"
 #include "ui/base/l10n/l10n_util.h"
+#include "ui/base/models/simple_menu_model.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/size.h"
 #include "ui/message_center/message_center_style.h"
 #include "ui/message_center/views/message_center_view.h"
@@ -23,8 +27,10 @@
 #include "ui/views/border.h"
 #include "ui/views/controls/button/checkbox.h"
 #include "ui/views/controls/button/custom_button.h"
+#include "ui/views/controls/button/menu_button.h"
 #include "ui/views/controls/image_view.h"
 #include "ui/views/controls/label.h"
+#include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/controls/scroll_view.h"
 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h"
 #include "ui/views/layout/box_layout.h"
@@ -114,6 +120,78 @@
 
 }  // namespace
 
+// NotifierGroupMenuModel //////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+class NotifierGroupMenuModel : public ui::SimpleMenuModel,
+                               public ui::SimpleMenuModel::Delegate {
+ public:
+  NotifierGroupMenuModel(NotifierSettingsProvider* notifier_settings_provider);
+  virtual ~NotifierGroupMenuModel();
+
+  // Overridden from ui::SimpleMenuModel::Delegate:
+  virtual bool IsCommandIdChecked(int command_id) const OVERRIDE;
+  virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE;
+  virtual bool GetAcceleratorForCommandId(
+      int command_id,
+      ui::Accelerator* accelerator) OVERRIDE;
+  virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE;
+
+ private:
+  NotifierSettingsProvider* notifier_settings_provider_;
+};
+
+NotifierGroupMenuModel::NotifierGroupMenuModel(
+    NotifierSettingsProvider* notifier_settings_provider)
+    : ui::SimpleMenuModel(this),
+      notifier_settings_provider_(notifier_settings_provider) {
+  if (!notifier_settings_provider_)
+    return;
+
+  size_t num_menu_items = notifier_settings_provider_->GetNotifierGroupCount();
+  for (size_t i = 0; i < num_menu_items; ++i) {
+    const NotifierGroup& group =
+        notifier_settings_provider_->GetNotifierGroupAt(i);
+
+    AddItem(i, group.login_info.empty() ? group.name : group.login_info);
+
+    gfx::ImageSkia resized_icon = gfx::ImageSkiaOperations::CreateResizedImage(
+        *group.icon.ToImageSkia(),
+        skia::ImageOperations::RESIZE_BETTER,
+        gfx::Size(kSettingsIconSize, kSettingsIconSize));
+
+    SetIcon(i, gfx::Image(resized_icon));
+  }
+}
+
+NotifierGroupMenuModel::~NotifierGroupMenuModel() {}
+
+bool NotifierGroupMenuModel::IsCommandIdChecked(int command_id) const {
+  return false;
+}
+
+bool NotifierGroupMenuModel::IsCommandIdEnabled(int command_id) const {
+  return true;
+}
+
+bool NotifierGroupMenuModel::GetAcceleratorForCommandId(
+    int command_id,
+    ui::Accelerator* accelerator) {
+  return false;
+}
+
+void NotifierGroupMenuModel::ExecuteCommand(int command_id, int event_flags) {
+  if (!notifier_settings_provider_)
+    return;
+
+  size_t notifier_group_index = static_cast<size_t>(command_id);
+  size_t num_notifier_groups =
+      notifier_settings_provider_->GetNotifierGroupCount();
+  if (notifier_group_index >= num_notifier_groups)
+    return;
+
+  notifier_settings_provider_->SwitchToNotifierGroup(notifier_group_index);
+}
+
 // We do not use views::Checkbox class directly because it doesn't support
 // showing 'icon'.
 class NotifierSettingsView::NotifierButton : public views::CustomButton,
@@ -240,30 +318,11 @@
   scroller_->SetVerticalScrollBar(new views::OverlayScrollBar(false));
   AddChildView(scroller_);
 
-  views::View* contents_view = new views::View();
-  contents_view->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kVertical, 0, 0, 0));
-
-  views::Label* top_label = new views::Label(l10n_util::GetStringUTF16(
-      IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION));
-  top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  top_label->SetMultiLine(true);
-  top_label->SizeToFit(kMinimumWindowWidth - kMarginWidth * 2);
-  contents_view->AddChildView(new EntryView(top_label));
-
   std::vector<Notifier*> notifiers;
   if (provider_)
     provider_->GetNotifierList(&notifiers);
-  for (size_t i = 0; i < notifiers.size(); ++i) {
-    NotifierButton* button = new NotifierButton(notifiers[i], this);
-    EntryView* entry = new EntryView(button);
-    entry->set_focusable(true);
-    contents_view->AddChildView(entry);
-    buttons_.insert(button);
-  }
-  scroller_->SetContents(contents_view);
 
-  contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize()));
+  UpdateContentsView(notifiers);
 }
 
 NotifierSettingsView::~NotifierSettingsView() {
@@ -287,6 +346,57 @@
   }
 }
 
+void NotifierSettingsView::NotifierGroupChanged() {
+  std::vector<Notifier*> notifiers;
+  if (provider_)
+    provider_->GetNotifierList(&notifiers);
+
+  UpdateContentsView(notifiers);
+}
+
+void NotifierSettingsView::UpdateContentsView(
+    const std::vector<Notifier*>& notifiers) {
+  buttons_.clear();
+
+  views::View* contents_view = new views::View();
+  contents_view->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0));
+
+  views::View* contents_title_view = new views::View();
+  contents_title_view->SetLayoutManager(
+      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 5));
+  views::Label* top_label = new views::Label(l10n_util::GetStringUTF16(
+      IDS_MESSAGE_CENTER_SETTINGS_DIALOG_DESCRIPTION));
+  top_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  top_label->SetMultiLine(true);
+  contents_title_view->AddChildView(top_label);
+
+  string16 notifier_group_text;
+  if (provider_) {
+    const NotifierGroup& active_group = provider_->GetActiveNotifierGroup();
+    notifier_group_text = active_group.login_info.empty()
+                              ? active_group.name
+                              : active_group.login_info;
+  }
+
+  views::View* notifier_group_selector =
+      new views::MenuButton(NULL, notifier_group_text, this, true);
+  contents_title_view->AddChildView(notifier_group_selector);
+  contents_view->AddChildView(new EntryView(contents_title_view));
+
+  for (size_t i = 0; i < notifiers.size(); ++i) {
+    NotifierButton* button = new NotifierButton(notifiers[i], this);
+    EntryView* entry = new EntryView(button);
+    entry->set_focusable(true);
+    contents_view->AddChildView(entry);
+    buttons_.insert(button);
+  }
+  scroller_->SetContents(contents_view);
+
+  contents_view->SetBoundsRect(gfx::Rect(contents_view->GetPreferredSize()));
+  InvalidateLayout();
+}
+
 void NotifierSettingsView::Layout() {
   int title_height = title_entry_->GetHeightForWidth(width());
   title_entry_->SetBounds(0, 0, width(), title_height);
@@ -343,11 +453,30 @@
 
   std::set<NotifierButton*>::iterator iter = buttons_.find(
       static_cast<NotifierButton*>(sender));
-  DCHECK(iter != buttons_.end());
+
+  if (iter == buttons_.end())
+    return;
 
   (*iter)->SetChecked(!(*iter)->checked());
   if (provider_)
     provider_->SetNotifierEnabled((*iter)->notifier(), (*iter)->checked());
 }
 
+void NotifierSettingsView::OnMenuButtonClicked(views::View* source,
+                                               const gfx::Point& point) {
+  notifier_group_menu_model_.reset(new NotifierGroupMenuModel(provider_));
+  notifier_group_menu_runner_.reset(
+      new views::MenuRunner(notifier_group_menu_model_.get()));
+  if (views::MenuRunner::MENU_DELETED ==
+      notifier_group_menu_runner_->RunMenuAt(GetWidget(),
+                                             NULL,
+                                             source->GetBoundsInScreen(),
+                                             views::MenuItemView::BUBBLE_ABOVE,
+                                             ui::MENU_SOURCE_MOUSE,
+                                             views::MenuRunner::CONTEXT_MENU))
+    return;
+  MessageCenterView* center_view = static_cast<MessageCenterView*>(parent());
+  center_view->OnSettingsChanged();
+}
+
 }  // namespace message_center
diff --git a/ui/message_center/views/notifier_settings_view.h b/ui/message_center/views/notifier_settings_view.h
index 303eff4..6fc5b58 100644
--- a/ui/message_center/views/notifier_settings_view.h
+++ b/ui/message_center/views/notifier_settings_view.h
@@ -5,20 +5,30 @@
 #ifndef UI_MESSAGE_CENTER_VIEWS_NOTIFIER_SETTINGS_VIEW_H_
 #define UI_MESSAGE_CENTER_VIEWS_NOTIFIER_SETTINGS_VIEW_H_
 
+#include <set>
+
+#include "base/memory/scoped_ptr.h"
 #include "ui/message_center/message_center_export.h"
 #include "ui/message_center/notifier_settings.h"
 #include "ui/message_center/views/message_bubble_base.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/menu_button_listener.h"
 #include "ui/views/view.h"
 
+namespace views {
+class MenuRunner;
+}
+
 namespace message_center {
+class NotifierGroupMenuModel;
 
 // A class to show the list of notifier extensions / URL patterns and allow
 // users to customize the settings.
 class MESSAGE_CENTER_EXPORT NotifierSettingsView
     : public NotifierSettingsObserver,
       public views::View,
-      public views::ButtonListener {
+      public views::ButtonListener,
+      public views::MenuButtonListener {
  public:
   explicit NotifierSettingsView(NotifierSettingsProvider* provider);
   virtual ~NotifierSettingsView();
@@ -28,6 +38,7 @@
   // Overridden from NotifierSettingsDelegate:
   virtual void UpdateIconImage(const NotifierId& notifier_id,
                                const gfx::Image& icon) OVERRIDE;
+  virtual void NotifierGroupChanged() OVERRIDE;
 
   void set_provider(NotifierSettingsProvider* new_provider) {
     provider_ = new_provider;
@@ -36,6 +47,9 @@
  private:
   class NotifierButton;
 
+  // Given a new list of notifiers, updates the view to reflect it.
+  void UpdateContentsView(const std::vector<Notifier*>& notifiers);
+
   // Overridden from views::View:
   virtual void Layout() OVERRIDE;
   virtual gfx::Size GetMinimumSize() OVERRIDE;
@@ -46,12 +60,16 @@
   // Overridden from views::ButtonListener:
   virtual void ButtonPressed(views::Button* sender,
                              const ui::Event& event) OVERRIDE;
+  virtual void OnMenuButtonClicked(views::View* source,
+                                   const gfx::Point& point) OVERRIDE;
 
   views::ImageButton* title_arrow_;
   views::View* title_entry_;
   views::ScrollView* scroller_;
   NotifierSettingsProvider* provider_;
   std::set<NotifierButton*> buttons_;
+  scoped_ptr<NotifierGroupMenuModel> notifier_group_menu_model_;
+  scoped_ptr<views::MenuRunner> notifier_group_menu_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(NotifierSettingsView);
 };
diff --git a/ui/surface/accelerated_surface_win.cc b/ui/surface/accelerated_surface_win.cc
index cc144ef..3b86db0 100644
--- a/ui/surface/accelerated_surface_win.cc
+++ b/ui/surface/accelerated_surface_win.cc
@@ -728,7 +728,6 @@
     return;
   }
 
-#if !defined(USE_AURA)
   // If the window is a different size than the swap chain that is being
   // presented then drop the frame.
   gfx::Size window_size = GetWindowSize();
@@ -751,7 +750,6 @@
                  "windowheight", window_size.height());
     return;
   }
-#endif
 
   // Round up size so the swap chain is not continuously resized with the
   // surface, which could lead to memory fragmentation.
diff --git a/ui/ui.gyp b/ui/ui.gyp
index 0cd6abd..e17d242 100644
--- a/ui/ui.gyp
+++ b/ui/ui.gyp
@@ -259,6 +259,8 @@
         'base/l10n/l10n_util_posix.cc',
         'base/l10n/l10n_util_win.cc',
         'base/l10n/l10n_util_win.h',
+        'base/l10n/time_format.cc',
+        'base/l10n/time_format.h',
         'base/layout.cc',
         'base/layout.h',
         'base/layout_mac.mm',
diff --git a/ui/ui.target.darwin-arm.mk b/ui/ui.target.darwin-arm.mk
index 602d86c..f3e940a 100644
--- a/ui/ui.target.darwin-arm.mk
+++ b/ui/ui.target.darwin-arm.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui.target.darwin-mips.mk b/ui/ui.target.darwin-mips.mk
index 5b22a3c..7a521ee 100644
--- a/ui/ui.target.darwin-mips.mk
+++ b/ui/ui.target.darwin-mips.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui.target.darwin-x86.mk b/ui/ui.target.darwin-x86.mk
index f2a0f18..9c93235 100644
--- a/ui/ui.target.darwin-x86.mk
+++ b/ui/ui.target.darwin-x86.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui.target.linux-arm.mk b/ui/ui.target.linux-arm.mk
index 602d86c..f3e940a 100644
--- a/ui/ui.target.linux-arm.mk
+++ b/ui/ui.target.linux-arm.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui.target.linux-mips.mk b/ui/ui.target.linux-mips.mk
index 5b22a3c..7a521ee 100644
--- a/ui/ui.target.linux-mips.mk
+++ b/ui/ui.target.linux-mips.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui.target.linux-x86.mk b/ui/ui.target.linux-x86.mk
index f2a0f18..9c93235 100644
--- a/ui/ui.target.linux-x86.mk
+++ b/ui/ui.target.linux-x86.mk
@@ -59,6 +59,7 @@
 	ui/base/l10n/l10n_util.cc \
 	ui/base/l10n/l10n_util_android.cc \
 	ui/base/l10n/l10n_util_posix.cc \
+	ui/base/l10n/time_format.cc \
 	ui/base/layout.cc \
 	ui/base/models/button_menu_item_model.cc \
 	ui/base/models/combobox_model.cc \
diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi
index d5db0d5..dc46a55 100644
--- a/ui/ui_unittests.gypi
+++ b/ui/ui_unittests.gypi
@@ -99,6 +99,7 @@
         'base/l10n/l10n_util_mac_unittest.mm',
         'base/l10n/l10n_util_unittest.cc',
         'base/l10n/l10n_util_win_unittest.cc',
+        'base/l10n/time_format_unittest.cc',
         'base/models/tree_node_iterator_unittest.cc',
         'base/range/range_mac_unittest.mm',
         'base/range/range_unittest.cc',
diff --git a/ui/views/ime/input_method_win.cc b/ui/views/ime/input_method_win.cc
deleted file mode 100644
index 5ec7c72..0000000
--- a/ui/views/ime/input_method_win.cc
+++ /dev/null
@@ -1,509 +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 "ui/views/ime/input_method_win.h"
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/strings/string_util.h"
-#include "ui/base/events/event.h"
-#include "ui/base/events/event_constants.h"
-#include "ui/base/events/event_utils.h"
-#include "ui/base/ime/composition_text.h"
-#include "ui/base/ime/input_method.h"
-#include "ui/base/ime/text_input_client.h"
-#include "ui/base/keycodes/keyboard_codes.h"
-#include "ui/base/win/hwnd_util.h"
-
-// Extra number of chars before and after selection (or composition) range which
-// is returned to IME for improving conversion accuracy.
-static const size_t kExtraNumberOfChars = 20;
-
-namespace views {
-
-InputMethodWin::InputMethodWin(internal::InputMethodDelegate* delegate,
-                               HWND hwnd,
-                               ui::InputMethod* host)
-    : hwnd_(hwnd),
-      active_(false),
-      is_candidate_popup_open_(false),
-      direction_(base::i18n::UNKNOWN_DIRECTION),
-      pending_requested_direction_(base::i18n::UNKNOWN_DIRECTION),
-      host_(host) {
-  SetDelegate(delegate);
-}
-
-InputMethodWin::~InputMethodWin() {
-  if (widget())
-    imm32_manager_.DisableIME(hwnd_);
-}
-
-void InputMethodWin::Init(Widget* widget) {
-  InputMethodBase::Init(widget);
-
-  // Gets the initial input locale and text direction information.
-  OnInputLocaleChanged();
-}
-
-void InputMethodWin::OnFocus() {
-  UpdateIMEState();
-}
-
-void InputMethodWin::OnBlur() {
-  ConfirmCompositionText();
-}
-
-bool InputMethodWin::OnUntranslatedIMEMessage(const base::NativeEvent& event,
-                                              NativeEventResult* result) {
-  LRESULT original_result = 0;
-  BOOL handled = FALSE;
-  switch (event.message) {
-    case WM_IME_SETCONTEXT:
-      original_result = OnImeSetContext(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_IME_STARTCOMPOSITION:
-      original_result = OnImeStartComposition(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_IME_COMPOSITION:
-      original_result = OnImeComposition(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_IME_ENDCOMPOSITION:
-      original_result = OnImeEndComposition(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_IME_REQUEST:
-      original_result = OnImeRequest(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_IME_NOTIFY:
-      original_result = OnImeNotify(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_CHAR:
-    case WM_SYSCHAR:
-      original_result = OnChar(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    case WM_DEADCHAR:
-    case WM_SYSDEADCHAR:
-      original_result = OnDeadChar(
-          event.message, event.wParam, event.lParam, &handled);
-      break;
-    default:
-      NOTREACHED() << "Unknown IME message:" << event.message;
-      break;
-  }
-  if (result)
-    *result = original_result;
-  return !!handled;
-}
-
-void InputMethodWin::DispatchKeyEvent(const ui::KeyEvent& key) {
-  // Handles ctrl-shift key to change text direction and layout alignment.
-  if (ui::IMM32Manager::IsRTLKeyboardLayoutInstalled() &&
-      !IsTextInputTypeNone()) {
-    ui::KeyboardCode code = key.key_code();
-    if (key.type() == ui::ET_KEY_PRESSED) {
-      if (code == ui::VKEY_SHIFT) {
-        base::i18n::TextDirection dir;
-        if (ui::IMM32Manager::IsCtrlShiftPressed(&dir))
-          pending_requested_direction_ = dir;
-      } else if (code != ui::VKEY_CONTROL) {
-        pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
-      }
-    } else if (key.type() == ui::ET_KEY_RELEASED &&
-               (code == ui::VKEY_SHIFT || code == ui::VKEY_CONTROL) &&
-               pending_requested_direction_ != base::i18n::UNKNOWN_DIRECTION) {
-      GetTextInputClient()->ChangeTextDirectionAndLayoutAlignment(
-          pending_requested_direction_);
-      pending_requested_direction_ = base::i18n::UNKNOWN_DIRECTION;
-    }
-  }
-
-  DispatchKeyEventPostIME(key);
-}
-
-void InputMethodWin::OnTextInputTypeChanged(View* view) {
-  if (IsViewFocused(view)) {
-    imm32_manager_.CancelIME(hwnd_);
-    UpdateIMEState();
-  }
-  InputMethodBase::OnTextInputTypeChanged(view);
-}
-
-void InputMethodWin::OnCaretBoundsChanged(View* view) {
-  gfx::Rect rect;
-  if (!IsViewFocused(view) || !GetCaretBoundsInWidget(&rect))
-    return;
-  imm32_manager_.UpdateCaretRect(hwnd_, rect);
-}
-
-void InputMethodWin::CancelComposition(View* view) {
-  if (IsViewFocused(view))
-    imm32_manager_.CancelIME(hwnd_);
-}
-
-void InputMethodWin::OnInputLocaleChanged() {
-  active_ = imm32_manager_.SetInputLanguage();
-  locale_ = imm32_manager_.GetInputLanguageName();
-  direction_ = imm32_manager_.GetTextDirection();
-  OnInputMethodChanged();
-}
-
-std::string InputMethodWin::GetInputLocale() {
-  return locale_;
-}
-
-base::i18n::TextDirection InputMethodWin::GetInputTextDirection() {
-  return direction_;
-}
-
-bool InputMethodWin::IsActive() {
-  return active_;
-}
-
-ui::TextInputClient* InputMethodWin::GetTextInputClient() const {
-  if (InputMethodBase::GetTextInputClient())
-    return InputMethodBase::GetTextInputClient();
-
-  return host_ ? host_->GetTextInputClient() : NULL;
-}
-
-bool InputMethodWin::IsCandidatePopupOpen() const {
-  return is_candidate_popup_open_;
-}
-
-void InputMethodWin::OnWillChangeFocus(View* focused_before, View* focused) {
-  ConfirmCompositionText();
-}
-
-void InputMethodWin::OnDidChangeFocus(View* focused_before, View* focused) {
-  UpdateIMEState();
-}
-
-LRESULT InputMethodWin::OnImeSetContext(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  active_ = (wparam == TRUE);
-  if (active_)
-    imm32_manager_.CreateImeWindow(hwnd_);
-
-  OnInputMethodChanged();
-  return imm32_manager_.SetImeWindowStyle(hwnd_, message, wparam, lparam,
-                                          handled);
-}
-
-LRESULT InputMethodWin::OnImeStartComposition(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  // We have to prevent WTL from calling ::DefWindowProc() because the function
-  // calls ::ImmSetCompositionWindow() and ::ImmSetCandidateWindow() to
-  // over-write the position of IME windows.
-  *handled = TRUE;
-
-  if (IsTextInputTypeNone())
-    return 0;
-
-  // Reset the composition status and create IME windows.
-  imm32_manager_.CreateImeWindow(hwnd_);
-  imm32_manager_.ResetComposition(hwnd_);
-  return 0;
-}
-
-LRESULT InputMethodWin::OnImeComposition(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  // We have to prevent WTL from calling ::DefWindowProc() because we do not
-  // want for the IMM (Input Method Manager) to send WM_IME_CHAR messages.
-  *handled = TRUE;
-
-  if (IsTextInputTypeNone())
-    return 0;
-
-  // At first, update the position of the IME window.
-  imm32_manager_.UpdateImeWindow(hwnd_);
-
-  // Retrieve the result string and its attributes of the ongoing composition
-  // and send it to a renderer process.
-  ui::CompositionText composition;
-  if (imm32_manager_.GetResult(hwnd_, lparam, &composition.text)) {
-    GetTextInputClient()->InsertText(composition.text);
-    imm32_manager_.ResetComposition(hwnd_);
-    // Fall though and try reading the composition string.
-    // Japanese IMEs send a message containing both GCS_RESULTSTR and
-    // GCS_COMPSTR, which means an ongoing composition has been finished
-    // by the start of another composition.
-  }
-  // Retrieve the composition string and its attributes of the ongoing
-  // composition and send it to a renderer process.
-  if (imm32_manager_.GetComposition(hwnd_, lparam, &composition))
-    GetTextInputClient()->SetCompositionText(composition);
-
-  return 0;
-}
-
-LRESULT InputMethodWin::OnImeEndComposition(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  // Let WTL call ::DefWindowProc() and release its resources.
-  *handled = FALSE;
-
-  if (IsTextInputTypeNone())
-    return 0;
-
-  if (GetTextInputClient()->HasCompositionText())
-    GetTextInputClient()->ClearCompositionText();
-
-  imm32_manager_.ResetComposition(hwnd_);
-  imm32_manager_.DestroyImeWindow(hwnd_);
-  return 0;
-}
-
-LRESULT InputMethodWin::OnImeRequest(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  *handled = FALSE;
-
-  // Should not receive WM_IME_REQUEST message, if IME is disabled.
-  const ui::TextInputType type = GetTextInputType();
-  if (type == ui::TEXT_INPUT_TYPE_NONE ||
-      type == ui::TEXT_INPUT_TYPE_PASSWORD) {
-    return 0;
-  }
-
-  switch (wparam) {
-    case IMR_RECONVERTSTRING:
-      *handled = TRUE;
-      return OnReconvertString(reinterpret_cast<RECONVERTSTRING*>(lparam));
-    case IMR_DOCUMENTFEED:
-      *handled = TRUE;
-      return OnDocumentFeed(reinterpret_cast<RECONVERTSTRING*>(lparam));
-    case IMR_QUERYCHARPOSITION:
-      *handled = TRUE;
-      return OnQueryCharPosition(reinterpret_cast<IMECHARPOSITION*>(lparam));
-    default:
-      return 0;
-  }
-}
-
-LRESULT InputMethodWin::OnImeNotify(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  *handled = FALSE;
-
-  // Update |is_candidate_popup_open_|, whether a candidate window is open.
-  switch (wparam) {
-  case IMN_OPENCANDIDATE:
-    is_candidate_popup_open_ = true;
-    break;
-  case IMN_CLOSECANDIDATE:
-    is_candidate_popup_open_ = false;
-    break;
-  }
-
-  return 0;
-}
-
-LRESULT InputMethodWin::OnChar(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  *handled = TRUE;
-
-  // We need to send character events to the focused text input client event if
-  // its text input type is ui::TEXT_INPUT_TYPE_NONE.
-  if (GetTextInputClient()) {
-    GetTextInputClient()->InsertChar(static_cast<char16>(wparam),
-                                     ui::GetModifiersFromKeyState());
-  }
-
-  // Explicitly show the system menu at a good location on [Alt]+[Space].
-  // Note: Setting |handled| to FALSE for DefWindowProc triggering of the system
-  //       menu causes unsdesirable titlebar artifacts in the classic theme.
-  if (message == WM_SYSCHAR && wparam == VK_SPACE)
-    ui::ShowSystemMenu(hwnd_);
-
-  return 0;
-}
-
-LRESULT InputMethodWin::OnDeadChar(
-    UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled) {
-  *handled = TRUE;
-
-  if (IsTextInputTypeNone())
-    return 0;
-
-  if (!GetTextInputClient())
-    return 0;
-
-  // Shows the dead character as a composition text, so that the user can know
-  // what dead key was pressed.
-  ui::CompositionText composition;
-  composition.text.assign(1, static_cast<char16>(wparam));
-  composition.selection = ui::Range(0, 1);
-  composition.underlines.push_back(
-      ui::CompositionUnderline(0, 1, SK_ColorBLACK, false));
-  GetTextInputClient()->SetCompositionText(composition);
-  return 0;
-}
-
-LRESULT InputMethodWin::OnDocumentFeed(RECONVERTSTRING* reconv) {
-  ui::TextInputClient* client = GetTextInputClient();
-  if (!client)
-    return 0;
-
-  ui::Range text_range;
-  if (!client->GetTextRange(&text_range) || text_range.is_empty())
-    return 0;
-
-  bool result = false;
-  ui::Range target_range;
-  if (client->HasCompositionText())
-    result = client->GetCompositionTextRange(&target_range);
-
-  if (!result || target_range.is_empty()) {
-    if (!client->GetSelectionRange(&target_range) ||
-        !target_range.IsValid()) {
-      return 0;
-    }
-  }
-
-  if (!text_range.Contains(target_range))
-    return 0;
-
-  if (target_range.GetMin() - text_range.start() > kExtraNumberOfChars)
-    text_range.set_start(target_range.GetMin() - kExtraNumberOfChars);
-
-  if (text_range.end() - target_range.GetMax() > kExtraNumberOfChars)
-    text_range.set_end(target_range.GetMax() + kExtraNumberOfChars);
-
-  size_t len = text_range.length();
-  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
-
-  if (!reconv)
-    return need_size;
-
-  if (reconv->dwSize < need_size)
-    return 0;
-
-  string16 text;
-  if (!GetTextInputClient()->GetTextFromRange(text_range, &text))
-    return 0;
-  DCHECK_EQ(text_range.length(), text.length());
-
-  reconv->dwVersion = 0;
-  reconv->dwStrLen = len;
-  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
-  reconv->dwCompStrLen =
-      client->HasCompositionText() ? target_range.length() : 0;
-  reconv->dwCompStrOffset =
-      (target_range.GetMin() - text_range.start()) * sizeof(WCHAR);
-  reconv->dwTargetStrLen = target_range.length();
-  reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
-
-  memcpy((char*)reconv + sizeof(RECONVERTSTRING),
-         text.c_str(), len * sizeof(WCHAR));
-
-  // According to Microsft API document, IMR_RECONVERTSTRING and
-  // IMR_DOCUMENTFEED should return reconv, but some applications return
-  // need_size.
-  return reinterpret_cast<LRESULT>(reconv);
-}
-
-LRESULT InputMethodWin::OnReconvertString(RECONVERTSTRING* reconv) {
-  ui::TextInputClient* client = GetTextInputClient();
-  if (!client)
-    return 0;
-
-  // If there is a composition string already, we don't allow reconversion.
-  if (client->HasCompositionText())
-    return 0;
-
-  ui::Range text_range;
-  if (!client->GetTextRange(&text_range) || text_range.is_empty())
-    return 0;
-
-  ui::Range selection_range;
-  if (!client->GetSelectionRange(&selection_range) ||
-      selection_range.is_empty()) {
-    return 0;
-  }
-
-  DCHECK(text_range.Contains(selection_range));
-
-  size_t len = selection_range.length();
-  size_t need_size = sizeof(RECONVERTSTRING) + len * sizeof(WCHAR);
-
-  if (!reconv)
-    return need_size;
-
-  if (reconv->dwSize < need_size)
-    return 0;
-
-  // TODO(penghuang): Return some extra context to help improve IME's
-  // reconversion accuracy.
-  string16 text;
-  if (!GetTextInputClient()->GetTextFromRange(selection_range, &text))
-    return 0;
-  DCHECK_EQ(selection_range.length(), text.length());
-
-  reconv->dwVersion = 0;
-  reconv->dwStrLen = len;
-  reconv->dwStrOffset = sizeof(RECONVERTSTRING);
-  reconv->dwCompStrLen = len;
-  reconv->dwCompStrOffset = 0;
-  reconv->dwTargetStrLen = len;
-  reconv->dwTargetStrOffset = 0;
-
-  memcpy(reinterpret_cast<char*>(reconv) + sizeof(RECONVERTSTRING),
-         text.c_str(), len * sizeof(WCHAR));
-
-  // According to Microsft API document, IMR_RECONVERTSTRING and
-  // IMR_DOCUMENTFEED should return reconv, but some applications return
-  // need_size.
-  return reinterpret_cast<LRESULT>(reconv);
-}
-
-LRESULT InputMethodWin::OnQueryCharPosition(IMECHARPOSITION *char_positon) {
-  if (!char_positon)
-    return 0;
-
-  if (char_positon->dwSize < sizeof(IMECHARPOSITION))
-    return 0;
-
-  ui::TextInputClient* client = GetTextInputClient();
-  if (!client)
-    return 0;
-
-  gfx::Rect rect;
-  if (!client->GetCompositionCharacterBounds(char_positon->dwCharPos, &rect))
-    return 0;
-
-  char_positon->pt.x = rect.x();
-  char_positon->pt.y = rect.y();
-  char_positon->cLineHeight = rect.height();
-  return 1;  // returns non-zero value when succeeded.
-}
-
-void InputMethodWin::ConfirmCompositionText() {
-  if (!IsTextInputTypeNone()) {
-    imm32_manager_.CleanupComposition(hwnd_);
-    // Though above line should confirm the client's composition text by sending
-    // a result text to us, in case the input method and the client are in
-    // inconsistent states, we check the client's composition state again.
-    if (GetTextInputClient()->HasCompositionText())
-      GetTextInputClient()->ConfirmCompositionText();
-  }
-}
-
-void InputMethodWin::UpdateIMEState() {
-  // Use switch here in case we are going to add more text input types.
-  // We disable input method in password field.
-  switch (GetTextInputType()) {
-    case ui::TEXT_INPUT_TYPE_NONE:
-    case ui::TEXT_INPUT_TYPE_PASSWORD:
-      imm32_manager_.DisableIME(hwnd_);
-      break;
-    default:
-      imm32_manager_.EnableIME(hwnd_);
-      break;
-  }
-}
-
-}  // namespace views
diff --git a/ui/views/ime/input_method_win.h b/ui/views/ime/input_method_win.h
deleted file mode 100644
index 5668e8f3..0000000
--- a/ui/views/ime/input_method_win.h
+++ /dev/null
@@ -1,117 +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 UI_VIEWS_IME_INPUT_METHOD_WIN_H_
-#define UI_VIEWS_IME_INPUT_METHOD_WIN_H_
-
-#include <windows.h>
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/base/ime/win/imm32_manager.h"
-#include "ui/views/ime/input_method_base.h"
-#include "ui/views/view.h"
-#include "ui/views/widget/widget.h"
-
-namespace ui {
-class InputMethod;
-}  // namespace ui
-
-namespace views {
-
-// An InputMethod implementation based on Windows IMM32 API.
-class InputMethodWin : public InputMethodBase {
- public:
-  InputMethodWin(internal::InputMethodDelegate* delegate,
-                 HWND hwnd,
-                 ui::InputMethod* host);
-  virtual ~InputMethodWin();
-
-  // Overridden from InputMethod:
-  virtual void Init(Widget* widget) OVERRIDE;
-  virtual void OnFocus() OVERRIDE;
-  virtual void OnBlur() OVERRIDE;
-  virtual bool OnUntranslatedIMEMessage(const base::NativeEvent& event,
-                                        NativeEventResult* result) OVERRIDE;
-  virtual void DispatchKeyEvent(const ui::KeyEvent& key) OVERRIDE;
-  virtual void OnTextInputTypeChanged(View* view) OVERRIDE;
-  virtual void OnCaretBoundsChanged(View* view) OVERRIDE;
-  virtual void CancelComposition(View* view) OVERRIDE;
-  virtual void OnInputLocaleChanged() OVERRIDE;
-  virtual std::string GetInputLocale() OVERRIDE;
-  virtual base::i18n::TextDirection GetInputTextDirection() OVERRIDE;
-  virtual bool IsActive() OVERRIDE;
-  virtual bool IsCandidatePopupOpen() const OVERRIDE;
-
-  // Overridden from InputMethodBase.
-  virtual ui::TextInputClient* GetTextInputClient() const OVERRIDE;
-
- private:
-  LRESULT OnImeSetContext(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  LRESULT OnImeStartComposition(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  LRESULT OnImeComposition(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  LRESULT OnImeEndComposition(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  LRESULT OnImeRequest(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  LRESULT OnImeNotify(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  // For both WM_CHAR and WM_SYSCHAR
-  LRESULT OnChar(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-  // For both WM_DEADCHAR and WM_SYSDEADCHAR
-  LRESULT OnDeadChar(
-      UINT message, WPARAM wparam, LPARAM lparam, BOOL* handled);
-
-  LRESULT OnDocumentFeed(RECONVERTSTRING *reconv);
-  LRESULT OnReconvertString(RECONVERTSTRING *reconv);
-  LRESULT OnQueryCharPosition(IMECHARPOSITION *char_positon);
-
-  // Overridden from InputMethodBase.
-  virtual void OnWillChangeFocus(View* focused_before, View* focused) OVERRIDE;
-  virtual void OnDidChangeFocus(View* focused_before, View* focused) OVERRIDE;
-
-  // Asks the client to confirm current composition text.
-  void ConfirmCompositionText();
-
-  // Enables or disables the IME according to the current text input type.
-  void UpdateIMEState();
-
-  // The HWND this InputMethod is bound to.
-  HWND hwnd_;
-
-  // Indicates if the current input locale has an IME.
-  bool active_;
-
-  // True if we know for sure that a candidate window is open.
-  bool is_candidate_popup_open_;
-
-  // Name of the current input locale.
-  std::string locale_;
-
-  // The current input text direction.
-  base::i18n::TextDirection direction_;
-
-  // The new text direction and layout alignment requested by the user by
-  // pressing ctrl-shift. It'll be sent to the text input client when the key
-  // is released.
-  base::i18n::TextDirection pending_requested_direction_;
-
-  // Windows IMM32 wrapper.
-  // (See "ui/base/ime/win/ime_input.h" for its details.)
-  ui::IMM32Manager imm32_manager_;
-
-  ui::InputMethod* const host_;
-
-  DISALLOW_COPY_AND_ASSIGN(InputMethodWin);
-};
-
-}  // namespace views
-
-#endif  // UI_VIEWS_IME_INPUT_METHOD_WIN_H_
diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc
index b309483..8b6b351 100644
--- a/ui/views/touchui/touch_selection_controller_impl.cc
+++ b/ui/views/touchui/touch_selection_controller_impl.cc
@@ -25,14 +25,39 @@
 const SkColor kSelectionHandleLineColor =
     SkColorSetRGB(0x42, 0x81, 0xf4);
 
+// When a handle is dragged, the drag position reported to the client view is
+// offset vertically to represent the cursor position. This constant specifies
+// the offset in  pixels above the "O" (see pic below). This is required because
+// say if this is zero, that means the drag position we report is the point
+// right above the "O" or the bottom most point of the cursor "|". In that case,
+// a vertical movement of even one pixel will make the handle jump to the line
+// below it. So when the user just starts dragging, the handle will jump to the
+// next line if the user makes any vertical movement. It is correct but
+// looks/feels weird. So we have this non-zero offset to prevent this jumping.
+//
+// Editing handle widget showing the difference between the position of the
+// ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the client:
+//                                  _____
+//                                 |  |<-|---- Drag position reported to client
+//                              _  |  O  |
+//          Vertical Padding __|   |   <-|---- ET_GESTURE_SCROLL_UPDATE position
+//                             |_  |_____|<--- Editing handle widget
+//
+//                                 | |
+//                                  T
+//                          Horizontal Padding
+//
+const int kSelectionHandleVerticalDragOffset = 5;
+
 // Padding around the selection handle defining the area that will be included
-// in the touch target to make dragging the handle easier.
-const int kSelectionHandlePadding = 10;
+// in the touch target to make dragging the handle easier (see pic above).
+const int kSelectionHandleHorizPadding = 10;
+const int kSelectionHandleVertPadding = 20;
 
 // The minimum selection size to trigger selection controller.
 // TODO(varunjain): Figure out if this is really required and get rid of it if
 // it isnt.
-const int kMinSelectionSize = 2;
+const int kMinSelectionSize = 1;
 
 const int kContextMenuTimoutMs = 200;
 
@@ -107,7 +132,9 @@
  public:
   explicit EditingHandleView(TouchSelectionControllerImpl* controller,
                              gfx::NativeView context)
-      : controller_(controller) {
+      : controller_(controller),
+        drag_offset_(0),
+        draw_invisible_(false) {
     widget_.reset(CreateTouchSelectionPopupWidget(context, this));
     widget_->SetContentsView(this);
     widget_->SetAlwaysOnTop(true);
@@ -132,9 +159,9 @@
   virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE {
     gfx::Size image_size = GetHandleImageSize();
     mask->addRect(SkIntToScalar(0), SkIntToScalar(cursor_height()),
-        SkIntToScalar(image_size.width()) + 2 * kSelectionHandlePadding,
+        SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
         SkIntToScalar(cursor_height() + image_size.height() +
-            kSelectionHandlePadding));
+            kSelectionHandleVertPadding));
   }
 
   virtual void DeleteDelegate() OVERRIDE {
@@ -143,9 +170,11 @@
 
   // Overridden from views::View:
   virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
+    if (draw_invisible_)
+      return;
     gfx::Size image_size = GetHandleImageSize();
     int cursor_pos_x = image_size.width() / 2 - kSelectionHandleLineWidth +
-        kSelectionHandlePadding;
+        kSelectionHandleHorizPadding;
 
     // Draw the cursor line.
     canvas->FillRect(
@@ -155,7 +184,7 @@
 
     // Draw the handle image.
     canvas->DrawImageInt(*GetHandleImage()->ToImageSkia(),
-        kSelectionHandlePadding, cursor_height());
+        kSelectionHandleHorizPadding, cursor_height());
   }
 
   virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
@@ -164,10 +193,15 @@
       case ui::ET_GESTURE_SCROLL_BEGIN:
         widget_->SetCapture(this);
         controller_->SetDraggingHandle(this);
+        drag_offset_ = event->y() - cursor_height() -
+            kSelectionHandleVerticalDragOffset;
         break;
-      case ui::ET_GESTURE_SCROLL_UPDATE:
-        controller_->SelectionHandleDragged(event->location());
+      case ui::ET_GESTURE_SCROLL_UPDATE: {
+        gfx::Point drag_pos(event->location().x(),
+            event->location().y() - drag_offset_);
+        controller_->SelectionHandleDragged(drag_pos);
         break;
+      }
       case ui::ET_GESTURE_SCROLL_END:
       case ui::ET_SCROLL_FLING_START:
         widget_->ReleaseCapture();
@@ -191,8 +225,8 @@
 
   virtual gfx::Size GetPreferredSize() OVERRIDE {
     gfx::Size image_size = GetHandleImageSize();
-    return gfx::Size(image_size.width() + 2 * kSelectionHandlePadding,
-        image_size.height() + cursor_height() + kSelectionHandlePadding);
+    return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
+        image_size.height() + cursor_height() + kSelectionHandleVertPadding);
   }
 
   bool IsWidgetVisible() const {
@@ -203,10 +237,10 @@
     gfx::Size image_size = GetHandleImageSize();
     selection_rect_ = rect;
     gfx::Rect widget_bounds(
-        rect.x() - image_size.width() / 2 - kSelectionHandlePadding,
+        rect.x() - image_size.width() / 2 - kSelectionHandleHorizPadding,
         rect.y(),
-        image_size.width() + 2 * kSelectionHandlePadding,
-        rect.height() + image_size.height() + kSelectionHandlePadding);
+        image_size.width() + 2 * kSelectionHandleHorizPadding,
+        rect.height() + image_size.height() + kSelectionHandleVertPadding);
     widget_->SetBounds(widget_bounds);
   }
 
@@ -214,10 +248,24 @@
     return widget_->GetClientAreaBoundsInScreen().origin();
   }
 
+  void SetDrawInvisible(bool draw_invisible) {
+    if (draw_invisible_ == draw_invisible)
+      return;
+    draw_invisible_ = draw_invisible;
+    SchedulePaint();
+  }
+
  private:
   scoped_ptr<Widget> widget_;
   TouchSelectionControllerImpl* controller_;
   gfx::Rect selection_rect_;
+  int drag_offset_;
+
+  // If set to true, the handle will not draw anything, hence providing an empty
+  // widget. We need this because we may want to stop showing the handle while
+  // it is being dragged. Since it is being dragged, we cannot destroy the
+  // handle.
+  bool draw_invisible_;
 
   DISALLOW_COPY_AND_ASSIGN(EditingHandleView);
 };
@@ -273,6 +321,13 @@
     // the start.
     dragging_handle_->SetSelectionRectInScreen(screen_rect_2);
 
+    // Temporary fix for selection handle going outside a window. On a webpage,
+    // the page should scroll if the selection handle is dragged outside the
+    // window. That does not happen currently. So we just hide the handle for
+    // now.
+    // TODO(varunjain): Fix this: crbug.com/269003
+    dragging_handle_->SetDrawInvisible(!client_view_->GetBounds().Contains(r2));
+
     if (dragging_handle_ != cursor_handle_.get()) {
       // The non-dragging-handle might have recently become visible.
       EditingHandleView* non_dragging_handle =
@@ -321,13 +376,11 @@
   HideContextMenu();
 
   DCHECK(dragging_handle_);
+  gfx::Point drag_pos_in_client = drag_pos;
+  ConvertPointToClientView(dragging_handle_, &drag_pos_in_client);
 
-  gfx::Size image_size = GetHandleImageSize();
-  gfx::Point offset_drag_pos(drag_pos.x(),
-      drag_pos.y() - image_size.height() - kSelectionHandlePadding - 1);
-  ConvertPointToClientView(dragging_handle_, &offset_drag_pos);
   if (dragging_handle_ == cursor_handle_.get()) {
-    client_view_->MoveCaretTo(offset_drag_pos);
+    client_view_->MoveCaretTo(drag_pos_in_client);
     return;
   }
 
@@ -344,7 +397,7 @@
   // Instruct client_view to select the region between p1 and p2. The position
   // of |fixed_handle| is the start and that of |dragging_handle| is the end
   // of selection.
-  client_view_->SelectRect(p2, offset_drag_pos);
+  client_view_->SelectRect(p2, drag_pos_in_client);
 }
 
 void TouchSelectionControllerImpl::ConvertPointToClientView(
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index ea0285b..ff3ab0a 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -297,8 +297,6 @@
         'ime/input_method_bridge.h',
         'ime/input_method_delegate.h',
         'ime/input_method.h',
-        'ime/input_method_win.cc',
-        'ime/input_method_win.h',
         'ime/mock_input_method.cc',
         'ime/mock_input_method.h',
         'layout/box_layout.cc',
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
index 12be4cc..2ca556c 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_position_client.cc
@@ -68,19 +68,16 @@
     const gfx::Rect& bounds,
     const gfx::Display& display) {
   // TODO: Use the 3rd parameter, |display|.
-  gfx::Point origin = bounds.origin();
   aura::RootWindow* root = window->GetRootWindow();
-  aura::Window::ConvertPointToTarget(window->parent(), root, &origin);
-
-  if (window->type() == aura::client::WINDOW_TYPE_CONTROL) {
-    window->SetBounds(gfx::Rect(origin, bounds.size()));
-    return;
-  }
 
   if (PositionWindowInScreenCoordinates(window)) {
     // The caller expects windows we consider "embedded" to be placed in the
     // screen coordinate system. So we need to offset the root window's
     // position (which is in screen coordinates) from these bounds.
+
+    gfx::Point origin = bounds.origin();
+    aura::Window::ConvertPointToTarget(window->parent(), root, &origin);
+
     gfx::Point host_origin = GetOrigin(root);
     origin.Offset(-host_origin.x(), -host_origin.y());
     window->SetBounds(gfx::Rect(origin, bounds.size()));
diff --git a/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc b/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
index 196f6e4..bb1cd8b 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_position_client_unittest.cc
@@ -34,4 +34,52 @@
   EXPECT_EQ("11,12", dialog->GetWindowBoundsInScreen().origin().ToString());
 }
 
+// Verifies that setting the bounds of a control parented to something other
+// than the root window is positioned correctly.
+TEST_F(DesktopScreenPositionClientTest, PositionControlWithNonRootParent) {
+  Widget widget1;
+  Widget widget2;
+  Widget widget3;
+  gfx::Point origin = gfx::Point(16, 16);
+
+  // Use a custom frame type.  By default we will choose a native frame when
+  // aero glass is enabled, and this complicates the logic surrounding origin
+  // computation, making it difficult to compute the expected origin location.
+  widget1.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+  widget2.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+  widget3.set_frame_type(Widget::FRAME_TYPE_FORCE_CUSTOM);
+
+  // Create 3 windows.  A root window, an arbitrary window parented to the root
+  // but NOT positioned at (0,0) relative to the root, and then a third window
+  // parented to the second, also not positioned at (0,0).
+  Widget::InitParams params1 =
+      CreateParams(Widget::InitParams::TYPE_WINDOW);
+  params1.bounds = gfx::Rect(origin, gfx::Size(700, 600));
+  params1.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params1.native_widget = new DesktopNativeWidgetAura(&widget1);
+  widget1.Init(params1);
+
+  Widget::InitParams params2 =
+    CreateParams(Widget::InitParams::TYPE_WINDOW);
+  params2.bounds = gfx::Rect(origin, gfx::Size(600, 500));
+  params2.parent = widget1.GetNativeView();
+  params2.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params2.child = true;
+  widget2.Init(params2);
+
+  Widget::InitParams params3 =
+      CreateParams(Widget::InitParams::TYPE_CONTROL);
+  params3.parent = widget2.GetNativeView();
+  params3.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
+  params3.child = true;
+  params3.bounds = gfx::Rect(origin, gfx::Size(500, 400));
+  widget3.Init(params3);
+
+  // The origin of the 3rd window should be the sum of all parent origins.
+  gfx::Point expected_origin(origin.x() * 3, origin.y() * 3);
+  gfx::Rect expected_bounds(expected_origin, gfx::Size(500, 400));
+  gfx::Rect actual_bounds(widget3.GetWindowBoundsInScreen());
+  EXPECT_EQ(expected_bounds.ToString(), actual_bounds.ToString());
+}
+
 }  // namespace views
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index f27ad8c..1a62709 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1030,17 +1030,16 @@
   }
 }
 
-gfx::Insets HWNDMessageHandler::GetClientAreaInsets() const {
-  gfx::Insets insets;
-  if (delegate_->GetClientAreaInsets(&insets))
-    return insets;
-  DCHECK(insets.empty());
+bool HWNDMessageHandler::GetClientAreaInsets(gfx::Insets* insets) const {
+  if (delegate_->GetClientAreaInsets(insets))
+    return true;
+  DCHECK(insets->empty());
 
-  // Returning an empty Insets object causes the default handling in
-  // NativeWidgetWin::OnNCCalcSize() to be invoked.
+  // Returning false causes the default handling in OnNCCalcSize() to
+  // be invoked.
   if (!delegate_->IsWidgetWindow() ||
       (!delegate_->IsUsingCustomFrame() && !remove_standard_frame_)) {
-    return insets;
+    return false;
   }
 
   if (IsMaximized()) {
@@ -1049,8 +1048,9 @@
     int border_thickness = GetSystemMetrics(SM_CXSIZEFRAME);
     if (remove_standard_frame_)
       border_thickness -= 1;
-    return gfx::Insets(border_thickness, border_thickness, border_thickness,
-                       border_thickness);
+    *insets = gfx::Insets(
+        border_thickness, border_thickness, border_thickness, border_thickness);
+    return true;
   }
 
   // Returning empty insets for a window with the standard frame removed seems
@@ -1067,8 +1067,17 @@
   // means that the client area is reported 1px larger than it really is, so
   // user code has to compensate by making its content shorter if it wants
   // everything to appear inside the window.
-  if (remove_standard_frame_)
-    return gfx::Insets(0, 0, IsMaximized() ? 0 : kClientAreaBottomInsetHack, 0);
+  if (remove_standard_frame_) {
+    *insets =
+        gfx::Insets(0, 0, IsMaximized() ? 0 : kClientAreaBottomInsetHack, 0);
+    return true;
+  }
+
+#if defined(USE_AURA)
+  // The -1 hack below breaks rendering in Aura.
+  // See http://crbug.com/172099 http://crbug.com/267131
+  *insets = gfx::Insets();
+#else
   // This is weird, but highly essential. If we don't offset the bottom edge
   // of the client rect, the window client area and window area will match,
   // and when returning to glass rendering mode from non-glass, the client
@@ -1080,7 +1089,9 @@
   // rect when using the opaque frame.
   // Note: this is only required for non-fullscreen windows. Note that
   // fullscreen windows are in restored state, not maximized.
-  return gfx::Insets(0, 0, fullscreen_handler_->fullscreen() ? 0 : 1, 0);
+  *insets = gfx::Insets(0, 0, fullscreen_handler_->fullscreen() ? 0 : 1, 0);
+#endif
+  return true;
 }
 
 void HWNDMessageHandler::ResetWindowRegion(bool force) {
@@ -1643,8 +1654,9 @@
     }
   }
 
-  gfx::Insets insets = GetClientAreaInsets();
-  if (insets.empty() && !fullscreen_handler_->fullscreen() &&
+  gfx::Insets insets;
+  bool got_insets = GetClientAreaInsets(&insets);
+  if (!got_insets && !fullscreen_handler_->fullscreen() &&
       !(mode && remove_standard_frame_)) {
     SetMsgHandled(FALSE);
     return 0;
diff --git a/ui/views/win/hwnd_message_handler.h b/ui/views/win/hwnd_message_handler.h
index d9e20d7..c1c724c 100644
--- a/ui/views/win/hwnd_message_handler.h
+++ b/ui/views/win/hwnd_message_handler.h
@@ -196,7 +196,7 @@
 
   // Returns the insets of the client area relative to the non-client area of
   // the window.
-  gfx::Insets GetClientAreaInsets() const;
+  bool GetClientAreaInsets(gfx::Insets* insets) const;
 
   // Resets the window region for the current widget bounds if necessary.
   // If |force| is true, the window region is reset to NULL even for native
diff --git a/ui/webui/resources/js/cr/ui/context_menu_handler.js b/ui/webui/resources/js/cr/ui/context_menu_handler.js
index 30ab13c..05264d6 100644
--- a/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -35,8 +35,11 @@
      * @param {!cr.ui.Menu} menu The menu to show.
      */
     showMenu: function(e, menu) {
-      this.menu_ = menu;
       menu.updateCommands(e.currentTarget);
+      if (!menu.hasVisibleItems())
+        return;
+
+      this.menu_ = menu;
       menu.classList.remove('hide-delayed');
       menu.hidden = false;
       menu.contextElement = e.currentTarget;
diff --git a/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
index e5b2476..fd106c2 100644
--- a/ui/webui/resources/js/cr/ui/focus_outline_manager.js
+++ b/ui/webui/resources/js/cr/ui/focus_outline_manager.js
@@ -32,11 +32,16 @@
     var self = this;
     doc.addEventListener('keydown', function(e) {
       if (e.keyCode == 9)  // Tab
-        self.visible = true;
+        self.focusByKeyboard_ = true;
     }, true);
 
     doc.addEventListener('mousedown', function(e) {
-      self.visible = false;
+      self.focusByKeyboard_ = false;
+    }, true);
+
+    doc.addEventListener('focus', function(event) {
+      // Update visibility only when focus is actually changed.
+      self.visible = self.focusByKeyboard_;
     }, true);
   }
 
@@ -48,6 +53,13 @@
 
   FocusOutlineManager.prototype = {
     /**
+     * Whether focus change is triggered by TAB key.
+     * @type {boolean}
+     * @private
+     */
+    focusByKeyboard_: false,
+
+    /**
      * Whether the focus outline should be visible.
      * @type {boolean}
      */
diff --git a/ui/webui/resources/js/cr/ui/menu.js b/ui/webui/resources/js/cr/ui/menu.js
index 3047123..4956b38 100644
--- a/ui/webui/resources/js/cr/ui/menu.js
+++ b/ui/webui/resources/js/cr/ui/menu.js
@@ -144,8 +144,10 @@
         this.selectedIndex = 0;
       }
 
-      if (this.selectedItem)
+      if (this.selectedItem) {
         this.selectedItem.focus();
+        this.setAttribute('aria-activedescendant', this.selectedItem.id);
+      }
     },
 
     /**
@@ -156,6 +158,19 @@
     },
 
     /**
+     * Returns if the menu has any visible item.
+     * @return {boolean} True if the menu has visible item. Otherwise, false.
+     */
+    hasVisibleItems: function() {
+      var menuItems = this.menuItems;  // Cache.
+      for (var i = 0, menuItem; menuItem = menuItems[i]; i++) {
+        if (!menuItem.hidden)
+          return true;
+      }
+      return false;
+    },
+
+    /**
      * This is the function that handles keyboard navigation. This is usually
      * called by the element responsible for managing the menu.
      * @param {Event} e The keydown event object.
diff --git a/ui/webui/resources/js/cr/ui/menu_item.js b/ui/webui/resources/js/cr/ui/menu_item.js
index d1ab2ea..89054e2 100644
--- a/ui/webui/resources/js/cr/ui/menu_item.js
+++ b/ui/webui/resources/js/cr/ui/menu_item.js
@@ -40,7 +40,10 @@
       // the appearance of this element.
       this.classList.add('custom-appearance');
 
-      this.setAttribute('role', 'menuitem');
+      // Enable Text to Speech on the menu. Additionaly, ID has to be set, since
+      // it is used in element's aria-activedescendant attribute.
+      if (!this.isSeparator())
+        this.setAttribute('role', 'menuitem');
 
       var iconUrl;
       if ((iconUrl = this.getAttribute('icon')))
diff --git a/webkit/browser/dom_storage/OWNERS b/webkit/browser/dom_storage/OWNERS
deleted file mode 100644
index 88ceed4..0000000
--- a/webkit/browser/dom_storage/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-marja@chromium.org
diff --git a/webkit/browser/dom_storage/dom_storage_context.cc b/webkit/browser/dom_storage/dom_storage_context.cc
deleted file mode 100644
index 5d7229d..0000000
--- a/webkit/browser/dom_storage/dom_storage_context.cc
+++ /dev/null
@@ -1,418 +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 "webkit/browser/dom_storage/dom_storage_context.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/file_util.h"
-#include "base/files/file_enumerator.h"
-#include "base/guid.h"
-#include "base/location.h"
-#include "base/time/time.h"
-#include "webkit/browser/dom_storage/dom_storage_area.h"
-#include "webkit/browser/dom_storage/dom_storage_database.h"
-#include "webkit/browser/dom_storage/dom_storage_namespace.h"
-#include "webkit/browser/dom_storage/dom_storage_task_runner.h"
-#include "webkit/browser/dom_storage/session_storage_database.h"
-#include "webkit/browser/quota/special_storage_policy.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
-
-namespace dom_storage {
-
-static const int kSessionStoraceScavengingSeconds = 60;
-
-DomStorageContext::DomStorageContext(
-    const base::FilePath& localstorage_directory,
-    const base::FilePath& sessionstorage_directory,
-    quota::SpecialStoragePolicy* special_storage_policy,
-    DomStorageTaskRunner* task_runner)
-    : localstorage_directory_(localstorage_directory),
-      sessionstorage_directory_(sessionstorage_directory),
-      task_runner_(task_runner),
-      is_shutdown_(false),
-      force_keep_session_state_(false),
-      special_storage_policy_(special_storage_policy),
-      scavenging_started_(false) {
-  // AtomicSequenceNum starts at 0 but we want to start session
-  // namespace ids at one since zero is reserved for the
-  // kLocalStorageNamespaceId.
-  session_id_sequence_.GetNext();
-}
-
-DomStorageContext::~DomStorageContext() {
-  if (session_storage_database_.get()) {
-    // SessionStorageDatabase shouldn't be deleted right away: deleting it will
-    // potentially involve waiting in leveldb::DBImpl::~DBImpl, and waiting
-    // shouldn't happen on this thread.
-    SessionStorageDatabase* to_release = session_storage_database_.get();
-    to_release->AddRef();
-    session_storage_database_ = NULL;
-    task_runner_->PostShutdownBlockingTask(
-        FROM_HERE,
-        DomStorageTaskRunner::COMMIT_SEQUENCE,
-        base::Bind(&SessionStorageDatabase::Release,
-                   base::Unretained(to_release)));
-  }
-}
-
-DomStorageNamespace* DomStorageContext::GetStorageNamespace(
-    int64 namespace_id) {
-  if (is_shutdown_)
-    return NULL;
-  StorageNamespaceMap::iterator found = namespaces_.find(namespace_id);
-  if (found == namespaces_.end()) {
-    if (namespace_id == kLocalStorageNamespaceId) {
-      if (!localstorage_directory_.empty()) {
-        if (!file_util::CreateDirectory(localstorage_directory_)) {
-          LOG(ERROR) << "Failed to create 'Local Storage' directory,"
-                        " falling back to in-memory only.";
-          localstorage_directory_ = base::FilePath();
-        }
-      }
-      DomStorageNamespace* local =
-          new DomStorageNamespace(localstorage_directory_, task_runner_.get());
-      namespaces_[kLocalStorageNamespaceId] = local;
-      return local;
-    }
-    return NULL;
-  }
-  return found->second.get();
-}
-
-void DomStorageContext::GetLocalStorageUsage(
-    std::vector<LocalStorageUsageInfo>* infos,
-    bool include_file_info) {
-  if (localstorage_directory_.empty())
-    return;
-  base::FileEnumerator enumerator(localstorage_directory_, false,
-                                  base::FileEnumerator::FILES);
-  for (base::FilePath path = enumerator.Next(); !path.empty();
-       path = enumerator.Next()) {
-    if (path.MatchesExtension(DomStorageArea::kDatabaseFileExtension)) {
-      LocalStorageUsageInfo info;
-      info.origin = DomStorageArea::OriginFromDatabaseFileName(path);
-      if (include_file_info) {
-        base::FileEnumerator::FileInfo find_info = enumerator.GetInfo();
-        info.data_size = find_info.GetSize();
-        info.last_modified = find_info.GetLastModifiedTime();
-      }
-      infos->push_back(info);
-    }
-  }
-}
-
-void DomStorageContext::GetSessionStorageUsage(
-    std::vector<SessionStorageUsageInfo>* infos) {
-  if (!session_storage_database_.get())
-    return;
-  std::map<std::string, std::vector<GURL> > namespaces_and_origins;
-  session_storage_database_->ReadNamespacesAndOrigins(
-      &namespaces_and_origins);
-  for (std::map<std::string, std::vector<GURL> >::const_iterator it =
-           namespaces_and_origins.begin();
-       it != namespaces_and_origins.end(); ++it) {
-    for (std::vector<GURL>::const_iterator origin_it = it->second.begin();
-         origin_it != it->second.end(); ++origin_it) {
-      SessionStorageUsageInfo info;
-      info.persistent_namespace_id = it->first;
-      info.origin = *origin_it;
-      infos->push_back(info);
-    }
-  }
-}
-
-void DomStorageContext::DeleteLocalStorage(const GURL& origin) {
-  DCHECK(!is_shutdown_);
-  DomStorageNamespace* local = GetStorageNamespace(kLocalStorageNamespaceId);
-  local->DeleteLocalStorageOrigin(origin);
-  // Synthesize a 'cleared' event if the area is open so CachedAreas in
-  // renderers get emptied out too.
-  DomStorageArea* area = local->GetOpenStorageArea(origin);
-  if (area)
-    NotifyAreaCleared(area, origin);
-}
-
-void DomStorageContext::DeleteSessionStorage(
-    const SessionStorageUsageInfo& usage_info) {
-  DCHECK(!is_shutdown_);
-  DomStorageNamespace* dom_storage_namespace = NULL;
-  std::map<std::string, int64>::const_iterator it =
-      persistent_namespace_id_to_namespace_id_.find(
-          usage_info.persistent_namespace_id);
-  if (it != persistent_namespace_id_to_namespace_id_.end()) {
-    dom_storage_namespace = GetStorageNamespace(it->second);
-  } else {
-    int64 namespace_id = AllocateSessionId();
-    CreateSessionNamespace(namespace_id, usage_info.persistent_namespace_id);
-    dom_storage_namespace = GetStorageNamespace(namespace_id);
-  }
-  dom_storage_namespace->DeleteSessionStorageOrigin(usage_info.origin);
-  // Synthesize a 'cleared' event if the area is open so CachedAreas in
-  // renderers get emptied out too.
-  DomStorageArea* area =
-      dom_storage_namespace->GetOpenStorageArea(usage_info.origin);
-  if (area)
-    NotifyAreaCleared(area, usage_info.origin);
-}
-
-void DomStorageContext::PurgeMemory() {
-  // We can only purge memory from the local storage namespace
-  // which is backed by disk.
-  // TODO(marja): Purge sessionStorage, too. (Requires changes to the FastClear
-  // functionality.)
-  StorageNamespaceMap::iterator found =
-      namespaces_.find(kLocalStorageNamespaceId);
-  if (found != namespaces_.end())
-    found->second->PurgeMemory(DomStorageNamespace::PURGE_AGGRESSIVE);
-}
-
-void DomStorageContext::Shutdown() {
-  is_shutdown_ = true;
-  StorageNamespaceMap::const_iterator it = namespaces_.begin();
-  for (; it != namespaces_.end(); ++it)
-    it->second->Shutdown();
-
-  if (localstorage_directory_.empty() && !session_storage_database_.get())
-    return;
-
-  // Respect the content policy settings about what to
-  // keep and what to discard.
-  if (force_keep_session_state_)
-    return;  // Keep everything.
-
-  bool has_session_only_origins =
-      special_storage_policy_.get() &&
-      special_storage_policy_->HasSessionOnlyOrigins();
-
-  if (has_session_only_origins) {
-    // We may have to delete something. We continue on the
-    // commit sequence after area shutdown tasks have cycled
-    // thru that sequence (and closed their database files).
-    bool success = task_runner_->PostShutdownBlockingTask(
-        FROM_HERE,
-        DomStorageTaskRunner::COMMIT_SEQUENCE,
-        base::Bind(&DomStorageContext::ClearSessionOnlyOrigins, this));
-    DCHECK(success);
-  }
-}
-
-void DomStorageContext::AddEventObserver(EventObserver* observer) {
-  event_observers_.AddObserver(observer);
-}
-
-void DomStorageContext::RemoveEventObserver(EventObserver* observer) {
-  event_observers_.RemoveObserver(observer);
-}
-
-void DomStorageContext::NotifyItemSet(
-    const DomStorageArea* area,
-    const base::string16& key,
-    const base::string16& new_value,
-    const base::NullableString16& old_value,
-    const GURL& page_url) {
-  FOR_EACH_OBSERVER(
-      EventObserver, event_observers_,
-      OnDomStorageItemSet(area, key, new_value, old_value, page_url));
-}
-
-void DomStorageContext::NotifyItemRemoved(
-    const DomStorageArea* area,
-    const base::string16& key,
-    const base::string16& old_value,
-    const GURL& page_url) {
-  FOR_EACH_OBSERVER(
-      EventObserver, event_observers_,
-      OnDomStorageItemRemoved(area, key, old_value, page_url));
-}
-
-void DomStorageContext::NotifyAreaCleared(
-    const DomStorageArea* area,
-    const GURL& page_url) {
-  FOR_EACH_OBSERVER(
-      EventObserver, event_observers_,
-      OnDomStorageAreaCleared(area, page_url));
-}
-
-std::string DomStorageContext::AllocatePersistentSessionId() {
-  std::string guid = base::GenerateGUID();
-  std::replace(guid.begin(), guid.end(), '-', '_');
-  return guid;
-}
-
-void DomStorageContext::CreateSessionNamespace(
-    int64 namespace_id,
-    const std::string& persistent_namespace_id) {
-  if (is_shutdown_)
-    return;
-  DCHECK(namespace_id != kLocalStorageNamespaceId);
-  DCHECK(namespaces_.find(namespace_id) == namespaces_.end());
-  namespaces_[namespace_id] = new DomStorageNamespace(
-      namespace_id, persistent_namespace_id, session_storage_database_.get(),
-      task_runner_.get());
-  persistent_namespace_id_to_namespace_id_[persistent_namespace_id] =
-      namespace_id;
-}
-
-void DomStorageContext::DeleteSessionNamespace(
-    int64 namespace_id, bool should_persist_data) {
-  DCHECK_NE(kLocalStorageNamespaceId, namespace_id);
-  StorageNamespaceMap::const_iterator it = namespaces_.find(namespace_id);
-  if (it == namespaces_.end())
-    return;
-  std::string persistent_namespace_id = it->second->persistent_namespace_id();
-  if (session_storage_database_.get()) {
-    if (!should_persist_data) {
-      task_runner_->PostShutdownBlockingTask(
-          FROM_HERE,
-          DomStorageTaskRunner::COMMIT_SEQUENCE,
-          base::Bind(
-              base::IgnoreResult(&SessionStorageDatabase::DeleteNamespace),
-              session_storage_database_,
-              persistent_namespace_id));
-    } else {
-      // Ensure that the data gets committed before we shut down.
-      it->second->Shutdown();
-      if (!scavenging_started_) {
-        // Protect the persistent namespace ID from scavenging.
-        protected_persistent_session_ids_.insert(persistent_namespace_id);
-      }
-    }
-  }
-  persistent_namespace_id_to_namespace_id_.erase(persistent_namespace_id);
-  namespaces_.erase(namespace_id);
-}
-
-void DomStorageContext::CloneSessionNamespace(
-    int64 existing_id, int64 new_id,
-    const std::string& new_persistent_id) {
-  if (is_shutdown_)
-    return;
-  DCHECK_NE(kLocalStorageNamespaceId, existing_id);
-  DCHECK_NE(kLocalStorageNamespaceId, new_id);
-  StorageNamespaceMap::iterator found = namespaces_.find(existing_id);
-  if (found != namespaces_.end())
-    namespaces_[new_id] = found->second->Clone(new_id, new_persistent_id);
-  else
-    CreateSessionNamespace(new_id, new_persistent_id);
-}
-
-void DomStorageContext::ClearSessionOnlyOrigins() {
-  if (!localstorage_directory_.empty()) {
-    std::vector<LocalStorageUsageInfo> infos;
-    const bool kDontIncludeFileInfo = false;
-    GetLocalStorageUsage(&infos, kDontIncludeFileInfo);
-    for (size_t i = 0; i < infos.size(); ++i) {
-      const GURL& origin = infos[i].origin;
-      if (special_storage_policy_->IsStorageProtected(origin))
-        continue;
-      if (!special_storage_policy_->IsStorageSessionOnly(origin))
-        continue;
-
-      base::FilePath database_file_path = localstorage_directory_.Append(
-          DomStorageArea::DatabaseFileNameFromOrigin(origin));
-      sql::Connection::Delete(database_file_path);
-    }
-  }
-  if (session_storage_database_.get()) {
-    std::vector<SessionStorageUsageInfo> infos;
-    GetSessionStorageUsage(&infos);
-    for (size_t i = 0; i < infos.size(); ++i) {
-      const GURL& origin = infos[i].origin;
-      if (special_storage_policy_->IsStorageProtected(origin))
-        continue;
-      if (!special_storage_policy_->IsStorageSessionOnly(origin))
-        continue;
-      session_storage_database_->DeleteArea(infos[i].persistent_namespace_id,
-                                            origin);
-    }
-  }
-}
-
-void DomStorageContext::SetSaveSessionStorageOnDisk() {
-  DCHECK(namespaces_.empty());
-  if (!sessionstorage_directory_.empty()) {
-    session_storage_database_ = new SessionStorageDatabase(
-        sessionstorage_directory_);
-  }
-}
-
-void DomStorageContext::StartScavengingUnusedSessionStorage() {
-  if (session_storage_database_.get()) {
-    task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(&DomStorageContext::FindUnusedNamespaces, this),
-        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
-  }
-}
-
-void DomStorageContext::FindUnusedNamespaces() {
-  DCHECK(session_storage_database_.get());
-  if (scavenging_started_)
-    return;
-  scavenging_started_ = true;
-  std::set<std::string> namespace_ids_in_use;
-  for (StorageNamespaceMap::const_iterator it = namespaces_.begin();
-       it != namespaces_.end(); ++it)
-    namespace_ids_in_use.insert(it->second->persistent_namespace_id());
-  std::set<std::string> protected_persistent_session_ids;
-  protected_persistent_session_ids.swap(protected_persistent_session_ids_);
-  task_runner_->PostShutdownBlockingTask(
-      FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
-      base::Bind(
-          &DomStorageContext::FindUnusedNamespacesInCommitSequence,
-          this, namespace_ids_in_use, protected_persistent_session_ids));
-}
-
-void DomStorageContext::FindUnusedNamespacesInCommitSequence(
-    const std::set<std::string>& namespace_ids_in_use,
-    const std::set<std::string>& protected_persistent_session_ids) {
-  DCHECK(session_storage_database_.get());
-  // Delete all namespaces which don't have an associated DomStorageNamespace
-  // alive.
-  std::map<std::string, std::vector<GURL> > namespaces_and_origins;
-  session_storage_database_->ReadNamespacesAndOrigins(&namespaces_and_origins);
-  for (std::map<std::string, std::vector<GURL> >::const_iterator it =
-           namespaces_and_origins.begin();
-       it != namespaces_and_origins.end(); ++it) {
-    if (namespace_ids_in_use.find(it->first) == namespace_ids_in_use.end() &&
-        protected_persistent_session_ids.find(it->first) ==
-        protected_persistent_session_ids.end()) {
-      deletable_persistent_namespace_ids_.push_back(it->first);
-    }
-  }
-  if (!deletable_persistent_namespace_ids_.empty()) {
-    task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(
-            &DomStorageContext::DeleteNextUnusedNamespace,
-            this),
-        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
-  }
-}
-
-void DomStorageContext::DeleteNextUnusedNamespace() {
-  if (is_shutdown_)
-    return;
-  task_runner_->PostShutdownBlockingTask(
-        FROM_HERE, DomStorageTaskRunner::COMMIT_SEQUENCE,
-        base::Bind(
-            &DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence,
-            this));
-}
-
-void DomStorageContext::DeleteNextUnusedNamespaceInCommitSequence() {
-  if (deletable_persistent_namespace_ids_.empty())
-    return;
-  const std::string& persistent_id = deletable_persistent_namespace_ids_.back();
-  session_storage_database_->DeleteNamespace(persistent_id);
-  deletable_persistent_namespace_ids_.pop_back();
-  if (!deletable_persistent_namespace_ids_.empty()) {
-    task_runner_->PostDelayedTask(
-        FROM_HERE, base::Bind(
-            &DomStorageContext::DeleteNextUnusedNamespace,
-            this),
-        base::TimeDelta::FromSeconds(kSessionStoraceScavengingSeconds));
-  }
-}
-
-}  // namespace dom_storage
diff --git a/webkit/browser/dom_storage/dom_storage_context.h b/webkit/browser/dom_storage/dom_storage_context.h
deleted file mode 100644
index 9005d61..0000000
--- a/webkit/browser/dom_storage/dom_storage_context.h
+++ /dev/null
@@ -1,231 +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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_H_
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/atomic_sequence_num.h"
-#include "base/basictypes.h"
-#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/observer_list.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-
-namespace base {
-class FilePath;
-class NullableString16;
-class Time;
-}
-
-namespace quota {
-class SpecialStoragePolicy;
-}
-
-namespace dom_storage {
-
-class DomStorageArea;
-class DomStorageNamespace;
-class DomStorageSession;
-class DomStorageTaskRunner;
-class SessionStorageDatabase;
-struct LocalStorageUsageInfo;
-struct SessionStorageUsageInfo;
-
-// The Context is the root of an object containment hierachy for
-// Namespaces and Areas related to the owning profile.
-// One instance is allocated in the main process for each profile,
-// instance methods should be called serially in the background as
-// determined by the task_runner. Specifcally not on chrome's non-blocking
-// IO thread since these methods can result in blocking file io.
-//
-// In general terms, the DomStorage object relationships are...
-//   Contexts (per-profile) own Namespaces which own Areas which share Maps.
-//   Hosts(per-renderer) refer to Namespaces and Areas open in its renderer.
-//   Sessions (per-tab) cause the creation and deletion of session Namespaces.
-//
-// Session Namespaces are cloned by initially making a shallow copy of
-// all contained Areas, the shallow copies refer to the same refcounted Map,
-// and does a deep copy-on-write if needed.
-//
-// Classes intended to be used by an embedder are DomStorageContext,
-// DomStorageHost, and DomStorageSession. The other classes are for
-// internal consumption.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageContext
-    : public base::RefCountedThreadSafe<DomStorageContext> {
- public:
-  // An interface for observing Local and Session Storage events on the
-  // background thread.
-  class EventObserver {
-   public:
-    virtual void OnDomStorageItemSet(
-        const DomStorageArea* area,
-        const base::string16& key,
-        const base::string16& new_value,
-        const base::NullableString16& old_value,  // may be null on initial insert
-        const GURL& page_url) = 0;
-    virtual void OnDomStorageItemRemoved(
-        const DomStorageArea* area,
-        const base::string16& key,
-        const base::string16& old_value,
-        const GURL& page_url) = 0;
-    virtual void OnDomStorageAreaCleared(
-        const DomStorageArea* area,
-        const GURL& page_url) = 0;
-
-   protected:
-    virtual ~EventObserver() {}
-  };
-
-  DomStorageContext(
-      const base::FilePath& localstorage_directory,  // empty for incognito profiles
-      const base::FilePath& sessionstorage_directory,  // empty for incognito profiles
-      quota::SpecialStoragePolicy* special_storage_policy,
-      DomStorageTaskRunner* task_runner);
-
-  // Returns the directory path for localStorage, or an empty directory, if
-  // there is no backing on disk.
-  const base::FilePath& localstorage_directory() {
-    return localstorage_directory_;
-  }
-
-  // Returns the directory path for sessionStorage, or an empty directory, if
-  // there is no backing on disk.
-  const base::FilePath& sessionstorage_directory() {
-    return sessionstorage_directory_;
-  }
-
-  DomStorageTaskRunner* task_runner() const { return task_runner_.get(); }
-  DomStorageNamespace* GetStorageNamespace(int64 namespace_id);
-
-  void GetLocalStorageUsage(std::vector<LocalStorageUsageInfo>* infos,
-                            bool include_file_info);
-  void GetSessionStorageUsage(std::vector<SessionStorageUsageInfo>* infos);
-  void DeleteLocalStorage(const GURL& origin);
-  void DeleteSessionStorage(const SessionStorageUsageInfo& usage_info);
-  void PurgeMemory();
-
-  // Used by content settings to alter the behavior around
-  // what data to keep and what data to discard at shutdown.
-  // The policy is not so straight forward to describe, see
-  // the implementation for details.
-  void SetForceKeepSessionState() {
-    force_keep_session_state_ = true;
-  }
-
-  // Called when the owning BrowserContext is ending.
-  // Schedules the commit of any unsaved changes and will delete
-  // and keep data on disk per the content settings and special storage
-  // policies. Contained areas and namespaces will stop functioning after
-  // this method has been called.
-  void Shutdown();
-
-  // Methods to add, remove, and notify EventObservers.
-  void AddEventObserver(EventObserver* observer);
-  void RemoveEventObserver(EventObserver* observer);
-  void NotifyItemSet(
-      const DomStorageArea* area,
-      const base::string16& key,
-      const base::string16& new_value,
-      const base::NullableString16& old_value,
-      const GURL& page_url);
-  void NotifyItemRemoved(
-      const DomStorageArea* area,
-      const base::string16& key,
-      const base::string16& old_value,
-      const GURL& page_url);
-  void NotifyAreaCleared(
-      const DomStorageArea* area,
-      const GURL& page_url);
-
-  // May be called on any thread.
-  int64 AllocateSessionId() {
-    return session_id_sequence_.GetNext();
-  }
-
-  std::string AllocatePersistentSessionId();
-
-  // Must be called on the background thread.
-  void CreateSessionNamespace(int64 namespace_id,
-                              const std::string& persistent_namespace_id);
-  void DeleteSessionNamespace(int64 namespace_id, bool should_persist_data);
-  void CloneSessionNamespace(int64 existing_id, int64 new_id,
-                             const std::string& new_persistent_id);
-
-  // Starts backing sessionStorage on disk. This function must be called right
-  // after DomStorageContext is created, before it's used.
-  void SetSaveSessionStorageOnDisk();
-
-  // Deletes all namespaces which don't have an associated DomStorageNamespace
-  // alive. This function is used for deleting possible leftover data after an
-  // unclean exit.
-  void StartScavengingUnusedSessionStorage();
-
- private:
-  friend class DomStorageContextTest;
-  FRIEND_TEST_ALL_PREFIXES(DomStorageContextTest, Basics);
-  friend class base::RefCountedThreadSafe<DomStorageContext>;
-  typedef std::map<int64, scoped_refptr<DomStorageNamespace> >
-      StorageNamespaceMap;
-
-  ~DomStorageContext();
-
-  void ClearSessionOnlyOrigins();
-
-  // For scavenging unused sessionStorages.
-  void FindUnusedNamespaces();
-  void FindUnusedNamespacesInCommitSequence(
-      const std::set<std::string>& namespace_ids_in_use,
-      const std::set<std::string>& protected_persistent_session_ids);
-  void DeleteNextUnusedNamespace();
-  void DeleteNextUnusedNamespaceInCommitSequence();
-
-  // Collection of namespaces keyed by id.
-  StorageNamespaceMap namespaces_;
-
-  // Where localstorage data is stored, maybe empty for the incognito use case.
-  base::FilePath localstorage_directory_;
-
-  // Where sessionstorage data is stored, maybe empty for the incognito use
-  // case. Always empty until the file-backed session storage feature is
-  // implemented.
-  base::FilePath sessionstorage_directory_;
-
-  // Used to schedule sequenced background tasks.
-  scoped_refptr<DomStorageTaskRunner> task_runner_;
-
-  // List of objects observing local storage events.
-  ObserverList<EventObserver> event_observers_;
-
-  // We use a 32 bit identifier for per tab storage sessions.
-  // At a tab per second, this range is large enough for 68 years.
-  base::AtomicSequenceNumber session_id_sequence_;
-
-  bool is_shutdown_;
-  bool force_keep_session_state_;
-  scoped_refptr<quota::SpecialStoragePolicy> special_storage_policy_;
-  scoped_refptr<SessionStorageDatabase> session_storage_database_;
-
-  // For cleaning up unused namespaces gradually.
-  bool scavenging_started_;
-  std::vector<std::string> deletable_persistent_namespace_ids_;
-
-  // Persistent namespace IDs to protect from gradual deletion (they will
-  // be needed for session restore).
-  std::set<std::string> protected_persistent_session_ids_;
-
-  // Mapping between persistent namespace IDs and namespace IDs for
-  // sessionStorage.
-  std::map<std::string, int64> persistent_namespace_id_to_namespace_id_;
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_CONTEXT_H_
diff --git a/webkit/browser/dom_storage/dom_storage_database_adapter.h b/webkit/browser/dom_storage/dom_storage_database_adapter.h
deleted file mode 100644
index 360e6bd..0000000
--- a/webkit/browser/dom_storage/dom_storage_database_adapter.h
+++ /dev/null
@@ -1,29 +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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
-
-// Database interface used by DomStorageArea. Abstracts the differences between
-// the per-origin DomStorageDatabases for localStorage and
-// SessionStorageDatabase which stores multiple origins.
-
-#include "webkit/browser/webkit_storage_browser_export.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
-
-namespace dom_storage {
-
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageDatabaseAdapter {
- public:
-  virtual ~DomStorageDatabaseAdapter() {}
-  virtual void ReadAllValues(ValuesMap* result) = 0;
-  virtual bool CommitChanges(
-      bool clear_all_first, const ValuesMap& changes) = 0;
-  virtual void DeleteFiles() {}
-  virtual void Reset() {}
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/dom_storage/dom_storage_session.h b/webkit/browser/dom_storage/dom_storage_session.h
deleted file mode 100644
index b500859..0000000
--- a/webkit/browser/dom_storage/dom_storage_session.h
+++ /dev/null
@@ -1,65 +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 WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/memory/ref_counted.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-
-namespace dom_storage {
-
-class DomStorageContext;
-
-// This refcounted class determines the lifetime of a session
-// storage namespace and provides an interface to Clone() an
-// existing session storage namespace. It may be used on any thread.
-// See class comments for DomStorageContext for a larger overview.
-class WEBKIT_STORAGE_BROWSER_EXPORT DomStorageSession
-    : public base::RefCountedThreadSafe<DomStorageSession> {
- public:
-  // Constructs a |DomStorageSession| and allocates new IDs for it.
-  explicit DomStorageSession(DomStorageContext* context);
-
-  // Constructs a |DomStorageSession| and assigns |persistent_namespace_id|
-  // to it. Allocates a new non-persistent ID.
-  DomStorageSession(DomStorageContext* context,
-                    const std::string& persistent_namespace_id);
-
-  int64 namespace_id() const { return namespace_id_; }
-  const std::string& persistent_namespace_id() const {
-    return persistent_namespace_id_;
-  }
-  void SetShouldPersist(bool should_persist);
-  bool should_persist() const;
-  bool IsFromContext(DomStorageContext* context);
-  DomStorageSession* Clone();
-
-  // Constructs a |DomStorageSession| by cloning
-  // |namespace_id_to_clone|. Allocates new IDs for it.
-  static DomStorageSession* CloneFrom(DomStorageContext* context,
-                                      int64 namepace_id_to_clone);
-
- private:
-  friend class base::RefCountedThreadSafe<DomStorageSession>;
-
-  DomStorageSession(DomStorageContext* context,
-                    int64 namespace_id,
-                    const std::string& persistent_namespace_id);
-  ~DomStorageSession();
-
-  scoped_refptr<DomStorageContext> context_;
-  int64 namespace_id_;
-  std::string persistent_namespace_id_;
-  bool should_persist_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(DomStorageSession);
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_DOM_STORAGE_SESSION_H_
diff --git a/webkit/browser/dom_storage/local_storage_database_adapter.cc b/webkit/browser/dom_storage/local_storage_database_adapter.cc
deleted file mode 100644
index 681939e..0000000
--- a/webkit/browser/dom_storage/local_storage_database_adapter.cc
+++ /dev/null
@@ -1,40 +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 "webkit/browser/dom_storage/local_storage_database_adapter.h"
-
-#include "base/file_util.h"
-#include "webkit/browser/dom_storage/dom_storage_database.h"
-
-namespace dom_storage {
-
-LocalStorageDatabaseAdapter::LocalStorageDatabaseAdapter(
-    const base::FilePath& path)
-    : db_(new DomStorageDatabase(path)) {
-}
-
-LocalStorageDatabaseAdapter::~LocalStorageDatabaseAdapter() { }
-
-void LocalStorageDatabaseAdapter::ReadAllValues(ValuesMap* result) {
-  db_->ReadAllValues(result);
-}
-
-bool LocalStorageDatabaseAdapter::CommitChanges(
-    bool clear_all_first, const ValuesMap& changes) {
-  return db_->CommitChanges(clear_all_first, changes);
-}
-
-void LocalStorageDatabaseAdapter::DeleteFiles() {
-  sql::Connection::Delete(db_->file_path());
-}
-
-void LocalStorageDatabaseAdapter::Reset() {
-  db_.reset(new DomStorageDatabase(db_->file_path()));
-}
-
-LocalStorageDatabaseAdapter::LocalStorageDatabaseAdapter()
-    : db_(new DomStorageDatabase()) {
-}
-
-}  // namespace dom_storage
diff --git a/webkit/browser/dom_storage/local_storage_database_adapter.h b/webkit/browser/dom_storage/local_storage_database_adapter.h
deleted file mode 100644
index 7cdabf4..0000000
--- a/webkit/browser/dom_storage/local_storage_database_adapter.h
+++ /dev/null
@@ -1,50 +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 WEBKIT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
-
-#include "base/gtest_prod_util.h"
-#include "base/memory/scoped_ptr.h"
-#include "webkit/browser/dom_storage/dom_storage_database_adapter.h"
-#include "webkit/browser/webkit_storage_browser_export.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace dom_storage {
-
-class DomStorageDatabase;
-
-class WEBKIT_STORAGE_BROWSER_EXPORT LocalStorageDatabaseAdapter :
-      public DomStorageDatabaseAdapter {
- public:
-  explicit LocalStorageDatabaseAdapter(const base::FilePath& path);
-  virtual ~LocalStorageDatabaseAdapter();
-  virtual void ReadAllValues(ValuesMap* result) OVERRIDE;
-  virtual bool CommitChanges(bool clear_all_first,
-                             const ValuesMap& changes) OVERRIDE;
-  virtual void DeleteFiles() OVERRIDE;
-  virtual void Reset() OVERRIDE;
-
- protected:
-  // Constructor that uses an in-memory sqlite database, for testing.
-  LocalStorageDatabaseAdapter();
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, BackingDatabaseOpened);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, CommitChangesAtShutdown);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, CommitTasks);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, DeleteOrigin);
-  FRIEND_TEST_ALL_PREFIXES(DomStorageAreaTest, PurgeMemory);
-
-  scoped_ptr<DomStorageDatabase> db_;
-
-  DISALLOW_COPY_AND_ASSIGN(LocalStorageDatabaseAdapter);
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_LOCAL_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/dom_storage/session_storage_database_adapter.h b/webkit/browser/dom_storage/session_storage_database_adapter.h
deleted file mode 100644
index 96b7b3e..0000000
--- a/webkit/browser/dom_storage/session_storage_database_adapter.h
+++ /dev/null
@@ -1,35 +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 WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
-#define WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
-
-#include "base/memory/ref_counted.h"
-#include "url/gurl.h"
-#include "webkit/browser/dom_storage/dom_storage_database_adapter.h"
-
-namespace dom_storage {
-
-class SessionStorageDatabase;
-
-class SessionStorageDatabaseAdapter : public DomStorageDatabaseAdapter {
- public:
-  SessionStorageDatabaseAdapter(SessionStorageDatabase* db,
-                                const std::string& permanent_namespace_id,
-                                const GURL& origin);
-  virtual ~SessionStorageDatabaseAdapter();
-  virtual void ReadAllValues(ValuesMap* result) OVERRIDE;
-  virtual bool CommitChanges(bool clear_all_first,
-                             const ValuesMap& changes) OVERRIDE;
- private:
-  scoped_refptr<SessionStorageDatabase> db_;
-  std::string permanent_namespace_id_;
-  GURL origin_;
-
-  DISALLOW_COPY_AND_ASSIGN(SessionStorageDatabaseAdapter);
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_BROWSER_DOM_STORAGE_SESSION_STORAGE_DATABASE_ADAPTER_H_
diff --git a/webkit/browser/fileapi/file_system_operation_context.h b/webkit/browser/fileapi/file_system_operation_context.h
index 4fae428..4d17510 100644
--- a/webkit/browser/fileapi/file_system_operation_context.h
+++ b/webkit/browser/fileapi/file_system_operation_context.h
@@ -77,30 +77,7 @@
     root_path_ = root_path;
   }
 
-  // Gets and sets value-type (or not-owned) variable as UserData.
-  // (SetUserValue can be called only on the same thread as this context
-  // is created as well as other setters.)
-  template <typename T> T GetUserValue(const char* key) const {
-    ValueAdapter<T>* v = static_cast<ValueAdapter<T>*>(GetUserData(key));
-    return v ? v->value() : T();
-  }
-  template <typename T> void SetUserValue(const char* key, const T& value) {
-    DCHECK(setter_thread_checker_.CalledOnValidThread());
-    SetUserData(key, new ValueAdapter<T>(value));
-  }
-
  private:
-  // An adapter for setting a value-type (or not owned) data as UserData.
-  template <typename T> class ValueAdapter
-      : public base::SupportsUserData::Data {
-   public:
-    ValueAdapter(const T& value) : value_(value) {}
-    const T& value() const { return value_; }
-   private:
-    T value_;
-    DISALLOW_COPY_AND_ASSIGN(ValueAdapter);
-  };
-
   scoped_refptr<FileSystemContext> file_system_context_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/webkit/common/dom_storage/OWNERS b/webkit/common/dom_storage/OWNERS
deleted file mode 100644
index 88ceed4..0000000
--- a/webkit/common/dom_storage/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-marja@chromium.org
diff --git a/webkit/common/dom_storage/dom_storage_map.h b/webkit/common/dom_storage/dom_storage_map.h
deleted file mode 100644
index 69db984..0000000
--- a/webkit/common/dom_storage/dom_storage_map.h
+++ /dev/null
@@ -1,64 +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 WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
-#define WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
-
-#include <map>
-
-#include "base/memory/ref_counted.h"
-#include "base/strings/nullable_string16.h"
-#include "base/strings/string16.h"
-#include "webkit/common/dom_storage/dom_storage_types.h"
-#include "webkit/common/webkit_storage_common_export.h"
-
-namespace dom_storage {
-
-// A wrapper around a std::map that adds refcounting and
-// tracks the size in bytes of the keys/values, enforcing a quota.
-// See class comments for DomStorageContext for a larger overview.
-class WEBKIT_STORAGE_COMMON_EXPORT DomStorageMap
-    : public base::RefCountedThreadSafe<DomStorageMap> {
- public:
-  explicit DomStorageMap(size_t quota);
-
-  unsigned Length() const;
-  base::NullableString16 Key(unsigned index);
-  base::NullableString16 GetItem(const base::string16& key) const;
-  bool SetItem(const base::string16& key, const base::string16& value,
-               base::NullableString16* old_value);
-  bool RemoveItem(const base::string16& key, base::string16* old_value);
-
-  // Swaps this instances values_ with |map|.
-  // Note: to grandfather in pre-existing files that are overbudget,
-  // this method does not do quota checking.
-  void SwapValues(ValuesMap* map);
-
-  // Writes a copy of the current set of values_ to the |map|.
-  void ExtractValues(ValuesMap* map) const { *map = values_; }
-
-  // Creates a new instance of DomStorageMap containing
-  // a deep copy of values_.
-  DomStorageMap* DeepCopy() const;
-
-  size_t bytes_used() const { return bytes_used_; }
-  size_t quota() const { return quota_; }
-  void set_quota(size_t quota) { quota_ = quota; }
-
- private:
-  friend class base::RefCountedThreadSafe<DomStorageMap>;
-  ~DomStorageMap();
-
-  void ResetKeyIterator();
-
-  ValuesMap values_;
-  ValuesMap::const_iterator key_iterator_;
-  unsigned last_key_index_;
-  size_t bytes_used_;
-  size_t quota_;
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_MAP_H_
diff --git a/webkit/common/dom_storage/dom_storage_types.cc b/webkit/common/dom_storage/dom_storage_types.cc
deleted file mode 100644
index 256f32d..0000000
--- a/webkit/common/dom_storage/dom_storage_types.cc
+++ /dev/null
@@ -1,16 +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 "webkit/common/dom_storage/dom_storage_types.h"
-
-namespace dom_storage {
-
-LocalStorageUsageInfo::LocalStorageUsageInfo()
-    : data_size(0) {}
-LocalStorageUsageInfo::~LocalStorageUsageInfo() {}
-
-SessionStorageUsageInfo::SessionStorageUsageInfo() {}
-SessionStorageUsageInfo::~SessionStorageUsageInfo() {}
-
-}  // namespace dom_storage
diff --git a/webkit/common/dom_storage/dom_storage_types.h b/webkit/common/dom_storage/dom_storage_types.h
deleted file mode 100644
index 1d1e585..0000000
--- a/webkit/common/dom_storage/dom_storage_types.h
+++ /dev/null
@@ -1,62 +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 WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
-#define WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
-
-#include <map>
-
-#include "base/basictypes.h"
-#include "base/strings/nullable_string16.h"
-#include "base/strings/string16.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-#include "webkit/common/webkit_storage_common_export.h"
-
-namespace dom_storage {
-
-// The quota for each storage area.
-// This value is enforced in renderer processes and the browser process.
-const size_t kPerAreaQuota = 10 * 1024 * 1024;
-
-// In the browser process we allow some overage to
-// accomodate concurrent writes from different renderers
-// that were allowed because the limit imposed in the renderer
-// wasn't exceeded.
-const size_t kPerAreaOverQuotaAllowance = 100 * 1024;
-
-// Value to indicate the localstorage namespace vs non-zero
-// values for sessionstorage namespaces.
-const int64 kLocalStorageNamespaceId = 0;
-
-const int64 kInvalidSessionStorageNamespaceId = kLocalStorageNamespaceId;
-
-// Start purging memory if the number of in-memory areas exceeds this.
-const int64 kMaxInMemoryAreas = 100;
-
-// Value to indicate an area that not be opened.
-const int kInvalidAreaId = -1;
-
-typedef std::map<base::string16, base::NullableString16> ValuesMap;
-
-struct WEBKIT_STORAGE_COMMON_EXPORT LocalStorageUsageInfo {
-  GURL origin;
-  size_t data_size;
-  base::Time last_modified;
-
-  LocalStorageUsageInfo();
-  ~LocalStorageUsageInfo();
-};
-
-struct WEBKIT_STORAGE_COMMON_EXPORT SessionStorageUsageInfo {
-  GURL origin;
-  std::string persistent_namespace_id;
-
-  SessionStorageUsageInfo();
-  ~SessionStorageUsageInfo();
-};
-
-}  // namespace dom_storage
-
-#endif  // WEBKIT_COMMON_DOM_STORAGE_DOM_STORAGE_TYPES_H_
diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
index 57767ec..886e40f 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc
@@ -73,7 +73,7 @@
   scoped_ptr<WebKit::WebGraphicsContext3D> context;
   if (gfx::GLSurface::InitializeOneOff()) {
     context.reset(new WebGraphicsContext3DInProcessCommandBufferImpl(
-      attributes, false, window));
+      scoped_ptr< ::gpu::GLInProcessContext>(), attributes, false, window));
   }
   return context.Pass();
 }
@@ -83,12 +83,29 @@
 WebGraphicsContext3DInProcessCommandBufferImpl::CreateOffscreenContext(
     const WebKit::WebGraphicsContext3D::Attributes& attributes) {
   return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
-      attributes, true, gfx::kNullAcceleratedWidget))
+                             scoped_ptr< ::gpu::GLInProcessContext>(),
+                             attributes,
+                             true,
+                             gfx::kNullAcceleratedWidget))
+      .PassAs<WebKit::WebGraphicsContext3D>();
+}
+
+scoped_ptr<WebKit::WebGraphicsContext3D>
+WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
+    scoped_ptr< ::gpu::GLInProcessContext> context,
+    const WebKit::WebGraphicsContext3D::Attributes& attributes) {
+  return make_scoped_ptr(
+      new WebGraphicsContext3DInProcessCommandBufferImpl(
+          context.Pass(),
+          attributes,
+          true /* is_offscreen. Not used. */,
+          gfx::kNullAcceleratedWidget /* window. Not used. */))
       .PassAs<WebKit::WebGraphicsContext3D>();
 }
 
 WebGraphicsContext3DInProcessCommandBufferImpl::
     WebGraphicsContext3DInProcessCommandBufferImpl(
+        scoped_ptr< ::gpu::GLInProcessContext> context,
         const WebKit::WebGraphicsContext3D::Attributes& attributes,
         bool is_offscreen,
         gfx::AcceleratedWidget window)
@@ -96,6 +113,7 @@
       window_(window),
       initialized_(false),
       initialize_failed_(false),
+      context_(context.Pass()),
       gl_(NULL),
       context_lost_callback_(NULL),
       context_lost_reason_(GL_NO_ERROR),
@@ -108,6 +126,17 @@
     ~WebGraphicsContext3DInProcessCommandBufferImpl() {
 }
 
+// static
+void WebGraphicsContext3DInProcessCommandBufferImpl::ConvertAttributes(
+    const WebKit::WebGraphicsContext3D::Attributes& attributes,
+    ::gpu::GLInProcessContextAttribs* output_attribs) {
+  output_attribs->alpha_size = attributes.alpha ? 8 : 0;
+  output_attribs->depth_size = attributes.depth ? 24 : 0;
+  output_attribs->stencil_size = attributes.stencil ? 8 : 0;
+  output_attribs->samples = attributes.antialias ? 4 : 0;
+  output_attribs->sample_buffers = attributes.antialias ? 1 : 0;
+}
+
 bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
   if (initialized_)
     return true;
@@ -118,46 +147,35 @@
   // Ensure the gles2 library is initialized first in a thread safe way.
   g_gles2_initializer.Get();
 
-  // Convert WebGL context creation attributes into GLInProcessContext / EGL
-  // size requests.
-  const int alpha_size = attributes_.alpha ? 8 : 0;
-  const int depth_size = attributes_.depth ? 24 : 0;
-  const int stencil_size = attributes_.stencil ? 8 : 0;
-  const int samples = attributes_.antialias ? 4 : 0;
-  const int sample_buffers = attributes_.antialias ? 1 : 0;
-  const int32 attribs[] = {
-    GLInProcessContext::ALPHA_SIZE, alpha_size,
-    GLInProcessContext::DEPTH_SIZE, depth_size,
-    GLInProcessContext::STENCIL_SIZE, stencil_size,
-    GLInProcessContext::SAMPLES, samples,
-    GLInProcessContext::SAMPLE_BUFFERS, sample_buffers,
-    GLInProcessContext::NONE,
-  };
-
-  const char* preferred_extensions = "*";
-
-  // TODO(kbr): More work will be needed in this implementation to
-  // properly support GPU switching. Like in the out-of-process
-  // command buffer implementation, all previously created contexts
-  // will need to be lost either when the first context requesting the
-  // discrete GPU is created, or the last one is destroyed.
-  gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
-
-  base::Closure context_lost_callback =
-      base::Bind(&WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost,
-                 base::Unretained(this));
-
-  context_.reset(GLInProcessContext::CreateContext(
-      is_offscreen_,
-      window_,
-      gfx::Size(1, 1),
-      attributes_.shareResources,
-      preferred_extensions,
-      attribs,
-      gpu_preference,
-      context_lost_callback));
-
   if (!context_) {
+    const char* preferred_extensions = "*";
+
+    // TODO(kbr): More work will be needed in this implementation to
+    // properly support GPU switching. Like in the out-of-process
+    // command buffer implementation, all previously created contexts
+    // will need to be lost either when the first context requesting the
+    // discrete GPU is created, or the last one is destroyed.
+    gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu;
+
+    ::gpu::GLInProcessContextAttribs attrib_struct;
+    ConvertAttributes(attributes_, &attrib_struct),
+
+    context_.reset(GLInProcessContext::CreateContext(
+        is_offscreen_,
+        window_,
+        gfx::Size(1, 1),
+        attributes_.shareResources,
+        preferred_extensions,
+        attrib_struct,
+        gpu_preference));
+  }
+
+  if (context_) {
+    base::Closure context_lost_callback = base::Bind(
+        &WebGraphicsContext3DInProcessCommandBufferImpl::OnContextLost,
+        base::Unretained(this));
+    context_->SetContextLostCallback(context_lost_callback);
+  } else {
     initialize_failed_ = true;
     return false;
   }
diff --git a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
index 9ef3698..d3620b4 100644
--- a/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
+++ b/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.h
@@ -39,6 +39,7 @@
 
 namespace gpu {
 class GLInProcessContext;
+struct GLInProcessContextAttribs;
 }
 
 namespace webkit {
@@ -54,8 +55,18 @@
   static scoped_ptr<WebKit::WebGraphicsContext3D> CreateOffscreenContext(
       const WebKit::WebGraphicsContext3D::Attributes& attributes);
 
+  static scoped_ptr<WebKit::WebGraphicsContext3D> WrapContext(
+      scoped_ptr< ::gpu::GLInProcessContext> context,
+      const WebKit::WebGraphicsContext3D::Attributes& attributes);
+
   virtual ~WebGraphicsContext3DInProcessCommandBufferImpl();
 
+  // Convert WebGL context creation attributes into GLInProcessContext / EGL
+  // size requests.
+  static void ConvertAttributes(
+      const WebKit::WebGraphicsContext3D::Attributes& attributes,
+      ::gpu::GLInProcessContextAttribs* output_attribs);
+
   //----------------------------------------------------------------------
   // WebGraphicsContext3D methods
   virtual bool makeContextCurrent();
@@ -536,6 +547,7 @@
 
  private:
   WebGraphicsContext3DInProcessCommandBufferImpl(
+      scoped_ptr< ::gpu::GLInProcessContext> context,
       const WebKit::WebGraphicsContext3D::Attributes& attributes,
       bool is_offscreen,
       gfx::AcceleratedWidget window);
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.cc b/webkit/renderer/compositor_bindings/web_layer_impl.cc
index 4969077..0545b3a 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.cc
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.cc
@@ -362,6 +362,10 @@
 
 bool WebLayerImpl::isOrphan() const { return !layer_->layer_tree_host(); }
 
+void WebLayerImpl::setWebLayerClient(WebKit::WebLayerClient* client) {
+  web_layer_client_ = client;
+}
+
 Layer* WebLayerImpl::layer() const { return layer_.get(); }
 
 }  // namespace webkit
diff --git a/webkit/renderer/compositor_bindings/web_layer_impl.h b/webkit/renderer/compositor_bindings/web_layer_impl.h
index b92b0bf..ee5997d 100644
--- a/webkit/renderer/compositor_bindings/web_layer_impl.h
+++ b/webkit/renderer/compositor_bindings/web_layer_impl.h
@@ -27,6 +27,7 @@
 
 namespace WebKit {
 class WebFilterOperations;
+class WebLayerClient;
 struct WebFloatRect;
 }
 
@@ -117,9 +118,11 @@
   virtual WebKit::WebLayerPositionConstraint positionConstraint() const;
   virtual void setScrollClient(WebKit::WebLayerScrollClient* client);
   virtual bool isOrphan() const;
+  virtual void setWebLayerClient(WebKit::WebLayerClient* client);
 
  protected:
   scoped_refptr<cc::Layer> layer_;
+  WebKit::WebLayerClient* web_layer_client_;
 
  private:
   scoped_ptr<WebToCCAnimationDelegateAdapter> animation_delegate_adapter_;
diff --git a/webkit/storage_browser.gyp b/webkit/storage_browser.gyp
index b44d2c5..04e609a 100644
--- a/webkit/storage_browser.gyp
+++ b/webkit/storage_browser.gyp
@@ -90,27 +90,6 @@
         'browser/database/databases_table.h',
         'browser/database/vfs_backend.cc',
         'browser/database/vfs_backend.h',
-        'browser/dom_storage/dom_storage_area.cc',
-        'browser/dom_storage/dom_storage_area.h',
-        'browser/dom_storage/dom_storage_context.cc',
-        'browser/dom_storage/dom_storage_context.h',
-        'browser/dom_storage/dom_storage_database.cc',
-        'browser/dom_storage/dom_storage_database.h',
-        'browser/dom_storage/dom_storage_database_adapter.h',
-        'browser/dom_storage/dom_storage_host.cc',
-        'browser/dom_storage/dom_storage_host.h',
-        'browser/dom_storage/dom_storage_namespace.cc',
-        'browser/dom_storage/dom_storage_namespace.h',
-        'browser/dom_storage/dom_storage_session.cc',
-        'browser/dom_storage/dom_storage_session.h',
-        'browser/dom_storage/dom_storage_task_runner.cc',
-        'browser/dom_storage/dom_storage_task_runner.h',
-        'browser/dom_storage/local_storage_database_adapter.cc',
-        'browser/dom_storage/local_storage_database_adapter.h',
-        'browser/dom_storage/session_storage_database.cc',
-        'browser/dom_storage/session_storage_database.h',
-        'browser/dom_storage/session_storage_database_adapter.cc',
-        'browser/dom_storage/session_storage_database_adapter.h',
         'browser/fileapi/async_file_util.h',
         'browser/fileapi/async_file_util_adapter.cc',
         'browser/fileapi/async_file_util_adapter.h',
diff --git a/webkit/storage_common.gyp b/webkit/storage_common.gyp
index c406b22..01e8f23 100644
--- a/webkit/storage_common.gyp
+++ b/webkit/storage_common.gyp
@@ -30,10 +30,6 @@
         'common/database/database_connections.h',
         'common/database/database_identifier.cc',
         'common/database/database_identifier.cc',
-        'common/dom_storage/dom_storage_map.cc',
-        'common/dom_storage/dom_storage_map.h',
-        'common/dom_storage/dom_storage_types.cc',
-        'common/dom_storage/dom_storage_types.h',
         'common/fileapi/directory_entry.cc',
         'common/fileapi/directory_entry.h',
         'common/fileapi/file_system_types.h',
diff --git a/webkit/webkit_storage_browser.target.darwin-arm.mk b/webkit/webkit_storage_browser.target.darwin-arm.mk
index b1ca9ad..349d8bc 100644
--- a/webkit/webkit_storage_browser.target.darwin-arm.mk
+++ b/webkit/webkit_storage_browser.target.darwin-arm.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_browser.target.darwin-mips.mk b/webkit/webkit_storage_browser.target.darwin-mips.mk
index d4db6e3..223f22b 100644
--- a/webkit/webkit_storage_browser.target.darwin-mips.mk
+++ b/webkit/webkit_storage_browser.target.darwin-mips.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_browser.target.darwin-x86.mk b/webkit/webkit_storage_browser.target.darwin-x86.mk
index a381d65..9c2fe20 100644
--- a/webkit/webkit_storage_browser.target.darwin-x86.mk
+++ b/webkit/webkit_storage_browser.target.darwin-x86.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-arm.mk b/webkit/webkit_storage_browser.target.linux-arm.mk
index b1ca9ad..349d8bc 100644
--- a/webkit/webkit_storage_browser.target.linux-arm.mk
+++ b/webkit/webkit_storage_browser.target.linux-arm.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-mips.mk b/webkit/webkit_storage_browser.target.linux-mips.mk
index d4db6e3..223f22b 100644
--- a/webkit/webkit_storage_browser.target.linux-mips.mk
+++ b/webkit/webkit_storage_browser.target.linux-mips.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_browser.target.linux-x86.mk b/webkit/webkit_storage_browser.target.linux-x86.mk
index a381d65..9c2fe20 100644
--- a/webkit/webkit_storage_browser.target.linux-x86.mk
+++ b/webkit/webkit_storage_browser.target.linux-x86.mk
@@ -57,16 +57,6 @@
 	webkit/browser/database/database_util.cc \
 	webkit/browser/database/databases_table.cc \
 	webkit/browser/database/vfs_backend.cc \
-	webkit/browser/dom_storage/dom_storage_area.cc \
-	webkit/browser/dom_storage/dom_storage_context.cc \
-	webkit/browser/dom_storage/dom_storage_database.cc \
-	webkit/browser/dom_storage/dom_storage_host.cc \
-	webkit/browser/dom_storage/dom_storage_namespace.cc \
-	webkit/browser/dom_storage/dom_storage_session.cc \
-	webkit/browser/dom_storage/dom_storage_task_runner.cc \
-	webkit/browser/dom_storage/local_storage_database_adapter.cc \
-	webkit/browser/dom_storage/session_storage_database.cc \
-	webkit/browser/dom_storage/session_storage_database_adapter.cc \
 	webkit/browser/fileapi/async_file_util_adapter.cc \
 	webkit/browser/fileapi/copy_or_move_operation_delegate.cc \
 	webkit/browser/fileapi/external_mount_points.cc \
diff --git a/webkit/webkit_storage_common.target.darwin-arm.mk b/webkit/webkit_storage_common.target.darwin-arm.mk
index 7316d19..868f85b 100644
--- a/webkit/webkit_storage_common.target.darwin-arm.mk
+++ b/webkit/webkit_storage_common.target.darwin-arm.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc
diff --git a/webkit/webkit_storage_common.target.darwin-mips.mk b/webkit/webkit_storage_common.target.darwin-mips.mk
index b93512f..dc12229 100644
--- a/webkit/webkit_storage_common.target.darwin-mips.mk
+++ b/webkit/webkit_storage_common.target.darwin-mips.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc
diff --git a/webkit/webkit_storage_common.target.darwin-x86.mk b/webkit/webkit_storage_common.target.darwin-x86.mk
index 3c53b09..3f34579 100644
--- a/webkit/webkit_storage_common.target.darwin-x86.mk
+++ b/webkit/webkit_storage_common.target.darwin-x86.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc
diff --git a/webkit/webkit_storage_common.target.linux-arm.mk b/webkit/webkit_storage_common.target.linux-arm.mk
index 7316d19..868f85b 100644
--- a/webkit/webkit_storage_common.target.linux-arm.mk
+++ b/webkit/webkit_storage_common.target.linux-arm.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc
diff --git a/webkit/webkit_storage_common.target.linux-mips.mk b/webkit/webkit_storage_common.target.linux-mips.mk
index b93512f..dc12229 100644
--- a/webkit/webkit_storage_common.target.linux-mips.mk
+++ b/webkit/webkit_storage_common.target.linux-mips.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc
diff --git a/webkit/webkit_storage_common.target.linux-x86.mk b/webkit/webkit_storage_common.target.linux-x86.mk
index 3c53b09..3f34579 100644
--- a/webkit/webkit_storage_common.target.linux-x86.mk
+++ b/webkit/webkit_storage_common.target.linux-x86.mk
@@ -29,8 +29,6 @@
 	webkit/common/blob/shareable_file_reference.cc \
 	webkit/common/database/database_connections.cc \
 	webkit/common/database/database_identifier.cc \
-	webkit/common/dom_storage/dom_storage_map.cc \
-	webkit/common/dom_storage/dom_storage_types.cc \
 	webkit/common/fileapi/directory_entry.cc \
 	webkit/common/fileapi/file_system_util.cc \
 	webkit/common/quota/quota_status_code.cc